Skip to content

Commit c91aae9

Browse files
committed
Merge branch 'ACP2E-3324' of https://github.com/adobe-commerce-tier-4/magento2ce into PR-31-10-2024
2 parents 6acfd6a + 6e26a5e commit c91aae9

File tree

10 files changed

+605
-45
lines changed

10 files changed

+605
-45
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Theme\Model\Config;
9+
10+
use Magento\Config\Model\Config\Structure;
11+
use Magento\Framework\Exception\ValidatorException;
12+
use Magento\Theme\Model\DesignConfigRepository;
13+
14+
class PathValidator extends \Magento\Config\Model\Config\PathValidator
15+
{
16+
/**
17+
* @param Structure $structure
18+
* @param DesignConfigRepository $designConfigRepository
19+
*/
20+
public function __construct(
21+
private readonly Structure $structure,
22+
private readonly DesignConfigRepository $designConfigRepository
23+
) {
24+
parent::__construct($structure);
25+
}
26+
27+
/**
28+
* @inheritdoc
29+
*/
30+
public function validate($path)
31+
{
32+
if (stripos($path, 'design/') !== 0) {
33+
return parent::validate($path);
34+
}
35+
36+
return $this->validateDesignPath($path);
37+
}
38+
39+
/**
40+
* Get design configuration field paths
41+
*
42+
* @return array
43+
*/
44+
private function getDesignFieldPaths(): array
45+
{
46+
$designConfig = $this->designConfigRepository->getByScope('default', null);
47+
$fieldsData = $designConfig->getExtensionAttributes()->getDesignConfigData();
48+
$data = [];
49+
foreach ($fieldsData as $fieldData) {
50+
$data[$fieldData->getFieldConfig()['path']] = [$fieldData->getFieldConfig()['path']];
51+
}
52+
return $data;
53+
}
54+
55+
/**
56+
* Validate design path configurations
57+
*
58+
* @param string $path
59+
* @return bool
60+
* @throws ValidatorException
61+
*/
62+
private function validateDesignPath(string $path): bool
63+
{
64+
$element = $this->structure->getElementByConfigPath($path);
65+
if ($element instanceof Structure\Element\Field && $element->getConfigPath()) {
66+
$path = $element->getConfigPath();
67+
}
68+
69+
$allPaths = array_merge($this->structure->getFieldPaths(), $this->getDesignFieldPaths());
70+
71+
if (!array_key_exists($path, $allPaths)) {
72+
throw new ValidatorException(__('The "%1" path doesn\'t exist. Verify and try again.', $path));
73+
}
74+
return true;
75+
}
76+
}

app/code/Magento/Theme/Model/Data/Design/ConfigFactory.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66

77
namespace Magento\Theme\Model\Data\Design;
88

9+
use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker;
10+
use Magento\Framework\App\ObjectManager;
911
use Magento\Framework\App\ScopeValidatorInterface;
1012
use Magento\Framework\Exception\LocalizedException;
1113
use Magento\Store\Model\StoreManagerInterface;
@@ -60,21 +62,24 @@ class ConfigFactory
6062
* @param DesignConfigExtensionFactory $configExtensionFactory
6163
* @param ScopeValidatorInterface $scopeValidator
6264
* @param StoreManagerInterface $storeManager
65+
* @param SettingChecker|null $settingChecker
6366
*/
6467
public function __construct(
6568
DesignConfigInterfaceFactory $designConfigFactory,
6669
MetadataProviderInterface $metadataProvider,
6770
DesignConfigDataInterfaceFactory $designConfigDataFactory,
6871
DesignConfigExtensionFactory $configExtensionFactory,
6972
ScopeValidatorInterface $scopeValidator,
70-
StoreManagerInterface $storeManager
73+
StoreManagerInterface $storeManager,
74+
private ?SettingChecker $settingChecker = null
7175
) {
7276
$this->designConfigFactory = $designConfigFactory;
7377
$this->metadataProvider = $metadataProvider;
7478
$this->designConfigDataFactory = $designConfigDataFactory;
7579
$this->configExtensionFactory = $configExtensionFactory;
7680
$this->scopeValidator = $scopeValidator;
7781
$this->storeManager = $storeManager;
82+
$this->settingChecker = $this->settingChecker ?? ObjectManager::getInstance()->get(SettingChecker::class);
7883
}
7984

8085
/**
@@ -100,7 +105,7 @@ public function create($scope, $scopeId, array $data = [])
100105
$configDataObject = $this->designConfigDataFactory->create();
101106
$configDataObject->setPath($metadata['path']);
102107
$configDataObject->setFieldConfig($metadata);
103-
if (isset($data[$name])) {
108+
if (isset($data[$name]) && !$this->settingChecker->isReadOnly($metadata['path'], $scope, $scopeId)) {
104109
$configDataObject->setValue($data[$name]);
105110
}
106111
$configData[] = $configDataObject;

app/code/Magento/Theme/Model/Design/Config/Validator.php

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2016 Adobe
4+
* All Rights Reserved.
55
*/
66

77
namespace Magento\Theme\Model\Design\Config;
@@ -50,22 +50,13 @@ public function __construct(TemplateFactory $templateFactory, $fields = [])
5050
*/
5151
public function validate(DesignConfigInterface $designConfig)
5252
{
53-
/** @var DesignConfigDataInterface[] $designConfigData */
54-
$designConfigData = $designConfig->getExtensionAttributes()->getDesignConfigData();
55-
$elements = [];
56-
foreach ($designConfigData as $designElement) {
57-
if (!in_array($designElement->getFieldConfig()['field'], $this->fields)) {
58-
continue;
59-
}
60-
/* Save mapping between field names and config paths */
61-
$elements[$designElement->getFieldConfig()['field']] = [
62-
'config_path' => $designElement->getPath(),
63-
'value' => $designElement->getValue()
64-
];
65-
}
53+
$elements = $this->getElements($designConfig);
6654

6755
foreach ($elements as $name => $data) {
6856
$templateId = $data['value'];
57+
if (!$templateId) {
58+
continue;
59+
}
6960
$text = $this->getTemplateText($templateId, $designConfig);
7061
// Check if template body has a reference to the same config path
7162
if (preg_match_all(Template::CONSTRUCTION_TEMPLATE_PATTERN, $text, $constructions, PREG_SET_ORDER)) {
@@ -86,6 +77,30 @@ public function validate(DesignConfigInterface $designConfig)
8677
}
8778
}
8879

80+
/**
81+
* Get elements from design configuration
82+
*
83+
* @param DesignConfigInterface $designConfig
84+
* @return array
85+
*/
86+
private function getElements(DesignConfigInterface $designConfig)
87+
{
88+
/** @var DesignConfigDataInterface[] $designConfigData */
89+
$designConfigData = $designConfig->getExtensionAttributes()->getDesignConfigData();
90+
$elements = [];
91+
foreach ($designConfigData as $designElement) {
92+
if (!in_array($designElement->getFieldConfig()['field'], $this->fields)) {
93+
continue;
94+
}
95+
/* Save mapping between field names and config paths */
96+
$elements[$designElement->getFieldConfig()['field']] = [
97+
'config_path' => $designElement->getPath(),
98+
'value' => $designElement->getValue()
99+
];
100+
}
101+
return $elements;
102+
}
103+
89104
/**
90105
* Returns store identifier if is store scope
91106
*
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Theme\Plugin;
9+
10+
use Magento\Config\Console\Command\ConfigSet\ProcessorFacade;
11+
use Magento\Framework\Config\File\ConfigFilePool;
12+
use Magento\Framework\Exception\LocalizedException;
13+
use Magento\Theme\Model\Data\Design\ConfigFactory;
14+
use Magento\Theme\Model\Design\Config\Validator;
15+
16+
class DesignProcessorFacade
17+
{
18+
/**
19+
* @param Validator $validator
20+
* @param ConfigFactory $configFactory
21+
*/
22+
public function __construct(
23+
private Validator $validator,
24+
private ConfigFactory $configFactory
25+
) {
26+
}
27+
28+
/**
29+
* Plugin to validate design configuration data before saving
30+
*
31+
* @param ProcessorFacade $subject
32+
* @param string $path
33+
* @param string $value
34+
* @param string $scope
35+
* @param string $scopeCode
36+
* @param bool $lock
37+
* @param string $lockTarget
38+
* @return string
39+
* @throws LocalizedException
40+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
41+
*/
42+
public function beforeProcessWithLockTarget(
43+
ProcessorFacade $subject,
44+
$path,
45+
$value,
46+
$scope,
47+
$scopeCode,
48+
$lock,
49+
$lockTarget = ConfigFilePool::APP_ENV
50+
) {
51+
if (stripos($path, 'design/') === 0) {
52+
$savePath = str_replace('design/', '', $path);
53+
$savePath = str_replace('/', '_', $savePath);
54+
$designConfig = $this->configFactory->create($scope, $scopeCode, [$savePath => $value]);
55+
$this->validator->validate($designConfig);
56+
}
57+
58+
return [$path, $value, $scope, $scopeCode, $lock, $lockTarget];
59+
}
60+
}

app/code/Magento/Theme/Test/Fixture/DesignConfig.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
namespace Magento\Theme\Test\Fixture;
2020

21+
use Magento\Framework\App\State;
2122
use Magento\Framework\DataObject;
2223
use Magento\Framework\DataObjectFactory;
2324
use Magento\Store\Model\ScopeInterface;
@@ -62,10 +63,12 @@ class DesignConfig implements RevertibleDataFixtureInterface
6263
/**
6364
* @param DesignConfigRepositoryInterface $designConfigRepository
6465
* @param DataObjectFactory $dataObjectFactory
66+
* @param State $state
6567
*/
6668
public function __construct(
6769
private readonly DesignConfigRepositoryInterface $designConfigRepository,
6870
private readonly DataObjectFactory $dataObjectFactory,
71+
private readonly State $state
6972
) {
7073
}
7174

@@ -117,9 +120,12 @@ private function applyConfig(string $scopeType, int $scopeId, array $data): arra
117120
$fieldData->setValue($data[$fieldData->getPath()]);
118121
}
119122
}
123+
$currentArea = $this->state->getAreaCode();
124+
$this->state->setAreaCode('adminhtml');
120125
$designConfig->setScope($scopeType);
121126
$designConfig->setScopeId($scopeId);
122127
$this->designConfigRepository->save($designConfig);
128+
$this->state->setAreaCode($currentArea);
123129
return $origData;
124130
}
125131
}

0 commit comments

Comments
 (0)