Skip to content

Commit abb6dfa

Browse files
authored
Merge pull request #560 from magento-performance/ACPT-1544
ACPT-1544: Fix EAV Config ::attributes to work across websites
2 parents 1fb4668 + 8a9b4cb commit abb6dfa

File tree

3 files changed

+93
-29
lines changed

3 files changed

+93
-29
lines changed

app/code/Magento/Catalog/Model/Config.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@ class Config extends \Magento\Eav\Model\Config
8989
*/
9090
protected $_eavConfig;
9191

92-
/**
93-
* @var \Magento\Store\Model\StoreManagerInterface
94-
*/
95-
protected $_storeManager;
96-
9792
/**
9893
* @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory
9994
*/
@@ -166,7 +161,8 @@ public function __construct(
166161
$universalFactory,
167162
$serializer,
168163
$scopeConfig,
169-
$attributesForPreload
164+
$attributesForPreload,
165+
$storeManager,
170166
);
171167
}
172168

app/code/Magento/Eav/Model/Config.php

Lines changed: 87 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Magento\Framework\Model\AbstractModel;
1616
use Magento\Framework\ObjectManager\ResetAfterRequestInterface;
1717
use Magento\Framework\Serialize\SerializerInterface;
18+
use Magento\Store\Model\StoreManagerInterface;
1819

1920
/**
2021
* EAV config model.
@@ -71,11 +72,8 @@ class Config implements ResetAfterRequestInterface
7172
/**
7273
* Initialized attributes
7374
*
74-
* array ($entityTypeCode =>
75-
* ($attributeCode => $object)
76-
* )
77-
*
78-
* @var AbstractAttribute[][]
75+
* [int $website][string $entityTypeCode][string $code] = AbstractAttribute $attribute
76+
* @var array<int, array<string, array<string, AbstractAttribute>>>
7977
*/
8078
private $attributes;
8179

@@ -123,6 +121,11 @@ class Config implements ResetAfterRequestInterface
123121
*/
124122
protected $_universalFactory;
125123

124+
/**
125+
* @var StoreManagerInterface
126+
*/
127+
protected $_storeManager;
128+
126129
/**
127130
* @var AbstractAttribute[]
128131
*/
@@ -159,6 +162,9 @@ class Config implements ResetAfterRequestInterface
159162
*/
160163
private $attributesForPreload;
161164

165+
/** @var bool[] */
166+
private array $isAttributeTypeWebsiteSpecificCache = [];
167+
162168
/**
163169
* @param \Magento\Framework\App\CacheInterface $cache
164170
* @param Entity\TypeFactory $entityTypeFactory
@@ -168,6 +174,7 @@ class Config implements ResetAfterRequestInterface
168174
* @param SerializerInterface|null $serializer
169175
* @param ScopeConfigInterface|null $scopeConfig
170176
* @param array $attributesForPreload
177+
* @param StoreManagerInterface|null $storeManager
171178
* @codeCoverageIgnore
172179
*/
173180
public function __construct(
@@ -178,7 +185,8 @@ public function __construct(
178185
\Magento\Framework\Validator\UniversalFactory $universalFactory,
179186
SerializerInterface $serializer = null,
180187
ScopeConfigInterface $scopeConfig = null,
181-
$attributesForPreload = []
188+
$attributesForPreload = [],
189+
?StoreManagerInterface $storeManager = null,
182190
) {
183191
$this->_cache = $cache;
184192
$this->_entityTypeFactory = $entityTypeFactory;
@@ -188,6 +196,7 @@ public function __construct(
188196
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);
189197
$this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
190198
$this->attributesForPreload = $attributesForPreload;
199+
$this->_storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class);
191200
}
192201

193202
/**
@@ -243,7 +252,12 @@ protected function _load($id)
243252
*/
244253
private function loadAttributes($entityTypeCode)
245254
{
246-
return $this->attributes[$entityTypeCode] ?? [];
255+
if ($this->isAttributeTypeWebsiteSpecific($entityTypeCode)) {
256+
$websiteId = $this->getWebsiteId();
257+
} else {
258+
$websiteId = 0;
259+
}
260+
return $this->attributes[$websiteId][$entityTypeCode] ?? [];
247261
}
248262

249263
/**
@@ -269,7 +283,12 @@ protected function _save($obj, $id)
269283
*/
270284
private function saveAttribute(AbstractAttribute $attribute, $entityTypeCode, $attributeCode)
271285
{
272-
$this->attributes[$entityTypeCode][$attributeCode] = $attribute;
286+
if ($this->isAttributeTypeWebsiteSpecific($entityTypeCode)) {
287+
$websiteId = $this->getWebsiteId();
288+
} else {
289+
$websiteId = 0;
290+
}
291+
$this->attributes[$websiteId][$entityTypeCode][$attributeCode] = $attribute;
273292
}
274293

275294
/**
@@ -476,7 +495,7 @@ protected function _initAttributes($entityType)
476495

477496
$entityTypeCode = $entityType->getEntityTypeCode();
478497
$attributes = $this->_universalFactory->create($entityType->getEntityAttributeCollection());
479-
$websiteId = $attributes instanceof Collection ? $this->getWebsiteId($attributes) : 0;
498+
$websiteId = $attributes instanceof Collection ? $this->getWebsiteIdFromAttributeCollection($attributes) : 0;
480499
$cacheKey = self::ATTRIBUTES_CACHE_ID . '-' . $entityTypeCode . '-' . $websiteId ;
481500

482501
if ($this->isCacheEnabled() && $this->initAttributesFromCache($entityType, $cacheKey)) {
@@ -537,6 +556,11 @@ public function getAttributes($entityType)
537556
*/
538557
public function getAttribute($entityType, $code)
539558
{
559+
if ($this->isAttributeTypeWebsiteSpecific($entityType)) {
560+
$websiteId = $this->getWebsiteId();
561+
} else {
562+
$websiteId = 0;
563+
}
540564
if ($code instanceof \Magento\Eav\Model\Entity\Attribute\AttributeInterface) {
541565
return $code;
542566
}
@@ -548,19 +572,19 @@ public function getAttribute($entityType, $code)
548572
$code = $this->_getAttributeReference($code, $entityTypeCode) ?: $code;
549573
}
550574

551-
if (isset($this->attributes[$entityTypeCode][$code])) {
575+
if (isset($this->attributes[$websiteId][$entityTypeCode][$code])) {
552576
\Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
553-
return $this->attributes[$entityTypeCode][$code];
577+
return $this->attributes[$websiteId][$entityTypeCode][$code];
554578
}
555579

556580
if (array_key_exists($entityTypeCode, $this->attributesForPreload)
557581
&& array_key_exists($code, $this->attributesForPreload[$entityTypeCode])
558582
) {
559583
$this->initSystemAttributes($entityType, $this->attributesForPreload[$entityTypeCode]);
560584
}
561-
if (isset($this->attributes[$entityTypeCode][$code])) {
585+
if (isset($this->attributes[$websiteId][$entityTypeCode][$code])) {
562586
\Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
563-
return $this->attributes[$entityTypeCode][$code];
587+
return $this->attributes[$websiteId][$entityTypeCode][$code];
564588
}
565589

566590
if ($this->scopeConfig->getValue(self::XML_PATH_CACHE_USER_DEFINED_ATTRIBUTES)) {
@@ -590,7 +614,8 @@ private function initSystemAttributes($entityType, $systemAttributes)
590614
return;
591615
}
592616
$attributeCollection = $this->_universalFactory->create($entityType->getEntityAttributeCollection());
593-
$websiteId = $attributeCollection instanceof Collection ? $this->getWebsiteId($attributeCollection) : 0;
617+
$websiteId = $attributeCollection instanceof Collection
618+
? $this->getWebsiteIdFromAttributeCollection($attributeCollection) : 0;
594619
$cacheKey = self::ATTRIBUTES_CACHE_ID . '-' . $entityTypeCode . '-' . $websiteId . '-preload';
595620
if ($this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey))) {
596621
$attributes = $this->serializer->unserialize($attributes);
@@ -628,7 +653,7 @@ private function initSystemAttributes($entityType, $systemAttributes)
628653
$cacheKey,
629654
[
630655
\Magento\Eav\Model\Cache\Type::CACHE_TAG,
631-
\Magento\Eav\Model\Entity\Attribute::CACHE_TAG
656+
\Magento\Eav\Model\Entity\Attribute::CACHE_TAG,
632657
]
633658
);
634659
}
@@ -904,7 +929,7 @@ public function importAttributesData($entityType, array $attributes)
904929
/**
905930
* Create attribute by attribute code
906931
*
907-
* @param string $entityType
932+
* @param string|Type $entityType
908933
* @param string $attributeCode
909934
* @return AbstractAttribute
910935
* @throws LocalizedException
@@ -973,27 +998,66 @@ private function initAttributesFromCache(Type $entityType, string $cacheKey)
973998
}
974999

9751000
/**
976-
* Returns website id.
1001+
* Returns website id from attribute collection.
9771002
*
9781003
* @param Collection $attributeCollection
9791004
* @return int
9801005
*/
981-
private function getWebsiteId(Collection $attributeCollection): int
1006+
private function getWebsiteIdFromAttributeCollection(Collection $attributeCollection): int
9821007
{
983-
return $attributeCollection->getWebsite() ? (int)$attributeCollection->getWebsite()->getId() : 0;
1008+
return (int)$attributeCollection->getWebsite()?->getId();
1009+
}
1010+
1011+
/**
1012+
* Return current website scope instance
1013+
*
1014+
* @return int website id
1015+
*/
1016+
public function getWebsiteId() : int
1017+
{
1018+
$websiteId = $this->_storeManager->getStore()?->getWebsiteId();
1019+
return (int)$websiteId;
1020+
}
1021+
1022+
/**
1023+
* Returns true if $entityType has website-specific options.
1024+
*
1025+
* Most attributes are global, but some can have website-specific options.
1026+
*
1027+
* @param string|Type $entityType
1028+
* @return bool
1029+
*/
1030+
private function isAttributeTypeWebsiteSpecific(string|Type $entityType) : bool
1031+
{
1032+
if ($entityType instanceof Type) {
1033+
$entityTypeCode = $entityType->getEntityTypeCode();
1034+
} else {
1035+
$entityTypeCode = $entityType;
1036+
}
1037+
if (key_exists($entityTypeCode, $this->isAttributeTypeWebsiteSpecificCache)) {
1038+
return $this->isAttributeTypeWebsiteSpecificCache[$entityTypeCode];
1039+
}
1040+
$entityType = $this->getEntityType($entityType);
1041+
$model = $entityType->getAttributeModel();
1042+
$returnValue = is_a($model, \Magento\Eav\Model\Attribute::class, true);
1043+
$this->isAttributeTypeWebsiteSpecificCache[$entityTypeCode] = $returnValue;
1044+
return $returnValue;
9841045
}
9851046

9861047
/**
9871048
* @inheritDoc
9881049
*/
9891050
public function _resetState(): void
9901051
{
1052+
$this->isAttributeTypeWebsiteSpecificCache = [];
9911053
$this->attributesPerSet = [];
9921054
$this->_attributeData = null;
993-
foreach ($this->attributes ?? [] as $attributesGroupedByEntityTypeCode) {
994-
foreach ($attributesGroupedByEntityTypeCode as $attribute) {
995-
if ($attribute instanceof ResetAfterRequestInterface) {
996-
$attribute->_resetState();
1055+
foreach ($this->attributes ?? [] as $attributesGroupedByWebsites) {
1056+
foreach ($attributesGroupedByWebsites ?? [] as $attributesGroupedByEntityTypeCode) {
1057+
foreach ($attributesGroupedByEntityTypeCode as $attribute) {
1058+
if ($attribute instanceof ResetAfterRequestInterface) {
1059+
$attribute->_resetState();
1060+
}
9971061
}
9981062
}
9991063
}

dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ResetPasswordTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public function testSendEmailWithSetNewPasswordLink(): void
8686
/**
8787
* @magentoAppArea frontend
8888
* @magentoDataFixture Magento/Customer/_files/customer.php
89+
* @magentoConfigFixture current_store customer/password/password_reset_protection_type 0
8990
* @return void
9091
*/
9192
public function testSendPasswordResetLink(): void
@@ -99,6 +100,7 @@ public function testSendPasswordResetLink(): void
99100
/**
100101
* @magentoAppArea frontend
101102
* @magentoDataFixture Magento/Customer/_files/customer.php
103+
* @magentoConfigFixture current_store customer/password/password_reset_protection_type 0
102104
* @return void
103105
*/
104106
public function testSendPasswordResetLinkDefaultWebsite(): void
@@ -112,6 +114,8 @@ public function testSendPasswordResetLinkDefaultWebsite(): void
112114
* @magentoAppArea frontend
113115
* @dataProvider passwordResetErrorsProvider
114116
* @magentoDataFixture Magento/Customer/_files/customer.php
117+
* @magentoConfigFixture current_store customer/password/password_reset_protection_type 0
118+
*
115119
* @param string $email
116120
* @param int|null $websiteId
117121
* @return void

0 commit comments

Comments
 (0)