Skip to content

Commit 73fca9f

Browse files
committed
ACP2E-3633: Browser crash when loading attribute set
1 parent 982b1c4 commit 73fca9f

File tree

10 files changed

+2240
-512
lines changed

10 files changed

+2240
-512
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Product\Attribute;
9+
10+
use Magento\Catalog\Model\Attribute\Config;
11+
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
12+
use Magento\Framework\Exception\LocalizedException;
13+
14+
class AttributeSetUnassignValidator implements AttributeSetUnassignValidatorInterface
15+
{
16+
/**
17+
* @var array
18+
*/
19+
private array $unassignable;
20+
21+
/**
22+
* @param Config $attributeConfig
23+
*/
24+
public function __construct(
25+
private readonly Config $attributeConfig
26+
) {
27+
}
28+
29+
/**
30+
* @inheritDoc
31+
*/
32+
public function validate(AbstractAttribute $attribute, int $attributeSetId): void
33+
{
34+
if (!isset($this->unassignable)) {
35+
$this->unassignable = $this->attributeConfig->getAttributeNames('unassignable');
36+
}
37+
if (in_array($attribute->getAttributeCode(), $this->unassignable)) {
38+
throw new LocalizedException(
39+
__("The system attribute can't be deleted.")
40+
);
41+
}
42+
}
43+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Product\Attribute;
9+
10+
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\Model\AbstractModel;
13+
14+
/**
15+
* Interface to validate attribute removal from an attribute set
16+
*/
17+
interface AttributeSetUnassignValidatorInterface
18+
{
19+
/**
20+
* Validate attribute
21+
*
22+
* @param AbstractModel $attribute
23+
* @param int $attributeSetId
24+
* @return void
25+
* @throws LocalizedException
26+
*/
27+
public function validate(AbstractAttribute $attribute, int $attributeSetId): void;
28+
}

app/code/Magento/Catalog/Model/Product/Attribute/Group.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
namespace Magento\Catalog\Model\Product\Attribute;
77

88
use Magento\Framework\Api\AttributeValueFactory;
9+
use Magento\Framework\App\ObjectManager;
10+
use Magento\Framework\Exception\LocalizedException;
911

1012
class Group extends \Magento\Eav\Model\Entity\Attribute\Group
1113
{
@@ -16,6 +18,11 @@ class Group extends \Magento\Eav\Model\Entity\Attribute\Group
1618
*/
1719
protected $_attributeCollectionFactory;
1820

21+
/**
22+
* @var AttributeSetUnassignValidatorInterface
23+
*/
24+
private $attributeSetUnassignValidator;
25+
1926
/**
2027
* Group constructor.
2128
* @param \Magento\Framework\Model\Context $context
@@ -27,6 +34,8 @@ class Group extends \Magento\Eav\Model\Entity\Attribute\Group
2734
* @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource
2835
* @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection
2936
* @param array $data
37+
* @param AttributeSetUnassignValidatorInterface|null $attributeSetUnassignValidator
38+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
3039
*/
3140
public function __construct(
3241
\Magento\Framework\Model\Context $context,
@@ -37,9 +46,12 @@ public function __construct(
3746
\Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory,
3847
?\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
3948
?\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
40-
array $data = []
49+
array $data = [],
50+
?AttributeSetUnassignValidatorInterface $attributeSetUnassignValidator = null
4151
) {
4252
$this->_attributeCollectionFactory = $attributeCollectionFactory;
53+
$this->attributeSetUnassignValidator = $attributeSetUnassignValidator
54+
?: ObjectManager::getInstance()->get(AttributeSetUnassignValidatorInterface::class);
4355
parent::__construct(
4456
$context,
4557
$registry,
@@ -71,4 +83,24 @@ public function hasSystemAttributes()
7183
}
7284
return $result;
7385
}
86+
87+
/**
88+
* @inheritdoc
89+
*/
90+
public function beforeDelete()
91+
{
92+
$attributesCollection = $this->_attributeCollectionFactory->create();
93+
$attributesCollection->setAttributeGroupFilter($this->getId());
94+
foreach ($attributesCollection as $attribute) {
95+
try {
96+
$this->attributeSetUnassignValidator->validate($attribute, (int) $attribute->getAttributeSetId());
97+
} catch (LocalizedException $e) {
98+
throw new LocalizedException(
99+
__("This group contains system attributes." .
100+
" Please move system attributes to another group and try again.")
101+
);
102+
}
103+
}
104+
return parent::beforeDelete();
105+
}
74106
}

app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
use Magento\Catalog\Model\Attribute\Backend\DefaultBackend;
1010
use Magento\Catalog\Model\Attribute\LockValidatorInterface;
11+
use Magento\Catalog\Model\Product\Attribute\AttributeSetUnassignValidatorInterface;
1112
use Magento\Eav\Model\Entity;
1213
use Magento\Framework\Api\AttributeValueFactory;
14+
use Magento\Framework\App\ObjectManager;
1315
use Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface;
1416

1517
/**
@@ -95,6 +97,11 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute implements
9597
*/
9698
private $eavAttributeFactory;
9799

100+
/**
101+
* @var AttributeSetUnassignValidatorInterface
102+
*/
103+
private $attributeSetUnassignValidator;
104+
98105
/**
99106
* @param \Magento\Framework\Model\Context $context
100107
* @param \Magento\Framework\Registry $registry
@@ -120,6 +127,7 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute implements
120127
* @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection
121128
* @param array $data
122129
* @param \Magento\Eav\Api\Data\AttributeExtensionFactory|null $eavAttributeFactory
130+
* @param AttributeSetUnassignValidatorInterface|null $attributeSetUnassignValidator
123131
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
124132
*/
125133
public function __construct(
@@ -146,14 +154,17 @@ public function __construct(
146154
?\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
147155
?\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
148156
array $data = [],
149-
?\Magento\Eav\Api\Data\AttributeExtensionFactory $eavAttributeFactory = null
157+
?\Magento\Eav\Api\Data\AttributeExtensionFactory $eavAttributeFactory = null,
158+
?AttributeSetUnassignValidatorInterface $attributeSetUnassignValidator = null
150159
) {
151160
$this->_indexerEavProcessor = $indexerEavProcessor;
152161
$this->_productFlatIndexerProcessor = $productFlatIndexerProcessor;
153162
$this->_productFlatIndexerHelper = $productFlatIndexerHelper;
154163
$this->attrLockValidator = $lockValidator;
155164
$this->eavAttributeFactory = $eavAttributeFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
156165
->get(\Magento\Eav\Api\Data\AttributeExtensionFactory::class);
166+
$this->attributeSetUnassignValidator = $attributeSetUnassignValidator
167+
?: ObjectManager::getInstance()->get(AttributeSetUnassignValidatorInterface::class);
157168
parent::__construct(
158169
$context,
159170
$registry,
@@ -914,4 +925,16 @@ protected function _getDefaultBackendModel()
914925

915926
return $backend;
916927
}
928+
929+
/**
930+
* @inheritdoc
931+
*/
932+
public function deleteEntity()
933+
{
934+
if ($this->getEntityAttributeId()) {
935+
$result = $this->_getResource()->getEntityAttribute($this->getEntityAttributeId());
936+
$result && $this->attributeSetUnassignValidator->validate($this, (int) $result['attribute_set_id']);
937+
}
938+
return parent::deleteEntity();
939+
}
917940
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
<preference for="Magento\Catalog\Api\CategoryListDeleteBySkuInterface" type="Magento\Catalog\Model\CategoryLinkRepository"/>
7878
<preference for="Magento\Theme\CustomerData\MessagesProviderInterface" type="Magento\Catalog\Model\Theme\CustomerData\MessagesProvider"/>
7979
<preference for="Magento\Catalog\Api\ProductAttributeIsFilterableManagementInterface" type="Magento\Catalog\Model\Product\Attribute\IsFilterableManagement" />
80+
<preference for="Magento\Catalog\Model\Product\Attribute\AttributeSetUnassignValidatorInterface" type="Magento\Catalog\Model\Product\Attribute\AttributeSetUnassignValidator" />
8081
<type name="Magento\Customer\Model\ResourceModel\Visitor">
8182
<plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
8283
</type>
@@ -1375,4 +1376,24 @@
13751376
</argument>
13761377
</arguments>
13771378
</type>
1379+
<virtualType name="Magento\Catalog\Virtual\Product\Attribute\GroupFactory" type="Magento\Eav\Model\Entity\Attribute\GroupFactory">
1380+
<arguments>
1381+
<argument name="instanceName" xsi:type="string">Magento\Catalog\Model\Product\Attribute\Group</argument>
1382+
</arguments>
1383+
</virtualType>
1384+
<virtualType name="Magento\Catalog\Virtual\Product\Attribute\Set" type="Magento\Eav\Model\Entity\Attribute\Set">
1385+
<arguments>
1386+
<argument name="attrGroupFactory" xsi:type="object">Magento\Catalog\Virtual\Product\Attribute\GroupFactory</argument>
1387+
</arguments>
1388+
</virtualType>
1389+
<virtualType name="Magento\Catalog\Virtual\Product\Attribute\SetFactory" type="Magento\Eav\Model\Entity\Attribute\SetFactory">
1390+
<arguments>
1391+
<argument name="instanceName" xsi:type="string">Magento\Catalog\Virtual\Product\Attribute\Set</argument>
1392+
</arguments>
1393+
</virtualType>
1394+
<type name="Magento\Catalog\Controller\Adminhtml\Product\Set\Save">
1395+
<arguments>
1396+
<argument name="attributeSetFactory" xsi:type="object">Magento\Catalog\Virtual\Product\Attribute\SetFactory</argument>
1397+
</arguments>
1398+
</type>
13781399
</config>

0 commit comments

Comments
 (0)