Skip to content

Commit 7f499e1

Browse files
author
Franciszek Wawrzak
committed
added scope as constructor parameter and properties for plugins cache
1 parent 53709eb commit 7f499e1

File tree

13 files changed

+261
-114
lines changed

13 files changed

+261
-114
lines changed

lib/internal/Magento/Framework/CompiledInterception/Generator/CompiledInterceptor.php

Lines changed: 98 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use Magento\Framework\App\ObjectManager;
1010
use Magento\Framework\Code\Generator\EntityAbstract;
11+
use Magento\Framework\Config\Scope;
1112
use Magento\Framework\Interception\Code\Generator\Interceptor;
1213
use Magento\Framework\Interception\DefinitionInterface;
1314

@@ -16,6 +17,9 @@ class CompiledInterceptor extends Interceptor
1617

1718
protected $plugins;
1819

20+
protected $classMethods = [];
21+
protected $classProperties = [];
22+
1923
public function __construct(
2024
$sourceClassName = null,
2125
$resultClassName = null,
@@ -41,14 +45,12 @@ public function __construct(
4145
}
4246
}
4347

48+
/**
49+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
50+
*/
4451
public function setInterceptedMethods($interceptedMethods)
4552
{
46-
//DUMMY
47-
}
48-
49-
protected function _getClassProperties()
50-
{
51-
return [];
53+
//NOOP
5254
}
5355

5456
protected function _generateCode()
@@ -57,41 +59,98 @@ protected function _generateCode()
5759
$reflection = new \ReflectionClass($typeName);
5860

5961
if ($reflection->isInterface()) {
60-
$this->_classGenerator->setImplementedInterfaces([$typeName]);
62+
return false;
6163
} else {
6264
$this->_classGenerator->setExtendedClass($typeName);
6365
}
6466

6567
$this->_classGenerator->addUse(ObjectManager::class);
66-
$this->_classGenerator->addUse(\Magento\Framework\Config\Scope::class);
68+
$this->_classGenerator->addUse(Scope::class);
69+
70+
$this->classMethods = [];
71+
$this->classProperties = [];
72+
$this->overrideMethodsAndGeneratePluginGetters($reflection);
73+
74+
array_unshift($this->classMethods, $this->_getConstructorInfo($reflection->getConstructor()));
75+
array_unshift($this->classProperties, [
76+
'name' => '____scope',
77+
'visibility' => 'private',
78+
'docblock' => [
79+
'tags' => [['name' => 'var', 'description' => 'Scope']],
80+
]
81+
]);
6782
//return parent::_generateCode();
6883
return EntityAbstract::_generateCode();
6984
}
7085

71-
protected function _getClassMethods()
86+
protected function overrideMethodsAndGeneratePluginGetters(\ReflectionClass $reflection)
7287
{
73-
$reflectionClass = new \ReflectionClass($this->getSourceClassName());
74-
$publicMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
88+
$publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
7589

76-
$methods = [];
7790
$allPlugins = [];
7891
foreach ($publicMethods as $method) {
7992
if ($this->isInterceptedMethod($method)) {
8093
$config = $this->_getPluginsConfig($method, $allPlugins);
8194
if (!empty($config)) {
82-
$methods[] = $this->_getCompiledMethodInfo($method, $config);
95+
$this->classMethods[] = $this->_getCompiledMethodInfo($method, $config);
8396
}
8497
}
8598
}
86-
if (!empty($methods) && !empty($allPlugins)) {
87-
foreach ($allPlugins as $key => $plugins) {
88-
foreach ($plugins as $plugin) {
89-
$methods[] = $this->_getPluginGetterInfo($plugin);
99+
foreach ($allPlugins as $plugins) {
100+
foreach ($plugins as $plugin) {
101+
$this->classMethods[] = $this->_getPluginGetterInfo($plugin);
102+
$this->classProperties[] = $this->_getPluginPropertyInfo($plugin);
103+
}
104+
}
105+
}
106+
107+
protected function _getClassMethods()
108+
{
109+
return $this->classMethods;
110+
}
111+
112+
protected function _getClassProperties()
113+
{
114+
return $this->classProperties;
115+
}
116+
117+
protected function _getConstructorInfo(\ReflectionMethod $parentConstructor = null)
118+
{
119+
if ($parentConstructor == null) {
120+
$parameters = [[
121+
'name' => 'scope',
122+
'type' => Scope::class
123+
]];
124+
$body = ["\$this->____scope = \$scope;"];
125+
} else {
126+
$parameters = $parentConstructor->getParameters();
127+
$addScopeParam = true;
128+
$scopeParamName = '____scope';
129+
foreach ($parameters as $parameter) {
130+
$parentCallParams[] = '$' . $parameter->getName();
131+
if ($parameter->getType() == Scope::class) {
132+
$scopeParamName = $parameter->getName();
133+
$addScopeParam = false;
90134
}
91135
}
136+
137+
$parameters = array_map(array($this, '_getMethodParameterInfo'), $parameters);
138+
$addScopeParam && array_unshift($parameters, [
139+
'name' => $scopeParamName,
140+
'type' => Scope::class
141+
]);
142+
$body = [
143+
"\$this->____scope = \$$scopeParamName;",
144+
"parent::__construct(" . implode(', ', $parentCallParams) .");"
145+
];
92146
}
93147

94-
return $methods;
148+
return [
149+
'name' => '__construct',
150+
'parameters' => $parameters,
151+
'body' => implode("\n", $body),
152+
'docblock' => ['shortDescription' => '{@inheritdoc}'],
153+
];
95154
}
96155

97156
private function addCodeSubBlock(&$body, $sub, $indent = 1)
@@ -117,8 +176,6 @@ protected function _getMethodSourceFromConfig(\ReflectionMethod $method, $conf,
117176
if (isset($conf[DefinitionInterface::LISTENER_BEFORE])) {
118177
foreach ($conf[DefinitionInterface::LISTENER_BEFORE] as $plugin) {
119178
if ($first) $first = false; else $body[] = "";
120-
//$body[] = "/** @var \\" . "{$plugin['class']} \$plugin {$plugin['code']} */";
121-
//$body[] = "\$plugin = \$this->" . $this->getGetterName($plugin) . "();";
122179

123180
$call = "\$this->" . $this->getGetterName($plugin) . "()->before$capName(\$this$extraParams);";
124181

@@ -136,11 +193,8 @@ protected function _getMethodSourceFromConfig(\ReflectionMethod $method, $conf,
136193
$main = [];
137194
if (isset($conf[DefinitionInterface::LISTENER_AROUND])) {
138195
$plugin = $conf[DefinitionInterface::LISTENER_AROUND];
139-
//$body[] = "/** @var \\" . "{$plugin['class']} \$plugin {$plugin['code']} */";
140-
//$body[] = "\$plugin = \$this->" . $this->getGetterName($plugin) . "();";
141196
$main[] = "\$this->" . $this->getGetterName($plugin) . "()->around$capName(\$this, function({$this->_getParameterListForNextCallback($parameters)}){";
142197
$this->addCodeSubBlock($main, $this->_getMethodSourceFromConfig($method, $plugin['next'] ?: [], $parameters, $returnVoid));
143-
//$body[] = "\treturn \$result;";
144198
$main[] = "}$extraParams);";
145199
} else {
146200
$main[] = "parent::{$method->getName()}({$this->_getParameterList($parameters)});";
@@ -149,8 +203,6 @@ protected function _getMethodSourceFromConfig(\ReflectionMethod $method, $conf,
149203

150204
if (isset($conf[DefinitionInterface::LISTENER_AFTER])) {
151205
foreach ($conf[DefinitionInterface::LISTENER_AFTER] as $plugin) {
152-
//$body[] = "/** @var \\" . "{$plugin['class']} \$plugin {$plugin['code']} */";
153-
//$body[] = "\$plugin = \$this->" . $this->getGetterName($plugin) . "();";
154206
if ($returnVoid) {
155207
$chain[] = ["((\$tmp = \$this->" . $this->getGetterName($plugin) . "()->after$capName(\$this, \$result$extraParams)) !== null) ? \$tmp : \$result;"];
156208
} else {
@@ -206,16 +258,29 @@ protected function _getParameterList(array $parameters)
206258

207259
protected function getGetterName($plugin)
208260
{
209-
return '_get_plugin_' . preg_replace("/[^A-Za-z0-9_]/", '_', $plugin['code'] . $plugin['suffix']);
261+
return '____plugin_' . $plugin['clean_name'];
262+
}
263+
264+
protected function _getPluginPropertyInfo($plugin)
265+
{
266+
return [
267+
'name' => '____plugin_' . $plugin['clean_name'],
268+
'visibility' => 'private',
269+
'docblock' => [
270+
'tags' => [['name' => 'var', 'description' => '\\' . $plugin['class']]],
271+
]
272+
];
210273
}
211274

212275
protected function _getPluginGetterInfo($plugin)
213276
{
214277
$body = [];
278+
$varName = "\$this->____plugin_" . $plugin['clean_name'];
215279

216-
$body[] = "static \$cache = null;";
217-
$body[] = "if (\$cache === null) \$cache = ObjectManager::getInstance()->get(\\" . "{$plugin['class']}::class);";
218-
$body[] = "return \$cache;";
280+
$body[] = "if ($varName === null) {";
281+
$body[] = "\t$varName = ObjectManager::getInstance()->get(\\" . "{$plugin['class']}::class);";
282+
$body[] = "}";
283+
$body[] = "return $varName;";
219284

220285
return [
221286
'name' => $this->getGetterName($plugin),
@@ -234,7 +299,7 @@ protected function _getCompiledMethodInfo(\ReflectionMethod $method, $config)
234299
$returnsVoid = ($method->hasReturnType() && $method->getReturnType()->getName() == 'void');
235300

236301
$body = [
237-
'switch(ObjectManager::getInstance()->get(Scope::class)->getCurrentScope()){'
302+
'switch($this->____scope->getCurrentScope()){'
238303
];
239304

240305
$cases = [];
@@ -247,7 +312,7 @@ protected function _getCompiledMethodInfo(\ReflectionMethod $method, $config)
247312
//call parent method for scopes with no plugins (or when no scope is set)
248313
$cases[] = ['cases'=>["\tdefault:"], 'conf'=>[]];
249314

250-
foreach($cases as $case) {
315+
foreach ($cases as $case) {
251316
$body = array_merge($body, $case['cases']);
252317
$this->addCodeSubBlock($body, $this->_getMethodSourceFromConfig($method, $case['conf'], $parameters, $returnsVoid), 2);
253318
//$body[] = "\t\tbreak;";
@@ -269,10 +334,11 @@ protected function _getPluginInfo(CompiledPluginList $plugins, $code, $className
269334
$className = $plugins->getPluginType($className, $code);
270335
if (!isset($allPlugins[$code])) $allPlugins[$code] = [];
271336
if (empty($allPlugins[$code][$className])) {
337+
$suffix = count($allPlugins[$code]) ? count($allPlugins[$code]) + 1 : '';
272338
$allPlugins[$code][$className] = [
273339
'code' => $code,
274340
'class' => $className,
275-
'suffix' => count($allPlugins[$code]) ? count($allPlugins[$code]) + 1 : ''
341+
'clean_name' => preg_replace("/[^A-Za-z0-9_]/", '_', $code . $suffix)
276342
];
277343
}
278344
$ret = $allPlugins[$code][$className];

lib/internal/Magento/Framework/CompiledInterception/README.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,7 @@ Interceptors generated by this plugin are 100% compatible with ones generated by
1313

1414
### ENABLING
1515

16-
to use in developer mode in `app/etc/di.xml` replace:
17-
```
18-
<item name="interceptor" xsi:type="string">\Magento\Framework\Interception\Code\Generator\Interceptor</item>
19-
```
20-
with:
21-
```
22-
<item name="interceptor" xsi:type="string">\Magento\Framework\CompiledInterception\Generator\CompiledInterceptor</item>
23-
```
24-
25-
to use compiled interceptors in production mode please add following preference to your di.xml
16+
to use compiled interceptors in developer and production mode please add following preference to your di.xml
2617
```
2718
<preference for="Magento\Framework\Interception\Code\Generator\Interceptor" type="Magento\Framework\CompiledInterception\Generator\CompiledInterceptor" />
2819
```
@@ -33,7 +24,7 @@ clear generated files and cache:
3324

3425
### DISABLING
3526

36-
Replace back the lines in `app/etc/di.xml`, remove module and clear cache and generated files.
27+
Replace remove preference from `app/etc/di.xml`, remove module and clear cache and generated files.
3728

3829
### TECHNICAL DETAILS
3930

@@ -80,7 +71,7 @@ public function methodX($arg) {
8071

8172
* fastest response time (5%-15% faster in developer and production mode)
8273
* no redundant calls to `___callPlugins` in call stack.
83-
* methods with no plugins are not overriden in parent at all.
74+
* methods with no plugins are not overridden in parent at all.
8475

8576
* implemented as a module and can be easily reverted to default `Generator\Interceptor`
8677

lib/internal/Magento/Framework/CompiledInterception/Test/Unit/CompiledInterceptor/CompiledInterceptorTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ public function testGenerate($className, $resultClassName, $fileName)
6060
$interceptor->method('_validateData')->willReturn(true);
6161

6262
$generated = $interceptor->generate();
63-
6463
$this->assertEquals($fileName . '.php', $generated, 'Generated interceptor is invalid.');
6564
}
6665

0 commit comments

Comments
 (0)