Skip to content

Commit dd350a7

Browse files
committed
MC-42276: New options in System configuration cause performance degradation in Catalog and CMS
1 parent bd27efb commit dd350a7

File tree

13 files changed

+528
-27
lines changed

13 files changed

+528
-27
lines changed

app/code/Magento/Cms/etc/adminhtml/di.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,9 @@
5757
<argument name="path" xsi:type="string">web/default_layouts/default_cms_layout</argument>
5858
</arguments>
5959
</virtualType>
60+
<type name="Magento\Cms\Model\Wysiwyg\Config">
61+
<arguments>
62+
<argument name="variableConfig" xsi:type="object">Magento\Variable\Model\Variable\Config\Proxy</argument>
63+
</arguments>
64+
</type>
6065
</config>
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Config\Model\Config;
10+
11+
use Magento\Framework\ObjectManager\NoninterceptableInterface;
12+
13+
/**
14+
* @inheritdoc
15+
*/
16+
class StructureLazy extends Structure implements NoninterceptableInterface
17+
{
18+
/**
19+
* @var Structure\Data
20+
*/
21+
private $structureData;
22+
23+
/**
24+
* @param \Magento\Config\Model\Config\Structure\Data $structureData
25+
* @param \Magento\Config\Model\Config\Structure\Element\Iterator\Tab $tabIterator
26+
* @param \Magento\Config\Model\Config\Structure\Element\FlyweightFactory $flyweightFactory
27+
* @param ScopeDefiner $scopeDefiner
28+
*/
29+
public function __construct(
30+
\Magento\Config\Model\Config\Structure\Data $structureData,
31+
\Magento\Config\Model\Config\Structure\Element\Iterator\Tab $tabIterator,
32+
\Magento\Config\Model\Config\Structure\Element\FlyweightFactory $flyweightFactory,
33+
ScopeDefiner $scopeDefiner
34+
) {
35+
$this->_tabIterator = $tabIterator;
36+
$this->_flyweightFactory = $flyweightFactory;
37+
$this->_scopeDefiner = $scopeDefiner;
38+
$this->structureData = $structureData;
39+
}
40+
41+
/**
42+
* @inheritdoc
43+
*/
44+
public function getElement($path)
45+
{
46+
$this->loadStructureData();
47+
return parent::getElement($path);
48+
}
49+
50+
/**
51+
* @inheritdoc
52+
*/
53+
public function getTabs()
54+
{
55+
$this->loadStructureData();
56+
return parent::getTabs();
57+
}
58+
59+
/**
60+
* @inheritdoc
61+
*/
62+
public function getSectionList()
63+
{
64+
$this->loadStructureData();
65+
return parent::getSectionList();
66+
}
67+
68+
/**
69+
* @inheritdoc
70+
*/
71+
public function getElementByConfigPath($path)
72+
{
73+
$this->loadStructureData();
74+
return parent::getElementByConfigPath($path);
75+
}
76+
77+
/**
78+
* @inheritdoc
79+
*/
80+
public function getFirstSection()
81+
{
82+
$this->loadStructureData();
83+
return parent::getTabs();
84+
}
85+
86+
/**
87+
* @inheritdoc
88+
*/
89+
public function getElementByPathParts(array $pathParts)
90+
{
91+
$this->loadStructureData();
92+
return parent:: getElementByPathParts($pathParts);
93+
}
94+
95+
/**
96+
* @inheritdoc
97+
*/
98+
public function getFieldPathsByAttribute($attributeName, $attributeValue)
99+
{
100+
$this->loadStructureData();
101+
return parent::getFieldPathsByAttribute($attributeName, $attributeValue);
102+
}
103+
104+
/**
105+
* @inheritdoc
106+
*/
107+
public function getFieldPaths()
108+
{
109+
$this->loadStructureData();
110+
return parent::getFieldPaths();
111+
}
112+
113+
/**
114+
* Load data
115+
*/
116+
private function loadStructureData()
117+
{
118+
if ($this->_data === null) {
119+
$this->_data = $this->structureData->get();
120+
}
121+
}
122+
}

app/code/Magento/Config/etc/di.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,4 +365,9 @@
365365
<argument name="structure" xsi:type="object">adminhtmlConfigStructure</argument>
366366
</arguments>
367367
</type>
368+
<type name="Magento\Config\Model\Config">
369+
<arguments>
370+
<argument name="configStructure" xsi:type="object">\Magento\Config\Model\Config\Structure\Proxy</argument>
371+
</arguments>
372+
</type>
368373
</config>

app/code/Magento/Email/Model/Template/Filter.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ class Filter extends Template
201201
*/
202202
private $pubDirectoryRead;
203203

204-
205204
/**
206205
* Filter constructor.
207206
* @param StringUtils $string
@@ -851,7 +850,7 @@ private function isAvailableConfigVariable($variable)
851850
{
852851
return in_array(
853852
$variable,
854-
array_column($this->configVariables->getData(), 'value')
853+
$this->configVariables->getAvailableVars()
855854
);
856855
}
857856

@@ -912,7 +911,7 @@ public function cssDirective($construction)
912911
return '/*' . PHP_EOL . $exception->getMessage() . PHP_EOL . '*/';
913912
}
914913

915-
if (empty($css)){
914+
if (empty($css)) {
916915
return '/* ' . __('Contents of the specified CSS file could not be loaded or is empty') . ' */';
917916
}
918917

app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,6 @@ class FilterTest extends TestCase
138138
*/
139139
private $variableResolver;
140140

141-
/**
142-
* @var MockObject|VariableResolverInterface
143-
*/
144-
private $variableResolverInterface;
145-
146141
/**
147142
* @var array
148143
*/
@@ -417,7 +412,7 @@ public function testApplyInlineCssThrowsExceptionWhenDesignParamsNotSet()
417412
public function testConfigDirectiveAvailable()
418413
{
419414
$path = "web/unsecure/base_url";
420-
$availableConfigs = [['value' => $path]];
415+
$availableConfigs = ['value' => $path];
421416
$construction = ["{{config path={$path}}}", 'config', " path={$path}"];
422417
$scopeConfigValue = 'value';
423418

@@ -429,7 +424,7 @@ public function testConfigDirectiveAvailable()
429424
$storeMock->expects($this->once())->method('getId')->willReturn(1);
430425

431426
$this->configVariables->expects($this->once())
432-
->method('getData')
427+
->method('getAvailableVars')
433428
->willReturn($availableConfigs);
434429
$this->scopeConfig->expects($this->once())
435430
->method('getValue')
@@ -452,7 +447,7 @@ public function testConfigDirectiveUnavailable()
452447
$storeMock->expects($this->once())->method('getId')->willReturn(1);
453448

454449
$this->configVariables->expects($this->once())
455-
->method('getData')
450+
->method('getAvailableVars')
456451
->willReturn($availableConfigs);
457452
$this->scopeConfig->expects($this->never())
458453
->method('getValue')

app/code/Magento/Paypal/etc/adminhtml/di.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
<argument name="storage" xsi:type="object">Magento\Paypal\Model\PayflowSession\Storage</argument>
2727
</arguments>
2828
</virtualType>
29+
<type name="Magento\Paypal\Model\Config\StructurePlugin">
30+
<arguments>
31+
<argument xsi:type="object" name="backendHelper">Magento\Paypal\Helper\Backend\Proxy</argument>
32+
</arguments>
33+
</type>
2934
<type name="Magento\Config\Model\Config\Structure">
3035
<plugin name="paypal_system_configuration" type="Magento\Paypal\Model\Config\StructurePlugin"/>
3136
</type>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Variable\Model\Config\Structure;
10+
11+
/**
12+
* Provide configuration for available variables
13+
*/
14+
class AvailableVariables
15+
{
16+
/**
17+
* @var string[]
18+
*/
19+
private $configPaths;
20+
21+
/**
22+
* @param string[] $configPaths
23+
*/
24+
public function __construct(
25+
$configPaths = []
26+
) {
27+
$this->configPaths = $configPaths;
28+
}
29+
30+
/**
31+
* Provide configured System configuration paths
32+
*
33+
* @return string[]
34+
*/
35+
public function getConfigPaths()
36+
{
37+
return $this->configPaths;
38+
}
39+
40+
/**
41+
* Provide configured System configuration sections
42+
*
43+
* @return string[]
44+
*/
45+
public function getFlatConfigPaths()
46+
{
47+
return array_merge(...array_values($this->configPaths));
48+
}
49+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Variable\Model\Config\Structure;
10+
11+
use Magento\Framework\App\ObjectManager;
12+
use Magento\Framework\Config\ValidationStateInterface;
13+
14+
/**
15+
* Filter dom structure to required components only
16+
*/
17+
class Dom extends \Magento\Framework\Config\Dom
18+
{
19+
/**
20+
* @var AvailableVariables
21+
*/
22+
private $structureConfig;
23+
24+
/**
25+
* @var array
26+
*/
27+
private $filters;
28+
29+
/**
30+
* @param string $xml
31+
* @param ValidationStateInterface $validationState
32+
* @param array $idAttributes
33+
* @param string $typeAttributeName
34+
* @param string $schemaFile
35+
* @param string $errorFormat
36+
* @param AvailableVariables|null $availableVariables
37+
*/
38+
public function __construct(
39+
$xml,
40+
ValidationStateInterface $validationState,
41+
array $idAttributes = [],
42+
$typeAttributeName = null,
43+
$schemaFile = null,
44+
$errorFormat = self::ERROR_FORMAT_DEFAULT,
45+
AvailableVariables $availableVariables = null
46+
) {
47+
$this->structureConfig = $availableVariables
48+
?: ObjectManager::getInstance()->get(AvailableVariables::class);
49+
parent::__construct($xml, $validationState, $idAttributes, $typeAttributeName, $schemaFile, $errorFormat);
50+
}
51+
52+
/**
53+
* @inheritdoc
54+
*/
55+
protected function _initDom($xml)
56+
{
57+
$dom = parent::_initDom($xml);
58+
foreach (['tab', 'section', 'group', 'field'] as $element) {
59+
$this->filterElements($dom, $element, $this->getElementFilters($element));
60+
}
61+
return $dom;
62+
}
63+
64+
/**
65+
* @inheritdoc
66+
*/
67+
public function merge($xml)
68+
{
69+
$dom = $this->_initDom($xml);
70+
if ($dom->documentElement->getElementsByTagName('section')->length >0) {
71+
$this->_mergeNode($dom->documentElement, '');
72+
}
73+
}
74+
75+
/**
76+
* Filter DOMDocument elements and keep only allowed
77+
*
78+
* @param \DOMDocument $dom
79+
* @param string $tag
80+
* @param array $ids
81+
*/
82+
private function filterElements($dom, $tag, $ids)
83+
{
84+
$removeElements = [];
85+
foreach ($dom->documentElement->getElementsByTagName($tag) as $removeElement) {
86+
if (!in_array($removeElement->getAttribute('id'), $ids)) {
87+
$removeElements[] = $removeElement;
88+
}
89+
}
90+
foreach ($removeElements as $removeElement) {
91+
$removeElement->parentNode->removeChild($removeElement);
92+
}
93+
}
94+
95+
/**
96+
* Get allowed identifiers by element tag
97+
*
98+
* @param string $tag
99+
* @return array|mixed
100+
*/
101+
private function getElementFilters($tag)
102+
{
103+
if (!isset($this->filters[$tag])) {
104+
$configPaths = $this->structureConfig->getFlatConfigPaths();
105+
$filterData = [];
106+
foreach (array_keys($configPaths) as $path) {
107+
list($section, $group, $field) = explode('/', $path);
108+
$filterData['section'][] = $section;
109+
$filterData['group'][] = $group;
110+
$filterData['field'][] = $field;
111+
}
112+
$filterData['tab'] = [];
113+
$this->filters = array_map('array_unique', $filterData);
114+
}
115+
116+
return $this->filters[$tag] ?? [];
117+
}
118+
}

0 commit comments

Comments
 (0)