Skip to content

Commit e038df3

Browse files
committed
Merge remote-tracking branch 'origin/MC-37558' into 2.4-develop-sidecar-pr4
2 parents f1b5f19 + 2c1cf25 commit e038df3

File tree

11 files changed

+710
-96
lines changed

11 files changed

+710
-96
lines changed

app/code/Magento/Csp/Model/BlockCache.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function save($data, $identifier, $tags = [], $lifeTime = null)
111111
];
112112
}
113113
}
114-
$data = $this->serializer->serialize(['policies' => $policiesData, 'html' => $data]);
114+
$data = $this->serializer->serialize(['policies' => $policiesData, 'html' => (string)$data]);
115115
}
116116

117117
return $this->cache->save($data, $identifier, $tags, $lifeTime);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Csp\Model\Collector;
9+
10+
use Magento\Csp\Api\Data\PolicyInterface;
11+
12+
/**
13+
* Merges policies using different mergers.
14+
*/
15+
class CompositeMerger implements MergerInterface
16+
{
17+
/**
18+
* @var MergerInterface[]
19+
*/
20+
private $mergers;
21+
22+
/**
23+
* @param MergerInterface[] $mergers
24+
*/
25+
public function __construct(array $mergers)
26+
{
27+
$this->mergers = $mergers;
28+
}
29+
30+
/**
31+
* @inheritDoc
32+
*/
33+
public function merge(PolicyInterface $policy1, PolicyInterface $policy2): PolicyInterface
34+
{
35+
foreach ($this->mergers as $merger) {
36+
if ($merger->canMerge($policy1, $policy2)) {
37+
return $merger->merge($policy1, $policy2);
38+
}
39+
}
40+
41+
throw new \RuntimeException('Cannot merge 2 policies of ' .get_class($policy1));
42+
}
43+
44+
/**
45+
* @inheritDoc
46+
*/
47+
public function canMerge(PolicyInterface $policy1, PolicyInterface $policy2): bool
48+
{
49+
foreach ($this->mergers as $merger) {
50+
if ($merger->canMerge($policy1, $policy2)) {
51+
return true;
52+
}
53+
}
54+
55+
return false;
56+
}
57+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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\Csp\Model\Collector\CspWhitelistXml;
10+
11+
use Magento\Framework\Config\FileResolverInterface;
12+
use Magento\Framework\Filesystem;
13+
use Magento\Framework\View\Design\ThemeInterface;
14+
use Magento\Framework\View\DesignInterface;
15+
use Magento\Framework\View\Design\Theme\CustomizationInterface;
16+
use Magento\Framework\View\Design\Theme\CustomizationInterfaceFactory;
17+
use Magento\Framework\App\Filesystem\DirectoryList;
18+
use Magento\Framework\Filesystem\Directory\ReadInterface as DirectoryRead;
19+
use Magento\Framework\Config\CompositeFileIteratorFactory;
20+
21+
/**
22+
* Combines configuration files from both modules and current theme.
23+
*/
24+
class FileResolver implements FileResolverInterface
25+
{
26+
/**
27+
* @var FileResolverInterface
28+
*/
29+
private $moduleFileResolver;
30+
31+
/**
32+
* @var ThemeInterface
33+
*/
34+
private $theme;
35+
36+
/**
37+
* @var CustomizationInterfaceFactory
38+
*/
39+
private $themeInfoFactory;
40+
41+
/**
42+
* @var DirectoryRead
43+
*/
44+
private $rootDir;
45+
46+
/**
47+
* @var CompositeFileIteratorFactory
48+
*/
49+
private $iteratorFactory;
50+
51+
/**
52+
* @param FileResolverInterface $moduleFileResolver
53+
* @param DesignInterface $design
54+
* @param CustomizationInterfaceFactory $customizationFactory
55+
* @param Filesystem $filesystem
56+
* @param CompositeFileIteratorFactory $iteratorFactory
57+
*/
58+
public function __construct(
59+
FileResolverInterface $moduleFileResolver,
60+
DesignInterface $design,
61+
CustomizationInterfaceFactory $customizationFactory,
62+
Filesystem $filesystem,
63+
CompositeFileIteratorFactory $iteratorFactory
64+
) {
65+
$this->moduleFileResolver = $moduleFileResolver;
66+
$this->theme = $design->getDesignTheme();
67+
$this->themeInfoFactory = $customizationFactory;
68+
$this->rootDir = $filesystem->getDirectoryRead(DirectoryList::ROOT);
69+
$this->iteratorFactory = $iteratorFactory;
70+
}
71+
72+
/**
73+
* @inheritDoc
74+
*/
75+
public function get($filename, $scope)
76+
{
77+
$configs = $this->moduleFileResolver->get($filename, $scope);
78+
if ($scope === 'global') {
79+
$files = [];
80+
$theme = $this->theme;
81+
while ($theme) {
82+
/** @var CustomizationInterface $info */
83+
$info = $this->themeInfoFactory->create(['theme' => $theme]);
84+
$file = $info->getThemeFilesPath() .'/etc/' .$filename;
85+
if ($this->rootDir->isExist($file)) {
86+
$files[] = $file;
87+
}
88+
$theme = $theme->getParentTheme();
89+
}
90+
$configs = $this->iteratorFactory->create(
91+
['paths' => array_reverse($files), 'existingIterator' => $configs]
92+
);
93+
}
94+
95+
return $configs;
96+
}
97+
}

app/code/Magento/Csp/Model/Collector/DynamicCollector.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,19 @@ class DynamicCollector implements PolicyCollectorInterface
2020
*/
2121
private $added = [];
2222

23+
/**
24+
* @var MergerInterface
25+
*/
26+
private $merger;
27+
28+
/**
29+
* @param MergerInterface $merger
30+
*/
31+
public function __construct(MergerInterface $merger)
32+
{
33+
$this->merger = $merger;
34+
}
35+
2336
/**
2437
* Add a policy for current page.
2538
*
@@ -28,14 +41,22 @@ class DynamicCollector implements PolicyCollectorInterface
2841
*/
2942
public function add(PolicyInterface $policy): void
3043
{
31-
$this->added[] = $policy;
44+
if (array_key_exists($policy->getId(), $this->added)) {
45+
if ($this->merger->canMerge($this->added[$policy->getId()], $policy)) {
46+
$this->added[$policy->getId()] = $this->merger->merge($this->added[$policy->getId()], $policy);
47+
} else {
48+
throw new \RuntimeException('Cannot merge a policy of ' .get_class($policy));
49+
}
50+
} else {
51+
$this->added[$policy->getId()] = $policy;
52+
}
3253
}
3354

3455
/**
3556
* @inheritDoc
3657
*/
3758
public function collect(array $defaultPolicies = []): array
3859
{
39-
return array_merge($defaultPolicies, $this->added);
60+
return array_merge($defaultPolicies, array_values($this->added));
4061
}
4162
}

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@
1515
</arguments>
1616
</type>
1717
<preference for="Magento\Csp\Api\PolicyCollectorInterface" type="Magento\Csp\Model\CompositePolicyCollector" />
18+
<preference for="Magento\Csp\Model\Collector\MergerInterface" type="Magento\Csp\Model\Collector\CompositeMerger" />
19+
<type name="Magento\Csp\Model\Collector\CompositeMerger">
20+
<arguments>
21+
<argument name="mergers" xsi:type="array">
22+
<item name="fetch" xsi:type="object">Magento\Csp\Model\Collector\FetchPolicyMerger</item>
23+
<item name="flag" xsi:type="object">Magento\Csp\Model\Collector\FlagPolicyMerger</item>
24+
<item name="plugins" xsi:type="object">Magento\Csp\Model\Collector\PluginTypesPolicyMerger</item>
25+
<item name="sandbox" xsi:type="object">Magento\Csp\Model\Collector\SandboxPolicyMerger</item>
26+
</argument>
27+
</arguments>
28+
</type>
1829
<type name="Magento\Csp\Model\CompositePolicyCollector">
1930
<arguments>
2031
<argument name="collectors" xsi:type="array">
@@ -24,10 +35,7 @@
2435
<item name="dynamic" xsi:type="object" sortOrder="3">Magento\Csp\Model\Collector\DynamicCollector\Proxy</item>
2536
</argument>
2637
<argument name="mergers" xsi:type="array">
27-
<item name="fetch" xsi:type="object">Magento\Csp\Model\Collector\FetchPolicyMerger</item>
28-
<item name="flag" xsi:type="object">Magento\Csp\Model\Collector\FlagPolicyMerger</item>
29-
<item name="plugins" xsi:type="object">Magento\Csp\Model\Collector\PluginTypesPolicyMerger</item>
30-
<item name="sandbox" xsi:type="object">Magento\Csp\Model\Collector\SandboxPolicyMerger</item>
38+
<item name="composite" xsi:type="object">Magento\Csp\Model\Collector\MergerInterface</item>
3139
</argument>
3240
</arguments>
3341
</type>
@@ -46,6 +54,7 @@
4654
<arguments>
4755
<argument name="converter" xsi:type="object">Magento\Csp\Model\Collector\CspWhitelistXml\Converter</argument>
4856
<argument name="schemaLocator" xsi:type="object">Magento\Csp\Model\Collector\CspWhitelistXml\SchemaLocator</argument>
57+
<argument name="fileResolver" xsi:type="object">Magento\Csp\Model\Collector\CspWhitelistXml\FileResolver</argument>
4958
<argument name="fileName" xsi:type="string">csp_whitelist.xml</argument>
5059
</arguments>
5160
</type>
@@ -93,6 +102,7 @@
93102
<type name="Magento\Csp\Model\BlockCache">
94103
<arguments>
95104
<argument name="cache" xsi:type="object">configured_block_cache</argument>
105+
<argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument>
96106
</arguments>
97107
</type>
98108
<type name="Magento\Framework\View\Element\Context">
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Controller\Adminhtml\Category\Save;
9+
10+
use Magento\Catalog\Api\CategoryRepositoryInterface;
11+
use Magento\Catalog\Api\Data\CategoryInterface;
12+
use Magento\Catalog\Model\Category;
13+
use Magento\Store\Model\StoreManagerInterface;
14+
15+
/**
16+
* Test related to update category.
17+
*
18+
* @magentoAppArea adminhtml
19+
* @magentoDbIsolation enabled
20+
*/
21+
class UpdateCategoryTest extends AbstractSaveCategoryTest
22+
{
23+
/** @var CategoryRepositoryInterface */
24+
private $categoryRepository;
25+
26+
/** @var StoreManagerInterface */
27+
private $storeManager;
28+
29+
/**
30+
* @inheritdoc
31+
*/
32+
protected function setUp(): void
33+
{
34+
parent::setUp();
35+
36+
$this->categoryRepository = $this->_objectManager->get(CategoryRepositoryInterface::class);
37+
$this->storeManager = $this->_objectManager->get(StoreManagerInterface::class);
38+
}
39+
40+
/**
41+
* @dataProvider categoryDataProvider
42+
* @magentoDataFixture Magento/Store/_files/second_store.php
43+
* @magentoDataFixture Magento/Catalog/_files/category.php
44+
*
45+
* @param array $postData
46+
* @return void
47+
*/
48+
public function testUpdateCategoryForDefaultStoreView(array $postData): void
49+
{
50+
$storeId = (int)$this->storeManager->getStore('default')->getId();
51+
$postData = array_merge($postData, ['store_id' => $storeId]);
52+
$responseData = $this->performSaveCategoryRequest($postData);
53+
$this->assertRequestIsSuccessfullyPerformed($responseData);
54+
$category = $this->categoryRepository->get($postData['entity_id'], $postData['store_id']);
55+
unset($postData['use_default']);
56+
unset($postData['use_config']);
57+
foreach ($postData as $key => $value) {
58+
$this->assertEquals($value, $category->getData($key));
59+
}
60+
}
61+
62+
/**
63+
* @return array
64+
*/
65+
public function categoryDataProvider(): array
66+
{
67+
return [
68+
[
69+
'post_data' => [
70+
'entity_id' => 333,
71+
CategoryInterface::KEY_IS_ACTIVE => '0',
72+
CategoryInterface::KEY_INCLUDE_IN_MENU => '0',
73+
CategoryInterface::KEY_NAME => 'Category default store',
74+
'description' => 'Description for default store',
75+
'landing_page' => '',
76+
'display_mode' => Category::DM_MIXED,
77+
CategoryInterface::KEY_AVAILABLE_SORT_BY => ['name', 'price'],
78+
'default_sort_by' => 'price',
79+
'filter_price_range' => 5,
80+
'url_key' => 'default-store-category',
81+
'meta_title' => 'meta_title default store',
82+
'meta_keywords' => 'meta_keywords default store',
83+
'meta_description' => 'meta_description default store',
84+
'custom_use_parent_settings' => '0',
85+
'custom_design' => '2',
86+
'page_layout' => '2columns-right',
87+
'custom_apply_to_products' => '1',
88+
'use_default' => [
89+
CategoryInterface::KEY_NAME => '0',
90+
CategoryInterface::KEY_IS_ACTIVE => '0',
91+
CategoryInterface::KEY_INCLUDE_IN_MENU => '0',
92+
'url_key' => '0',
93+
'meta_title' => '0',
94+
'custom_use_parent_settings' => '0',
95+
'custom_apply_to_products' => '0',
96+
'description' => '0',
97+
'landing_page' => '0',
98+
'display_mode' => '0',
99+
'custom_design' => '0',
100+
'page_layout' => '0',
101+
'meta_keywords' => '0',
102+
'meta_description' => '0',
103+
'custom_layout_update' => '0',
104+
],
105+
'use_config' => [
106+
CategoryInterface::KEY_AVAILABLE_SORT_BY => false,
107+
'default_sort_by' => false,
108+
'filter_price_range' => false,
109+
],
110+
],
111+
],
112+
];
113+
}
114+
}

0 commit comments

Comments
 (0)