Skip to content

Commit cbeae91

Browse files
committed
Merge branch 'ACP2E-2842' of https://github.com/adobe-commerce-tier-4/magento2ce into PR-03-12-2024-anna
2 parents ba93ede + d974332 commit cbeae91

File tree

4 files changed

+330
-0
lines changed

4 files changed

+330
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Theme\Observer;
20+
21+
use Magento\Framework\App\Config\ScopeConfigInterface;
22+
use Magento\Framework\Event\Observer;
23+
use Magento\Framework\Event\ObserverInterface;
24+
use Magento\Store\Model\ScopeInterface;
25+
use Magento\Store\Model\StoreManager;
26+
use Magento\Store\Model\StoreManagerInterface;
27+
use Magento\Theme\Api\DesignConfigRepositoryInterface;
28+
29+
class MoveStoreLevelDesignConfigToWebsiteScopeOnSingleStoreMode implements ObserverInterface
30+
{
31+
/**
32+
* @param ScopeConfigInterface $scopeConfig
33+
* @param DesignConfigRepositoryInterface $designConfigRepository
34+
* @param StoreManagerInterface $storeManager
35+
*/
36+
public function __construct(
37+
private readonly ScopeConfigInterface $scopeConfig,
38+
private readonly DesignConfigRepositoryInterface $designConfigRepository,
39+
private readonly StoreManagerInterface $storeManager
40+
) {
41+
}
42+
43+
/**
44+
* @inheritDoc
45+
*/
46+
public function execute(Observer $observer)
47+
{
48+
$changedPaths = (array)$observer->getEvent()->getChangedPaths();
49+
if (in_array(StoreManager::XML_PATH_SINGLE_STORE_MODE_ENABLED, $changedPaths, true)
50+
&& $this->scopeConfig->getValue(StoreManager::XML_PATH_SINGLE_STORE_MODE_ENABLED)
51+
) {
52+
$store = $this->storeManager->getDefaultStoreView();
53+
if ($store) {
54+
$websiteId = $store->getWebsiteId();
55+
$storeId = $store->getId();
56+
$designConfig = $this->designConfigRepository->getByScope(ScopeInterface::SCOPE_STORES, $storeId);
57+
// Copy design config from store scope to website scope
58+
$designConfig->setScope(ScopeInterface::SCOPE_WEBSITES);
59+
$designConfig->setScopeId($websiteId);
60+
$this->designConfigRepository->save($designConfig);
61+
// At this point store design config is the same as website design config.
62+
// let's delete store design config to preserve inheritance from website design config.
63+
$designConfig->setScope(ScopeInterface::SCOPE_STORES);
64+
$designConfig->setScopeId($storeId);
65+
$this->designConfigRepository->delete($designConfig);
66+
}
67+
}
68+
}
69+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Theme\Test\Fixture;
20+
21+
use Magento\Framework\DataObject;
22+
use Magento\Framework\DataObjectFactory;
23+
use Magento\Store\Model\ScopeInterface;
24+
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
25+
use Magento\Theme\Api\DesignConfigRepositoryInterface;
26+
27+
/**
28+
* Design Config fixture
29+
*
30+
* Example 1: Basic usage
31+
*
32+
* ```php
33+
* #[
34+
* DataFixture(
35+
* DesignConfigFixture::class,
36+
* [
37+
* 'scope_type' => ScopeInterface::SCOPE_WEBSITES,
38+
* 'scope_id' => 1,
39+
* 'data' => [
40+
* [
41+
* 'path' => 'design/footer/absolute_footer',
42+
* 'value' => 'test footer'
43+
* ]
44+
* ]
45+
* ]
46+
* )
47+
* ]
48+
* public function testConfig(): void
49+
* {
50+
*
51+
* }
52+
* ```
53+
*/
54+
class DesignConfig implements RevertibleDataFixtureInterface
55+
{
56+
private const DEFAULT_DATA = [
57+
'scope_type' => ScopeInterface::SCOPE_STORES,
58+
'scope_id' => 1,
59+
'data' => []
60+
];
61+
62+
/**
63+
* @param DesignConfigRepositoryInterface $designConfigRepository
64+
* @param DataObjectFactory $dataObjectFactory
65+
*/
66+
public function __construct(
67+
private readonly DesignConfigRepositoryInterface $designConfigRepository,
68+
private readonly DataObjectFactory $dataObjectFactory,
69+
) {
70+
}
71+
72+
/**
73+
* @inheritDoc
74+
*/
75+
public function apply(array $data = []): ?DataObject
76+
{
77+
$data = array_merge(self::DEFAULT_DATA, $data);
78+
$data['orig_data'] = $this->applyConfig(
79+
$data['scope_type'],
80+
$data['scope_id'],
81+
array_column($data['data'], 'value', 'path')
82+
);
83+
return $this->dataObjectFactory->create(['data' => $data]);
84+
}
85+
86+
/**
87+
* @inheritDoc
88+
*/
89+
public function revert(DataObject $data): void
90+
{
91+
$this->applyConfig(
92+
$data['scope_type'],
93+
$data['scope_id'],
94+
array_column($data['orig_data'], 'value', 'path')
95+
);
96+
}
97+
98+
/**
99+
* Save config
100+
*
101+
* @param string $scopeType
102+
* @param int $scopeId
103+
* @param array $data
104+
* @return array
105+
*/
106+
private function applyConfig(string $scopeType, int $scopeId, array $data): array
107+
{
108+
$designConfig = $this->designConfigRepository->getByScope($scopeType, $scopeId);
109+
$fieldsData = $designConfig->getExtensionAttributes()->getDesignConfigData();
110+
$origData = [];
111+
foreach ($fieldsData as $fieldData) {
112+
if (array_key_exists($fieldData->getPath(), $data)) {
113+
$origData[] = [
114+
'path' => $fieldData->getPath(),
115+
'value' => $fieldData->getValue()
116+
];
117+
$fieldData->setValue($data[$fieldData->getPath()]);
118+
}
119+
}
120+
$designConfig->setScope($scopeType);
121+
$designConfig->setScopeId($scopeId);
122+
$this->designConfigRepository->save($designConfig);
123+
return $origData;
124+
}
125+
}

app/code/Magento/Theme/etc/events.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@
1212
<event name="theme_save_after">
1313
<observer name="check_theme_is_assigned" instance="Magento\Theme\Observer\CheckThemeIsAssignedObserver" />
1414
</event>
15+
<event name="admin_system_config_changed_section_general">
16+
<observer name="move_store_level_design_config_to_website_scope_on_single_store_mode" instance="Magento\Theme\Observer\MoveStoreLevelDesignConfigToWebsiteScopeOnSingleStoreMode" />
17+
</event>
1518
</config>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Theme\Observer;
20+
21+
use Magento\Framework\App\Config\ReinitableConfigInterface;
22+
use Magento\Framework\Event\ManagerInterface;
23+
use Magento\Store\Model\ScopeInterface;
24+
use Magento\Store\Model\StoreManager;
25+
use Magento\TestFramework\Fixture\AppArea;
26+
use Magento\TestFramework\Fixture\Config;
27+
use Magento\TestFramework\Fixture\DataFixture;
28+
use Magento\TestFramework\Helper\Bootstrap;
29+
use Magento\TestFramework\Indexer\TestCase;
30+
use Magento\Theme\Api\DesignConfigRepositoryInterface;
31+
use Magento\Theme\Test\Fixture\DesignConfig as DesignConfigFixture;
32+
33+
class MoveStoreLevelDesignConfigToWebsiteScopeOnSingleStoreModeTest extends TestCase
34+
{
35+
private const XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER = 'design/footer/absolute_footer';
36+
private const INITIAL_FOOTER_TEXT_STORES = 'test footer text for store scope';
37+
private const INITIAL_FOOTER_TEXT_WEBSITES = 'test footer text for websites scope';
38+
private const UPDATED_FOOTER_TEXT_WEBSITES = 'updated footer text for websites scope';
39+
40+
#[
41+
DataFixture(
42+
DesignConfigFixture::class,
43+
[
44+
'scope_type' => ScopeInterface::SCOPE_WEBSITES,
45+
'scope_id' => 1,
46+
'data' => [
47+
[
48+
'path' => self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER,
49+
'value' => self::INITIAL_FOOTER_TEXT_WEBSITES
50+
]
51+
]
52+
]
53+
),
54+
DataFixture(
55+
DesignConfigFixture::class,
56+
[
57+
'scope_type' => ScopeInterface::SCOPE_STORES,
58+
'scope_id' => 1,
59+
'data' => [
60+
[
61+
'path' => self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER,
62+
'value' => self::INITIAL_FOOTER_TEXT_STORES
63+
]
64+
]
65+
]
66+
),
67+
Config(StoreManager::XML_PATH_SINGLE_STORE_MODE_ENABLED, 1),
68+
AppArea('adminhtml')
69+
]
70+
public function testExecute(): void
71+
{
72+
$eventManager = Bootstrap::getObjectManager()->get(ManagerInterface::class);
73+
$scopeConfig = Bootstrap::getObjectManager()->get(ReinitableConfigInterface::class);
74+
$this->assertEquals(
75+
self::INITIAL_FOOTER_TEXT_WEBSITES,
76+
$scopeConfig->getValue(self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER, ScopeInterface::SCOPE_WEBSITES)
77+
);
78+
$this->assertEquals(
79+
self::INITIAL_FOOTER_TEXT_STORES,
80+
$scopeConfig->getValue(self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER, ScopeInterface::SCOPE_STORES)
81+
);
82+
$eventManager->dispatch(
83+
'admin_system_config_changed_section_general',
84+
[
85+
'website' => '',
86+
'store' => '',
87+
'changed_paths' => [
88+
StoreManager::XML_PATH_SINGLE_STORE_MODE_ENABLED
89+
],
90+
]
91+
);
92+
$this->assertEquals(
93+
self::INITIAL_FOOTER_TEXT_STORES,
94+
$scopeConfig->getValue(self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER, ScopeInterface::SCOPE_WEBSITES)
95+
);
96+
$this->assertEquals(
97+
self::INITIAL_FOOTER_TEXT_STORES,
98+
$scopeConfig->getValue(self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER, ScopeInterface::SCOPE_STORES)
99+
);
100+
101+
$this->updateConfig(
102+
self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER,
103+
self::UPDATED_FOOTER_TEXT_WEBSITES,
104+
ScopeInterface::SCOPE_WEBSITES,
105+
1
106+
);
107+
108+
$this->assertEquals(
109+
self::UPDATED_FOOTER_TEXT_WEBSITES,
110+
$scopeConfig->getValue(self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER, ScopeInterface::SCOPE_WEBSITES)
111+
);
112+
$this->assertEquals(
113+
self::UPDATED_FOOTER_TEXT_WEBSITES,
114+
$scopeConfig->getValue(self::XML_PATH_DESIGN_FOOTER_ABSOLUTE_FOOTER, ScopeInterface::SCOPE_STORES)
115+
);
116+
}
117+
118+
private function updateConfig(string $path, string $value, string $scopeType, int $scopeId): void
119+
{
120+
$designConfigRepository = Bootstrap::getObjectManager()->get(DesignConfigRepositoryInterface::class);
121+
$designConfig = $designConfigRepository->getByScope($scopeType, $scopeId);
122+
$fieldsData = $designConfig->getExtensionAttributes()->getDesignConfigData();
123+
foreach ($fieldsData as $fieldData) {
124+
if ($fieldData->getPath() === $path) {
125+
$fieldData->setValue($value);
126+
}
127+
128+
}
129+
$designConfig->setScope($scopeType);
130+
$designConfig->setScopeId($scopeId);
131+
$designConfigRepository->save($designConfig);
132+
}
133+
}

0 commit comments

Comments
 (0)