diff --git a/vendor/magento/module-catalog/Model/Attribute/ScopeOverriddenValue.php b/vendor/magento/module-catalog/Model/Attribute/ScopeOverriddenValue.php index e58383f7d9b..16fcc4f207d 100644 --- a/vendor/magento/module-catalog/Model/Attribute/ScopeOverriddenValue.php +++ b/vendor/magento/module-catalog/Model/Attribute/ScopeOverriddenValue.php @@ -6,6 +6,8 @@ namespace Magento\Catalog\Model\Attribute; +use Magento\Catalog\Model\AbstractModel; +use Magento\Framework\DataObject; use Magento\Framework\EntityManager\MetadataPool; use Magento\Eav\Api\AttributeRepositoryInterface as AttributeRepository; use Magento\Framework\Api\SearchCriteriaBuilder; @@ -15,7 +17,6 @@ use Magento\Store\Model\Store; use Magento\Framework\App\ResourceConnection; /** - * Class ScopeOverriddenValue * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ScopeOverriddenValue @@ -76,7 +77,7 @@ class ScopeOverriddenValue * Whether attribute value is overridden in specific store * * @param string $entityType - * @param \Magento\Catalog\Model\AbstractModel $entity + * @param AbstractModel $entity * @param string $attributeCode * @param int|string $storeId * @return bool @@ -86,39 +87,41 @@ class ScopeOverriddenValue if ((int)$storeId === Store::DEFAULT_STORE_ID) { return false; } - if (!isset($this->attributesValues[$storeId])) { + $values = $this->getAttributesValues($entityType, $entity); + + if (!isset($values[$storeId])) { $this->initAttributeValues($entityType, $entity, (int)$storeId); + $values = $this->getAttributesValues($entityType, $entity); } - return isset($this->attributesValues[$storeId]) - && array_key_exists($attributeCode, $this->attributesValues[$storeId]); + return isset($values[$storeId]) && array_key_exists($attributeCode, $values[$storeId]); } /** * Get attribute default values * * @param string $entityType - * @param \Magento\Catalog\Model\AbstractModel $entity + * @param AbstractModel $entity * @return array * * @deprecated 101.0.0 */ public function getDefaultValues($entityType, $entity) { - if ($this->attributesValues === null) { + $values = $this->getAttributesValues($entityType, $entity); + if (!isset($values[Store::DEFAULT_STORE_ID])) { $this->initAttributeValues($entityType, $entity, (int)$entity->getStoreId()); + $values = $this->getAttributesValues($entityType, $entity); } - return isset($this->attributesValues[Store::DEFAULT_STORE_ID]) - ? $this->attributesValues[Store::DEFAULT_STORE_ID] - : []; + return $values[Store::DEFAULT_STORE_ID] ?? []; } /** * Init attribute values. * * @param string $entityType - * @param \Magento\Catalog\Model\AbstractModel $entity + * @param AbstractModel $entity * @param int $storeId * @throws \Magento\Framework\Exception\LocalizedException * @return void @@ -129,6 +132,7 @@ class ScopeOverriddenValue /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */ $attributeTables = []; if ($metadata->getEavEntityType()) { + $entityId = $entity->getData($metadata->getLinkField()); foreach ($this->getAttributes($entityType) as $attribute) { if (!$attribute->isStatic()) { $attributeTables[$attribute->getBackend()->getTable()][] = $attribute->getAttributeId(); @@ -147,7 +151,7 @@ class ScopeOverriddenValue 'a.attribute_id = t.attribute_id', ['attribute_code' => 'a.attribute_code'] ) - ->where($metadata->getLinkField() . ' = ?', $entity->getData($metadata->getLinkField())) + ->where($metadata->getLinkField() . ' = ?', $entityId) ->where('t.attribute_id IN (?)', $attributeCodes) ->where('t.store_id IN (?)', $storeIds); $selects[] = $select; @@ -158,9 +162,12 @@ class ScopeOverriddenValue \Magento\Framework\DB\Select::SQL_UNION_ALL ); $attributes = $metadata->getEntityConnection()->fetchAll((string)$unionSelect); + $values = array_fill_keys($storeIds, []); foreach ($attributes as $attribute) { - $this->attributesValues[$attribute['store_id']][$attribute['attribute_code']] = $attribute['value']; + $values[$attribute['store_id']][$attribute['attribute_code']] = $attribute['value']; } + $values += $this->getAttributesValues($entityType, $entity); + $this->setAttributesValues($entityType, $entity, $values); } } @@ -187,4 +194,52 @@ class ScopeOverriddenValue ); return $searchResult->getItems(); } + + /** + * Clear entity attributes values cache + * + * @param string $entityType + * @param DataObject $entity + * @return void + * @throws \Exception + */ + public function clearAttributesValues(string $entityType, DataObject $entity): void + { + if (isset($this->attributesValues[$entityType])) { + $metadata = $this->metadataPool->getMetadata($entityType); + $entityId = $entity->getData($metadata->getLinkField()); + unset($this->attributesValues[$entityType][$entityId]); + } + } + + /** + * Get entity attributes values from cache + * + * @param string $entityType + * @param DataObject $entity + * @return array + * @throws \Exception + */ + private function getAttributesValues(string $entityType, DataObject $entity): array + { + $metadata = $this->metadataPool->getMetadata($entityType); + $entityId = $entity->getData($metadata->getLinkField()); + return $this->attributesValues[$entityType][$entityId] ?? []; + } + + /** + * Set entity attributes values into cache + * + * @param string $entityType + * @param DataObject $entity + * @param array $values + * @return void + * @throws \Exception + */ + private function setAttributesValues(string $entityType, DataObject $entity, array $values): void + { + $metadata = $this->metadataPool->getMetadata($entityType); + $entityId = $entity->getData($metadata->getLinkField()); + $this->attributesValues[$entityType][$entityId] = $values; + } } diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product.php b/vendor/magento/module-catalog/Model/ResourceModel/Product.php index b3c50015d9d..b72bd8c4415 100644 --- a/vendor/magento/module-catalog/Model/ResourceModel/Product.php +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product.php @@ -5,6 +5,8 @@ */ namespace Magento\Catalog\Model\ResourceModel; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\ResourceModel\Product\Website\Link as ProductWebsiteLink; use Magento\Eav\Api\AttributeManagementInterface; use Magento\Framework\App\ObjectManager; @@ -40,15 +42,11 @@ class Product extends AbstractResource protected $_productCategoryTable; /** - * Catalog category - * * @var Category */ protected $_catalogCategory; /** - * Category collection factory - * * @var Category\CollectionFactory */ protected $_categoryCollectionFactory; @@ -105,6 +103,11 @@ class Product extends AbstractResource */ private $mediaImageDeleteProcessor; + /** + * @var ScopeOverriddenValue + */ + private $scopeOverriddenValue; + /** * @param \Magento\Eav\Model\Entity\Context $context * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -120,6 +123,7 @@ class Product extends AbstractResource * @param UniqueValidationInterface|null $uniqueValidator * @param AttributeManagementInterface|null $eavAttributeManagement * @param MediaImageDeleteProcessor|null $mediaImageDeleteProcessor + * @param ScopeOverriddenValue|null $scopeOverriddenValue * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -136,7 +140,8 @@ class Product extends AbstractResource TableMaintainer $tableMaintainer = null, UniqueValidationInterface $uniqueValidator = null, AttributeManagementInterface $eavAttributeManagement = null, - ?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null + ?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null, + ?ScopeOverriddenValue $scopeOverriddenValue = null ) { $this->_categoryCollectionFactory = $categoryCollectionFactory; $this->_catalogCategory = $catalogCategory; @@ -157,6 +162,8 @@ class Product extends AbstractResource ?? ObjectManager::getInstance()->get(AttributeManagementInterface::class); $this->mediaImageDeleteProcessor = $mediaImageDeleteProcessor ?? ObjectManager::getInstance()->get(MediaImageDeleteProcessor::class); + $this->scopeOverriddenValue = $scopeOverriddenValue + ?? ObjectManager::getInstance()->get(ScopeOverriddenValue::class); } /** @@ -316,6 +323,7 @@ class Product extends AbstractResource { $this->removeNotInSetAttributeValues($product); $this->_saveWebsiteIds($product)->_saveCategories($product); + $this->scopeOverriddenValue->clearAttributesValues(ProductInterface::class, $product); return parent::_afterSave($product); }