From 66874c3ad57aa1f37205e8516a99fc9cd7cf2022 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 5 Apr 2017 15:15:33 +0300 Subject: [PATCH 01/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Catalog/Model/ResourceModel/Category.php | 11 ++- .../Catalog/Model/ResourceModel/Product.php | 11 ++- .../Aggregation/AggregationResolver.php | 1 + app/code/Magento/Eav/Model/Config.php | 89 +++++++++++++------ .../Eav/Model/Entity/AbstractEntity.php | 39 ++++---- .../Eav/Model/Entity/AttributeLoader.php | 7 +- .../Swatches/Model/Plugin/Configurable.php | 38 ++++---- 7 files changed, 121 insertions(+), 75 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index b01870fecb52c..a9c705697b268 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -1011,7 +1011,16 @@ public function countVisible() public function load($object, $entityId, $attributes = []) { $this->_attributes = []; - $this->loadAttributesMetadata($attributes); + $select = $this->_getLoadRowSelect($object, $entityId); + $row = $this->getConnection()->fetchRow($select); + + if (is_array($row)) { + $object->addData($row); + } else { + $object->isObjectNew(true); + } + + $this->loadAttributesForObject($attributes, $object); $object = $this->getEntityManager()->load($object, $entityId); if (!$this->getEntityManager()->has($object)) { $object->isObjectNew(true); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product.php b/app/code/Magento/Catalog/Model/ResourceModel/Product.php index 5dd618450ad65..9da059bd8ea00 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product.php @@ -567,7 +567,16 @@ public function validate($object) */ public function load($object, $entityId, $attributes = []) { - $this->loadAttributesMetadata($attributes); + $select = $this->_getLoadRowSelect($object, $entityId); + $row = $this->getConnection()->fetchRow($select); + + if (is_array($row)) { + $object->addData($row); + } else { + $object->isObjectNew(true); + } + + $this->loadAttributesForObject($attributes, $object); $this->getEntityManager()->load($object, $entityId); return $this; } diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php b/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php index 9d6c10d4dfc32..950afaa66be78 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php @@ -87,6 +87,7 @@ private function getApplicableAttributeCodes(array $documentIds) $searchCriteria = $this->searchCriteriaBuilder ->addFilter('attribute_set_id', $attributeSetIds, 'in') + ->addFilter('is_filterable', true) ->create(); $result = $this->productAttributeRepository->getList($searchCriteria); diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index ba5ef33138602..c68f3f211abbd 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -107,7 +107,7 @@ class Config protected $_universalFactory; /** - * @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute[] + * @var AbstractAttribute[] */ private $attributeProto = []; @@ -499,22 +499,22 @@ public function getAttribute($entityType, $code) return $code; } \Magento\Framework\Profiler::start('EAV: ' . __METHOD__, ['group' => 'EAV', 'method' => __METHOD__]); - $this->_initAttributes($entityType); - $entityTypeCode = $this->getEntityType($entityType)->getEntityTypeCode(); - if (is_numeric($code)) { - $attributeCode = $this->_getAttributeReference($code, $entityTypeCode); - if ($attributeCode) { - $code = $attributeCode; - } + + if (is_numeric($code)) { // if code is numeric, try to map attribute id to code + $code = $this->_getAttributeReference($code, $entityTypeCode) ?: $code; } $attributes = $this->loadAttributes($entityTypeCode); $attribute = isset($attributes[$code]) ? $attributes[$code] : null; if (!$attribute) { $attribute = $this->createAttributeByAttributeCode($entityType, $code); - $this->_addAttributeReference($code, $code, $entityTypeCode); - $this->saveAttribute($attribute, $entityTypeCode, $code); + $this->_addAttributeReference( + $attribute->getAttributeId(), + $attribute->getAttributeCode(), + $entityTypeCode + ); + $this->saveAttribute($attribute, $entityTypeCode, $attribute->getAttributeCode()); } \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__); return $attribute; @@ -529,7 +529,7 @@ public function getAttribute($entityType, $code) private function createAttribute($model) { if (!isset($this->attributeProto[$model])) { - /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */ + /** @var AbstractAttribute $attribute */ $this->attributeProto[$model] = $this->_universalFactory->create($model); } return clone $this->attributeProto[$model]; @@ -563,6 +563,42 @@ public function getEntityAttributeCodes($entityType, $object = null) return $this->_attributeCodes[$cacheKey]; } + $attributes = array_keys($this->getEntityAttributes($entityType, $object)); + + $this->_attributeCodes[$cacheKey] = $attributes; + if ($this->isCacheEnabled()) { + $this->_cache->save( + $this->serializer->serialize($attributes), + $cacheKey, + [ + \Magento\Eav\Model\Cache\Type::CACHE_TAG, + \Magento\Eav\Model\Entity\Attribute::CACHE_TAG + ] + ); + } + + return $attributes; + } + + + /** + * Get all entity type attributes + * + * @param int|string|Type $entityType + * @param \Magento\Framework\DataObject|null $object + * @return AbstractAttribute[] + */ + public function getEntityAttributes($entityType, $object = null) + { + $entityType = $this->getEntityType($entityType); + $attributeSetId = 0; + $storeId = 0; + if ($object instanceof \Magento\Framework\DataObject) { + $attributeSetId = $object->getAttributeSetId() ?: $attributeSetId; + $storeId = $object->getStoreId() ?: $storeId; + } + + $attributes = []; if ($attributeSetId) { $attributesInfo = $this->_universalFactory->create( $entityType->getEntityAttributeCollection() @@ -573,28 +609,17 @@ public function getEntityAttributeCodes($entityType, $object = null) )->addStoreLabel( $storeId )->getData(); - $attributes = []; + foreach ($attributesInfo as $attributeData) { - $attributes[] = $attributeData['attribute_code']; - $this->_createAttribute($entityType, $attributeData); + $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); } } else { $this->_initAttributes($entityType); - $attributes = array_keys($this->_attributeData[$entityType->getEntityTypeCode()]); - } - - $this->_attributeCodes[$cacheKey] = $attributes; - if ($this->isCacheEnabled()) { - $this->_cache->save( - $this->serializer->serialize($attributes), - $cacheKey, - [ - \Magento\Eav\Model\Cache\Type::CACHE_TAG, - \Magento\Eav\Model\Entity\Attribute::CACHE_TAG - ] - ); + $attributesData = $this->_attributeData[$entityType->getEntityTypeCode()]; + foreach ($attributesData as $attributeData) { + $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); + } } - return $attributes; } @@ -691,7 +716,13 @@ private function createAttributeByAttributeCode($entityType, $attributeCode) { $entityType = $this->getEntityType($entityType); $attribute = $this->createAttribute($entityType->getAttributeModel()); - $attribute->setAttributeCode($attributeCode); + if (is_numeric($attributeCode)) { + $attribute->load($attributeCode); + } else { + $attribute->loadByCode($entityType->getEntityTypeId(), $attributeCode); + $attribute->setAttributeCode($attributeCode); + } + $entity = $entityType->getEntity(); if ($entity && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes())) { $attribute->setBackendType( diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 46660138d32e1..b7d744d5dcfc2 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -394,7 +394,6 @@ protected function _getConfig() */ public function getAttribute($attribute) { - /** @var $config \Magento\Eav\Model\Config */ $config = $this->_getConfig(); if (is_numeric($attribute)) { @@ -456,6 +455,7 @@ public function getAttribute($attribute) */ public function addAttribute(AbstractAttribute $attribute) { + $attribute = clone $attribute; //we change state of attribute, so lets make copy $attribute->setEntity($this); $attributeCode = $attribute->getAttributeCode(); @@ -961,13 +961,6 @@ public function load($object, $entityId, $attributes = []) $object->isObjectNew(true); } - $this->loadAttributesMetadata($attributes); - - $this->_loadModelAttributes($object); - $this->_afterLoad($object); - $object->afterLoad(); - $object->setOrigData(); - $object->setHasDataChanges(false); \Magento\Framework\Profiler::stop('EAV:load_entity'); return $this; } @@ -975,21 +968,13 @@ public function load($object, $entityId, $attributes = []) /** * Loads attributes metadata. * + * @deprecated Use self::loadAttributesForObject instead * @param array|null $attributes * @return $this */ protected function loadAttributesMetadata($attributes) { - if (empty($attributes)) { - $this->loadAllAttributes(); - } else { - if (!is_array($attributes)) { - $attributes = [$attributes]; - } - foreach ($attributes as $attrCode) { - $this->getAttribute($attrCode); - } - } + $this->loadAttributesForObject($attributes); } /** @@ -1926,4 +1911,22 @@ public function afterDelete(\Magento\Framework\DataObject $object) { $this->_afterDelete($object); } + + /** + * @param array $attributes + * @param |null $object + */ + protected function loadAttributesForObject($attributes, $object = null) + { + if (empty($attributes)) { + $this->loadAllAttributes($object); + } else { + if (!is_array($attributes)) { + $attributes = [$attributes]; + } + foreach ($attributes as $attrCode) { + $this->getAttribute($attrCode); + } + } + } } diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index 2dd362b445a09..0e31d9e75bf93 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -57,7 +57,8 @@ public function __construct( */ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = null) { - $attributeCodes = $this->config->getEntityAttributeCodes($resource->getEntityType(), $object); + $attributes = $this->config->getEntityAttributes($resource->getEntityType(), $object); + $attributeCodes = array_keys($attributes); /** * Check and init default attributes */ @@ -71,8 +72,8 @@ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = $resource->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); } } - foreach ($attributeCodes as $code) { - $resource->getAttribute($code); + foreach ($attributes as $code => $attribute) { + $resource->addAttribute($attribute); } return $resource; } diff --git a/app/code/Magento/Swatches/Model/Plugin/Configurable.php b/app/code/Magento/Swatches/Model/Plugin/Configurable.php index a66e820253fa6..97bc71fd2fce1 100644 --- a/app/code/Magento/Swatches/Model/Plugin/Configurable.php +++ b/app/code/Magento/Swatches/Model/Plugin/Configurable.php @@ -5,6 +5,7 @@ */ namespace Magento\Swatches\Model\Plugin; +use Magento\Catalog\Api\Data\ProductInterface; use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableProductType; use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection; @@ -20,11 +21,6 @@ class Configurable */ private $swatchHelper; - /** - * @var array - */ - private $swatchAttributes; - /** * @param \Magento\Swatches\Model\SwatchFactory $eavConfig * @param \Magento\Swatches\Helper\Data $swatchHelper @@ -38,33 +34,29 @@ public function __construct( } /** - * Returns Configurable Products Collection with added swatch attributes + * Add swatch attributes to Configurable Products Collection * - * @param ConfigurableProduct $subject + * @param ConfigurableProductType $subject * @param Collection $result + * @param ProductInterface $product * @return Collection - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function afterGetUsedProductCollection( ConfigurableProductType $subject, - Collection $result + Collection $result, + ProductInterface $product ) { - if (!$this->swatchAttributes) { - $this->swatchAttributes = ['image']; - $entityType = $result->getEntity()->getType(); - foreach ($this->eavConfig->getEntityAttributeCodes($entityType) as $code) { - $attribute = $this->eavConfig->getAttribute($entityType, $code); - if ($attribute->getData('additional_data') - && ( - $this->swatchHelper->isVisualSwatch($attribute) || $this->swatchHelper->isTextSwatch($attribute) - ) - ) { - $this->swatchAttributes[] = $code; - } + $swatchAttributes = ['image']; + foreach ($subject->getUsedProductAttributes($product) as $code => $attribute) { + if ($attribute->getData('additional_data') + && ( + $this->swatchHelper->isVisualSwatch($attribute) || $this->swatchHelper->isTextSwatch($attribute) + ) + ) { + $swatchAttributes[] = $code; } } - $result->addAttributeToSelect($this->swatchAttributes); + $result->addAttributeToSelect($swatchAttributes); return $result; } } From 1e27fadf60dc9c7f6d30c9406f86208f804618f5 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 5 Apr 2017 17:01:21 +0300 Subject: [PATCH 02/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Entity/AttributeLoader.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index 0e31d9e75bf93..f62b12f1e12d2 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -62,18 +62,19 @@ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = /** * Check and init default attributes */ + $storage = $object ?: $resource; $defaultAttributes = $resource->getDefaultAttributes(); foreach ($defaultAttributes as $attributeCode) { $attributeIndex = array_search($attributeCode, $attributeCodes); if ($attributeIndex !== false) { - $resource->getAttribute($attributeCodes[$attributeIndex]); + $storage->getAttribute($attributeCodes[$attributeIndex]); unset($attributeCodes[$attributeIndex]); } else { - $resource->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); + $storage->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); } } foreach ($attributes as $code => $attribute) { - $resource->addAttribute($attribute); + $storage->addAttribute($attribute); } return $resource; } From 2d57480a81b03961a60a5f82eb871e6f6809fa0c Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 5 Apr 2017 17:38:08 +0300 Subject: [PATCH 03/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Magento/Eav/Model/Entity/AbstractEntity.php | 10 +++++++++- .../Magento/Eav/Model/Entity/AttributeLoader.php | 15 ++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index b7d744d5dcfc2..393a40c8cb11c 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -957,10 +957,18 @@ public function load($object, $entityId, $attributes = []) if (is_array($row)) { $object->addData($row); + $this->loadAttributesForObject($attributes, $object); + + $this->_loadModelAttributes($object); + $this->_afterLoad($object); + $object->afterLoad(); + $object->setOrigData(); + $object->setHasDataChanges(false); } else { $object->isObjectNew(true); } + \Magento\Framework\Profiler::stop('EAV:load_entity'); return $this; } @@ -1655,7 +1663,7 @@ protected function getAttributeRow($entity, $object, $attribute) { $data = [ 'attribute_id' => $attribute->getId(), - $entity->getLinkField() => $object->getData($entity->getLinkField()), + $this->getLinkField() => $object->getData($this->getLinkField()), ]; if (!$this->getEntityTable()) { diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index f62b12f1e12d2..df2411e18c283 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -62,19 +62,12 @@ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = /** * Check and init default attributes */ - $storage = $object ?: $resource; - $defaultAttributes = $resource->getDefaultAttributes(); - foreach ($defaultAttributes as $attributeCode) { - $attributeIndex = array_search($attributeCode, $attributeCodes); - if ($attributeIndex !== false) { - $storage->getAttribute($attributeCodes[$attributeIndex]); - unset($attributeCodes[$attributeIndex]); - } else { - $storage->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); - } + $defaultAttributesCodes = array_intersect($resource->getDefaultAttributes(), $attributeCodes); + foreach ($defaultAttributesCodes as $attributeCode) { + $resource->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); } foreach ($attributes as $code => $attribute) { - $storage->addAttribute($attribute); + $resource->addAttribute($attribute); } return $resource; } From 105f43db701a74f6b6e7d586eba103b53643b8f8 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 7 Apr 2017 11:19:28 +0300 Subject: [PATCH 04/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/bootstrap.php | 23 +++++++++++++++++++ .../Model/Product/Type/AbstractType.php | 3 +-- app/code/Magento/Eav/Model/Config.php | 2 +- .../Eav/Model/Entity/AbstractEntity.php | 4 ++-- .../Entity/Attribute/AbstractAttribute.php | 4 ++-- .../Eav/Model/Entity/AttributeLoader.php | 2 +- .../Observer/AfterEntitySave.php | 2 +- 7 files changed, 31 insertions(+), 9 deletions(-) diff --git a/app/bootstrap.php b/app/bootstrap.php index a3d48bca147fe..63dc22881481c 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -62,3 +62,26 @@ /* Adjustment of precision value for several versions of PHP */ ini_set('precision', 17); ini_set('serialize_precision', 17); + +register_shutdown_function(function (){ + if (strpos(@$_SERVER['HTTP_ACCEPT'], 'text/html') !== false) { + /** @var \Magento\Framework\App\Resource $adapter */ + $adapter = \Magento\Framework\App\ObjectManager::getInstance() + ->get('Magento\Framework\App\ResourceConnection'); + // composer.phar require "jdorn/sql-formatter:1.3.*@dev" + // require_once '/home/user/.composer/vendor/jdorn/sql-formatter/lib/SqlFormatter.php'; + /** @var Zend_Db_Profiler $profiler */ + $profiler = $adapter->getConnection('read')->getProfiler(); + if ($profiler->getEnabled()) { + echo ""; + echo ''; + foreach ($profiler->getQueryProfiles() as $query) { + /** @var Zend_Db_Profiler_Query $query*/ + echo ''; + echo ''; + echo ''; + echo ''; + } + } + } +}); diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php index 805d6edc66f1f..1d3e4a2d9e6f4 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php +++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php @@ -723,8 +723,7 @@ public function save($product) protected function _removeNotApplicableAttributes($product) { $entityType = $product->getResource()->getEntityType(); - foreach ($this->_eavConfig->getEntityAttributeCodes($entityType, $product) as $attributeCode) { - $attribute = $this->_eavConfig->getAttribute($entityType, $attributeCode); + foreach ($this->_eavConfig->getEntityAttributes($entityType, $product) as $attributeCode => $attribute) { $applyTo = $attribute->getApplyTo(); if (is_array($applyTo) && count($applyTo) > 0 && !in_array($product->getTypeId(), $applyTo)) { $product->unsetData($attribute->getAttributeCode()); diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index c68f3f211abbd..082e54a92d474 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -608,7 +608,7 @@ public function getEntityAttributes($entityType, $object = null) $attributeSetId )->addStoreLabel( $storeId - )->getData(); + )->addSetInfo()->getData(); foreach ($attributesInfo as $attributeData) { $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 393a40c8cb11c..2142a0495303b 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -455,7 +455,7 @@ public function getAttribute($attribute) */ public function addAttribute(AbstractAttribute $attribute) { - $attribute = clone $attribute; //we change state of attribute, so lets make copy + $attribute = $attribute; //we change state of attribute, so lets make copy $attribute->setEntity($this); $attributeCode = $attribute->getAttributeCode(); @@ -685,7 +685,7 @@ protected function _isCallableAttributeInstance($instance, $method, $args) /** * Get attributes by name array * - * @return array + * @return \Magento\Eav\Model\Entity\Attribute[] */ public function getAttributesByCode() { diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index 7b17599941ebf..d9e2a532f8019 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -515,7 +515,7 @@ public function setEntity($entity) public function getEntity() { if (!$this->_entity) { - $this->_entity = $this->getEntityType(); + throw new \RuntimeException('Entity does not set'); } return $this->_entity; @@ -753,7 +753,7 @@ public function getBackendTable() } else { $backendTable = trim($this->_getData('backend_table')); if (empty($backendTable)) { - $entityTable = [$this->getEntity()->getEntityTablePrefix(), $this->getBackendType()]; + $entityTable = [$this->getEntityType()->getEntityTablePrefix(), $this->getBackendType()]; $backendTable = $this->getResource()->getTable($entityTable); } $this->_dataTable = $backendTable; diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index df2411e18c283..da1c4573889e0 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -66,7 +66,7 @@ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = foreach ($defaultAttributesCodes as $attributeCode) { $resource->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); } - foreach ($attributes as $code => $attribute) { + foreach ($attributes as $attributeCode => $attribute) { $resource->addAttribute($attribute); } return $resource; diff --git a/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php b/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php index 799e1b9dc0e22..b855929afbe8c 100644 --- a/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php +++ b/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php @@ -28,7 +28,7 @@ public function execute(Observer $observer) $entity = $observer->getEvent()->getEntity(); if ($entity instanceof AbstractModel) { if (method_exists($entity->getResource(), 'loadAllAttributes')) { - $entity->getResource()->loadAllAttributes(); + $entity->getResource()->loadAllAttributes($entity); } $entity->getResource()->afterSave($entity); $entity->afterSave(); From b22c8370b9a9ee718f030eb206d1478f9ff23f41 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 7 Apr 2017 13:08:39 +0300 Subject: [PATCH 05/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 8 ++++---- .../Eav/Model/Entity/Attribute/AbstractAttribute.php | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 082e54a92d474..4a8fba57309cf 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -716,13 +716,13 @@ private function createAttributeByAttributeCode($entityType, $attributeCode) { $entityType = $this->getEntityType($entityType); $attribute = $this->createAttribute($entityType->getAttributeModel()); - if (is_numeric($attributeCode)) { - $attribute->load($attributeCode); - } else { - $attribute->loadByCode($entityType->getEntityTypeId(), $attributeCode); + + $attribute->loadByCode($entityType->getEntityTypeId(), $attributeCode); + if (empty($attribute->getId())) { $attribute->setAttributeCode($attributeCode); } + $entity = $entityType->getEntity(); if ($entity && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes())) { $attribute->setBackendType( diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index d9e2a532f8019..58c0cec7979a9 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -865,6 +865,7 @@ public function _getFlatColumnsDdlDefinition() * Retrieve flat columns definition in old format (before MMDB support) * Used in database compatible mode * + * @deprecated * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ From bf3c79430507fb3748fa8a7b4926d750bfd45310 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 7 Apr 2017 13:21:42 +0300 Subject: [PATCH 06/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 4a8fba57309cf..8bcc938b32bd7 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -608,7 +608,8 @@ public function getEntityAttributes($entityType, $object = null) $attributeSetId )->addStoreLabel( $storeId - )->addSetInfo()->getData(); + ) + ->getData(); foreach ($attributesInfo as $attributeData) { $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); @@ -716,13 +717,16 @@ private function createAttributeByAttributeCode($entityType, $attributeCode) { $entityType = $this->getEntityType($entityType); $attribute = $this->createAttribute($entityType->getAttributeModel()); - - $attribute->loadByCode($entityType->getEntityTypeId(), $attributeCode); - if (empty($attribute->getId())) { + if (is_numeric($attributeCode)) { + $attribute->load($attributeCode); + if ($attribute->getEntityTypeId() != $entityType->getId()) { + $attribute = $this->createAttribute($entityType->getAttributeModel()); + } + } else { + $attribute->loadByCode($entityType->getEntityTypeId(), $attributeCode); $attribute->setAttributeCode($attributeCode); } - $entity = $entityType->getEntity(); if ($entity && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes())) { $attribute->setBackendType( From f1cd1ba8f5b620173527d9de62b19f3849aae807 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 7 Apr 2017 15:27:05 +0300 Subject: [PATCH 07/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 8bcc938b32bd7..7e6bc734697b4 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -441,9 +441,7 @@ protected function _initAttributes($entityType) } // attributes should be reloaded via model to be processed by custom resource model $attributeObject = $this->_createAttribute($entityType, $attribute); - $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attributeObject->load( - $attributeObject->getId() - )->toArray(); + $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attributeObject->toArray(); } if ($this->isCacheEnabled()) { $this->_cache->save( From 0f7b9cac1507905f4164d0c5329d56081acd3378 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 7 Apr 2017 16:25:39 +0300 Subject: [PATCH 08/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Catalog/Model/ResourceModel/Attribute.php | 2 +- app/code/Magento/Eav/Model/Attribute/Data/File.php | 2 +- app/code/Magento/Eav/Model/Entity/AbstractEntity.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php index bdb3cdab617ac..964c99b301259 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php @@ -142,7 +142,7 @@ public function deleteEntity(\Magento\Framework\Model\AbstractModel $object) ->getLinkField(); $select = $this->getConnection()->select()->from( - $attribute->getEntity()->getEntityTable(), + $attribute->getEntityType()->getEntityTable(), $linkField )->where( 'attribute_set_id = ?', diff --git a/app/code/Magento/Eav/Model/Attribute/Data/File.php b/app/code/Magento/Eav/Model/Attribute/Data/File.php index c49b85481177c..44cdcf30a3a55 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/File.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/File.php @@ -229,7 +229,7 @@ public function compactValue($value) } } - $destinationFolder = $attribute->getEntity()->getEntityTypeCode(); + $destinationFolder = $attribute->getEntityType()->getEntityTypeCode(); // unlink entity file if ($toDelete) { diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 2142a0495303b..192e4acafe93a 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -685,7 +685,7 @@ protected function _isCallableAttributeInstance($instance, $method, $args) /** * Get attributes by name array * - * @return \Magento\Eav\Model\Entity\Attribute[] + * @return array */ public function getAttributesByCode() { From 3cf4b23d44fba9e1d3038354cbd56f3001f397d4 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 7 Apr 2017 18:04:39 +0300 Subject: [PATCH 09/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Model/Adapter/Aggregation/AggregationResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php b/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php index 950afaa66be78..88b2cd77bd971 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Aggregation/AggregationResolver.php @@ -87,7 +87,7 @@ private function getApplicableAttributeCodes(array $documentIds) $searchCriteria = $this->searchCriteriaBuilder ->addFilter('attribute_set_id', $attributeSetIds, 'in') - ->addFilter('is_filterable', true) + ->addFilter('is_filterable', 0, 'neq') ->create(); $result = $this->productAttributeRepository->getList($searchCriteria); From 3a64250badc693852cf8773f27f37277296c2e1f Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Mon, 10 Apr 2017 15:59:53 +0300 Subject: [PATCH 10/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/bootstrap.php | 23 ----------------------- app/code/Magento/Eav/Model/Attribute.php | 2 +- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/app/bootstrap.php b/app/bootstrap.php index 63dc22881481c..a3d48bca147fe 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -62,26 +62,3 @@ /* Adjustment of precision value for several versions of PHP */ ini_set('precision', 17); ini_set('serialize_precision', 17); - -register_shutdown_function(function (){ - if (strpos(@$_SERVER['HTTP_ACCEPT'], 'text/html') !== false) { - /** @var \Magento\Framework\App\Resource $adapter */ - $adapter = \Magento\Framework\App\ObjectManager::getInstance() - ->get('Magento\Framework\App\ResourceConnection'); - // composer.phar require "jdorn/sql-formatter:1.3.*@dev" - // require_once '/home/user/.composer/vendor/jdorn/sql-formatter/lib/SqlFormatter.php'; - /** @var Zend_Db_Profiler $profiler */ - $profiler = $adapter->getConnection('read')->getProfiler(); - if ($profiler->getEnabled()) { - echo "
', $profiler->getTotalElapsedSecs(), 's ','', $profiler->getTotalNumQueries() , 'queries', '', microtime(1) - $_SERVER['REQUEST_TIME_FLOAT'], '
', number_format(1000 * $query->getElapsedSecs(), 2), 'ms', '', $query->getQuery(), '
"; - echo ''; - foreach ($profiler->getQueryProfiles() as $query) { - /** @var Zend_Db_Profiler_Query $query*/ - echo ''; - echo ''; - echo ''; - echo ''; - } - } - } -}); diff --git a/app/code/Magento/Eav/Model/Attribute.php b/app/code/Magento/Eav/Model/Attribute.php index 2ddb8adb3bddb..c8253ca5a2c85 100644 --- a/app/code/Magento/Eav/Model/Attribute.php +++ b/app/code/Magento/Eav/Model/Attribute.php @@ -103,7 +103,7 @@ public function getValidateRules() if (is_array($rules)) { return $rules; } elseif (!empty($rules)) { - return $this->getSerializer()->unserialize($rules); + return (array)$this->getSerializer()->unserialize($rules); } return []; } From 4cacb25432345a176c51157660aa9ecdc5199115 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Mon, 10 Apr 2017 17:31:24 +0300 Subject: [PATCH 11/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Customer/Model/AttributeMetadataConverter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/AttributeMetadataConverter.php b/app/code/Magento/Customer/Model/AttributeMetadataConverter.php index 046ee00fa3c85..44d104659e069 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataConverter.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataConverter.php @@ -87,7 +87,7 @@ public function createMetadataAttribute($attribute) } } $validationRules = []; - foreach ($attribute->getValidateRules() as $name => $value) { + foreach ((array)$attribute->getValidateRules() as $name => $value) { $validationRule = $this->validationRuleFactory->create() ->setName($name) ->setValue($value); From 4545b0a5f0acbebe4e244bb8d432110f47e8be6e Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 11 Apr 2017 20:24:35 +0300 Subject: [PATCH 12/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 7e6bc734697b4..9f8d45f50b4b1 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -726,7 +726,9 @@ private function createAttributeByAttributeCode($entityType, $attributeCode) } $entity = $entityType->getEntity(); - if ($entity && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes())) { + if ($entity instanceof \Magento\Eav\Model\Entity\AbstractEntity + && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes(), true) + ) { $attribute->setBackendType( AbstractAttribute::TYPE_STATIC )->setIsGlobal( From 0e30adc697cd5766211b2a563d129c5c18d6d220 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 11 Apr 2017 20:59:15 +0300 Subject: [PATCH 13/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 9f8d45f50b4b1..98de0158681b8 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -726,14 +726,10 @@ private function createAttributeByAttributeCode($entityType, $attributeCode) } $entity = $entityType->getEntity(); - if ($entity instanceof \Magento\Eav\Model\Entity\AbstractEntity + if ($entity instanceof \Magento\Eav\Model\ResourceModel\Attribute\DefaultEntityAttributes\ProviderInterface && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes(), true) ) { - $attribute->setBackendType( - AbstractAttribute::TYPE_STATIC - )->setIsGlobal( - 1 - ); + $attribute->setBackendType(AbstractAttribute::TYPE_STATIC)->setIsGlobal(1); } $attribute->setEntityType($entityType)->setEntityTypeId($entityType->getId()); return $attribute; From 3fd6a91926b83724b9f380d32809ca7bdc5d7a38 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 11 Apr 2017 23:14:41 +0300 Subject: [PATCH 14/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php | 2 +- app/code/Magento/Eav/Model/Entity/AttributeLoader.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index 58c0cec7979a9..5299f0a8a1d36 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -515,7 +515,7 @@ public function setEntity($entity) public function getEntity() { if (!$this->_entity) { - throw new \RuntimeException('Entity does not set'); + $this->_entity = $this->getEntityType()->getEntity(); } return $this->_entity; diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index da1c4573889e0..65667af3daa26 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -62,7 +62,7 @@ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = /** * Check and init default attributes */ - $defaultAttributesCodes = array_intersect($resource->getDefaultAttributes(), $attributeCodes); + $defaultAttributesCodes = array_diff($resource->getDefaultAttributes(), $attributeCodes); foreach ($defaultAttributesCodes as $attributeCode) { $resource->addAttribute($this->_getDefaultAttribute($resource, $attributeCode)); } From 7e56e44603bc21a0cf351d1c03331592b97446fd Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 12 Apr 2017 17:28:41 +0300 Subject: [PATCH 15/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Model/Product/Gallery/ProcessorTest.php | 4 ++-- .../Test/Unit/Model/Product/TypeTest.php | 4 ++-- app/code/Magento/Eav/Model/Config.php | 4 +--- .../Unit/Model/Plugin/ConfigurableTest.php | 21 ++++++------------- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php index 1d437f78d89f1..bcc4df7b0144c 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php @@ -165,7 +165,7 @@ public function testValidate($value) $attributeCode = 'attr_code'; $attribute = $this->getMock( \Magento\Eav\Model\Entity\Attribute::class, - ['getAttributeCode', 'getIsRequired', 'isValueEmpty', 'getIsUnique', 'getEntityType', '__wakeup'], + ['getAttributeCode', 'getIsRequired', 'isValueEmpty', 'getIsUnique', 'getEntity', '__wakeup'], [], '', false @@ -178,7 +178,7 @@ public function testValidate($value) $attribute->expects($this->any())->method('getIsRequired')->will($this->returnValue(true)); $attribute->expects($this->any())->method('isValueEmpty')->will($this->returnValue($value)); $attribute->expects($this->any())->method('getIsUnique')->will($this->returnValue(true)); - $attribute->expects($this->any())->method('getEntityType')->will($this->returnValue($attributeEntity)); + $attribute->expects($this->any())->method('getEntity')->will($this->returnValue($attributeEntity)); $attributeEntity->expects($this->any())->method('checkAttributeUniqueValue')->will($this->returnValue(true)); $this->attributeRepository->expects($this->once()) diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php index 15b9c0f3c5457..81004b956514b 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php @@ -153,9 +153,9 @@ function ($value) { $this->product->expects($this->any())->method('setLinksExist')->with($this->equalTo(false)); $this->product->expects($this->any())->method('canAffectOptions')->with($this->equalTo(true)); - $eavConfigMock = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityAttributeCodes'], [], '', false); + $eavConfigMock = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityAttributes'], [], '', false); $eavConfigMock->expects($this->any()) - ->method('getEntityAttributeCodes') + ->method('getEntityAttributes') ->with($this->equalTo($entityTypeMock), $this->equalTo($this->product)) ->will($this->returnValue([])); diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 98de0158681b8..f10ddfc4d835a 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -578,7 +578,6 @@ public function getEntityAttributeCodes($entityType, $object = null) return $attributes; } - /** * Get all entity type attributes * @@ -606,8 +605,7 @@ public function getEntityAttributes($entityType, $object = null) $attributeSetId )->addStoreLabel( $storeId - ) - ->getData(); + )->getData(); foreach ($attributesInfo as $attributeData) { $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); diff --git a/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php b/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php index a41f728b1698b..d354f07ea4962 100644 --- a/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php @@ -45,9 +45,11 @@ protected function setUp() public function testAfterGetUsedProductCollection() { + $product = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class)->getMock(); + $subject = $this->getMock( \Magento\ConfigurableProduct\Model\Product\Type\Configurable::class, - [], + ['getUsedProductAttributes'], [], '', false @@ -60,22 +62,11 @@ public function testAfterGetUsedProductCollection() false ); - $collectionEntity = $this->getMock( - \Magento\Eav\Model\Entity\Collection\AbstractCollection::class, - ['getType'], - [], - '', - false - ); - $collectionEntity->expects($this->once())->method('getType')->willReturn('catalog'); - $result->expects($this->once())->method('getEntity')->willReturn($collectionEntity); - $attribute = $this->getMock(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, [], [], '', false); - $this->eavConfig->expects($this->once())->method('getEntityAttributeCodes')->with('catalog') - ->willReturn(['size', 'color', 'swatch1']); + $subject->expects($this->once())->method('getUsedProductAttributes')->with($product) + ->willReturn(['size' => $attribute, 'color' => $attribute, 'swatch1' => $attribute]); - $this->eavConfig->expects($this->exactly(3))->method('getAttribute')->willReturn($attribute); $attribute->expects($this->any()) ->method('getData') ->with('additional_data') @@ -85,7 +76,7 @@ public function testAfterGetUsedProductCollection() $result->expects($this->once())->method('addAttributeToSelect') ->with($this->identicalTo(['image', 'size', 'color', 'swatch1']))->willReturn($result); - $result = $this->pluginModel->afterGetUsedProductCollection($subject, $result); + $result = $this->pluginModel->afterGetUsedProductCollection($subject, $result, $product); $this->assertInstanceOf( \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection::class, $result From 3db8bd9634ab146730a00382297ac80d4aab6a95 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 12 Apr 2017 21:59:41 +0300 Subject: [PATCH 16/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Model/Product/Type/AbstractType.php | 2 +- app/code/Magento/Eav/Model/Config.php | 83 ++++++++----------- .../Eav/Model/Entity/AttributeLoader.php | 2 +- .../Eav/Test/Unit/Model/ConfigTest.php | 10 +-- .../Unit/Model/Entity/AttributeLoaderTest.php | 62 +++++--------- 5 files changed, 65 insertions(+), 94 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php index 1d3e4a2d9e6f4..fa38fe82d0473 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php +++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php @@ -723,7 +723,7 @@ public function save($product) protected function _removeNotApplicableAttributes($product) { $entityType = $product->getResource()->getEntityType(); - foreach ($this->_eavConfig->getEntityAttributes($entityType, $product) as $attributeCode => $attribute) { + foreach ($this->_eavConfig->getEntityAttributes($entityType, $product) as $attribute) { $applyTo = $attribute->getApplyTo(); if (is_array($applyTo) && count($applyTo) > 0 && !in_array($product->getTypeId(), $applyTo)) { $product->unsetData($attribute->getAttributeCode()); diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index f10ddfc4d835a..8be3f7359903d 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -543,6 +543,19 @@ private function createAttribute($model) * @SuppressWarnings(PHPMD.NPathComplexity) */ public function getEntityAttributeCodes($entityType, $object = null) + { + $attributes = array_keys($this->getEntityAttributes($entityType, $object)); + return $attributes; + } + + /** + * Get all entity type attributes + * + * @param int|string|Type $entityType + * @param \Magento\Framework\DataObject|null $object + * @return AbstractAttribute[] + */ + public function getEntityAttributes($entityType, $object = null) { $entityType = $this->getEntityType($entityType); $attributeSetId = 0; @@ -556,17 +569,31 @@ public function getEntityAttributeCodes($entityType, $object = null) return $this->_attributeCodes[$cacheKey]; } - if ($this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey))) { - $this->_attributeCodes[$cacheKey] = $this->serializer->unserialize($attributes); - return $this->_attributeCodes[$cacheKey]; - } + $attributeData = $this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey)) + ? $this->serializer->unserialize($attributes) + : null; - $attributes = array_keys($this->getEntityAttributes($entityType, $object)); - $this->_attributeCodes[$cacheKey] = $attributes; + $attributes = []; + if ($attributeData === null) { + if ($attributeSetId) { + $attributesData = $this->_universalFactory->create( + $entityType->getEntityAttributeCollection() + )->setEntityTypeFilter( + $entityType + )->setAttributeSetFilter( + $attributeSetId + )->addStoreLabel( + $storeId + )->getData(); + } else { + $this->_initAttributes($entityType); + $attributesData = $this->_attributeData[$entityType->getEntityTypeCode()]; + } + } if ($this->isCacheEnabled()) { $this->_cache->save( - $this->serializer->serialize($attributes), + $this->serializer->serialize($attributesData), $cacheKey, [ \Magento\Eav\Model\Cache\Type::CACHE_TAG, @@ -575,48 +602,10 @@ public function getEntityAttributeCodes($entityType, $object = null) ); } - return $attributes; - } - - /** - * Get all entity type attributes - * - * @param int|string|Type $entityType - * @param \Magento\Framework\DataObject|null $object - * @return AbstractAttribute[] - */ - public function getEntityAttributes($entityType, $object = null) - { - $entityType = $this->getEntityType($entityType); - $attributeSetId = 0; - $storeId = 0; - if ($object instanceof \Magento\Framework\DataObject) { - $attributeSetId = $object->getAttributeSetId() ?: $attributeSetId; - $storeId = $object->getStoreId() ?: $storeId; + foreach ($attributesData as $attributeData) { + $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); } - $attributes = []; - if ($attributeSetId) { - $attributesInfo = $this->_universalFactory->create( - $entityType->getEntityAttributeCollection() - )->setEntityTypeFilter( - $entityType - )->setAttributeSetFilter( - $attributeSetId - )->addStoreLabel( - $storeId - )->getData(); - - foreach ($attributesInfo as $attributeData) { - $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); - } - } else { - $this->_initAttributes($entityType); - $attributesData = $this->_attributeData[$entityType->getEntityTypeCode()]; - foreach ($attributesData as $attributeData) { - $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); - } - } return $attributes; } diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index 65667af3daa26..bf6e2a3afdffb 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -57,7 +57,7 @@ public function __construct( */ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = null) { - $attributes = $this->config->getEntityAttributes($resource->getEntityType(), $object); + $attributes = (array)$this->config->getEntityAttributes($resource->getEntityType(), $object); $attributeCodes = array_keys($attributes); /** * Check and init default attributes diff --git a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php index f3336b5496357..ef5b7137e8c5b 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php @@ -113,14 +113,14 @@ public function testGetAttributeCache($cacheEnabled, $loadCalls, $unserializeCal ->method('getData') ->willReturn([$attributeData]); $entityAttributeMock = $this->getMockBuilder(Attribute::class) - ->setMethods(['setData', 'load', 'toArray']) + ->setMethods(['setData', 'loadByCode', 'toArray']) ->disableOriginalConstructor() ->getMock(); - $entityAttributeMock->method('setData') + $entityAttributeMock->expects($this->atLeastOnce())->method('setData') ->willReturnSelf(); - $entityAttributeMock->method('load') + $entityAttributeMock->expects($this->atLeastOnce())->method('loadByCode') ->willReturnSelf(); - $entityAttributeMock->method('toArray') + $entityAttributeMock->expects($this->atLeastOnce())->method('toArray') ->willReturn($attributeData); $factoryCalls = [ [ @@ -180,7 +180,7 @@ public function testGetAttributeCache($cacheEnabled, $loadCalls, $unserializeCal ->method('create') ->will($this->returnValueMap($factoryCalls)); - $this->assertEquals($entityAttributeMock, $this->config->getAttribute($entityType, 'attribute_code_1')); + $this->assertInstanceOf(Attribute::class, $this->config->getAttribute($entityType, 'attribute_code_1')); } /** diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php index 6ba0c3aa6bb01..4deb3a576ecef 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php @@ -55,26 +55,19 @@ protected function setUp() public function testLoadAllAttributes() { - $attributeCodes = ['foo']; $defaultAttributes = ['bar']; - $attributeModel = Attribute::class; $entityTypeId = 1; $dataObject = new DataObject(); $this->entityMock->expects($this->any()) ->method('getEntityType') ->willReturn($this->entityTypeMock); - $this->configMock->expects($this->once()) - ->method('getEntityAttributeCodes') - ->willReturn($attributeCodes, $dataObject); + $this->entityMock->expects($this->once()) ->method('getDefaultAttributes') ->willReturn($defaultAttributes); $this->entityTypeMock->expects($this->any()) ->method('getId') ->willReturn($entityTypeId); - $this->entityTypeMock->expects($this->once()) - ->method('getAttributeModel') - ->willReturn($attributeModel); $attributeMock = $this->getMock( \Magento\Eav\Model\Attribute::class, [ @@ -88,58 +81,47 @@ public function testLoadAllAttributes() '', false ); - $this->objectManagerMock->expects($this->once()) - ->method('create') - ->with($attributeModel) - ->willReturn($attributeMock); - $attributeMock->expects($this->once()) - ->method('setAttributeCode') - ->with($defaultAttributes[0]) - ->willReturnSelf(); - $attributeMock->expects($this->once()) - ->method('setBackendType') - ->with(AbstractAttribute::TYPE_STATIC) - ->willReturnSelf(); - $attributeMock->expects($this->once()) - ->method('setIsGlobal') - ->with(1) - ->willReturnSelf(); - $attributeMock->expects($this->once()) - ->method('setEntityType') - ->with($this->entityTypeMock) - ->willReturnSelf(); - $attributeMock->expects($this->once()) - ->method('setEntityTypeId') - ->with($entityTypeId) - ->willReturnSelf(); + $this->configMock->expects($this->once()) + ->method('getEntityAttributes') + ->willReturn(['bar' => $attributeMock]); $this->entityMock->expects($this->once()) ->method('addAttribute') ->with($attributeMock); - $this->entityMock->expects($this->once()) - ->method('getAttribute') - ->with($attributeCodes[0]); $this->attributeLoader->loadAllAttributes($this->entityMock, $dataObject); } public function testLoadAllAttributesAttributeCodesPresentInDefaultAttributes() { - $attributeCodes = ['bar']; + $attributeMock = $this->getMock( + \Magento\Eav\Model\Attribute::class, + [ + 'setAttributeCode', + 'setBackendType', + 'setIsGlobal', + 'setEntityType', + 'setEntityTypeId' + ], + [], + '', + false + ); + $attributeCodes = ['bar'=>$attributeMock]; $defaultAttributes = ['bar']; $dataObject = new DataObject(); $this->entityMock->expects($this->any()) ->method('getEntityType') ->willReturn($this->entityTypeMock); $this->configMock->expects($this->once()) - ->method('getEntityAttributeCodes') + ->method('getEntityAttributes') ->willReturn($attributeCodes, $dataObject); $this->entityMock->expects($this->once()) ->method('getDefaultAttributes') ->willReturn($defaultAttributes); + $this->entityMock->expects($this->atLeastOnce()) + ->method('addAttribute')->with($attributeMock); + $this->objectManagerMock->expects($this->never()) ->method('create'); - $this->entityMock->expects($this->once()) - ->method('getAttribute') - ->with($attributeCodes[0]); $this->attributeLoader->loadAllAttributes($this->entityMock, $dataObject); } } From a829e07845d5cbb2c281697268915b94db30c0e8 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 12 Apr 2017 22:07:05 +0300 Subject: [PATCH 17/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 8be3f7359903d..7e6cedbf5671c 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -565,17 +565,14 @@ public function getEntityAttributes($entityType, $object = null) $storeId = $object->getStoreId() ?: $storeId; } $cacheKey = self::ATTRIBUTES_CODES_CACHE_ID . $entityType->getId() . '-' . $storeId . '-' . $attributeSetId; - if (isset($this->_attributeCodes[$cacheKey])) { - return $this->_attributeCodes[$cacheKey]; - } - $attributeData = $this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey)) + $attributesData = $this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey)) ? $this->serializer->unserialize($attributes) : null; $attributes = []; - if ($attributeData === null) { + if ($attributesData === null) { if ($attributeSetId) { $attributesData = $this->_universalFactory->create( $entityType->getEntityAttributeCollection() From 679a21cec436c681dd0d3997766fe14152795ef7 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 18 Apr 2017 18:39:19 +0300 Subject: [PATCH 18/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Catalog/Model/ResourceModel/Attribute.php | 2 +- app/code/Magento/Eav/Model/Config.php | 18 ++---------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php index 964c99b301259..bdb3cdab617ac 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php @@ -142,7 +142,7 @@ public function deleteEntity(\Magento\Framework\Model\AbstractModel $object) ->getLinkField(); $select = $this->getConnection()->select()->from( - $attribute->getEntityType()->getEntityTable(), + $attribute->getEntity()->getEntityTable(), $linkField )->where( 'attribute_set_id = ?', diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 7e6cedbf5671c..25d793e9cbf26 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -410,7 +410,7 @@ public function getEntityType($code) /** * Initialize all attributes for entity type * - * @param string $entityType + * @param string $entityType * @return $this */ protected function _initAttributes($entityType) @@ -466,21 +466,7 @@ protected function _initAttributes($entityType) */ public function getAttributes($entityType) { - $this->_initAttributes($entityType); - - $entityTypeCode = $this->getEntityType($entityType)->getEntityTypeCode(); - - $attributes = $this->loadAttributes($entityTypeCode); - if (!$attributes) { - $attributeCodes = $this->getEntityAttributeCodes($entityTypeCode); - foreach ($attributeCodes as $code) { - $attribute = $this->createAttributeByAttributeCode($entityType, $code); - $this->_addAttributeReference($code, $code, $entityTypeCode); - $this->saveAttribute($attribute, $entityTypeCode, $code); - } - $attributes = $this->loadAttributes($entityTypeCode); - } - return $attributes; + return $this->getEntityAttributes($entityType); } /** From 7f90628818a4c65a1f7a09c499d4ea63dcd3f205 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 19 Apr 2017 17:37:08 +0300 Subject: [PATCH 19/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 25d793e9cbf26..dc48ccda6d9fa 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -441,6 +441,7 @@ protected function _initAttributes($entityType) } // attributes should be reloaded via model to be processed by custom resource model $attributeObject = $this->_createAttribute($entityType, $attribute); + $this->saveAttribute($attribute, $entityTypeCode, $attribute->getAttributeCode()); $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attributeObject->toArray(); } if ($this->isCacheEnabled()) { @@ -482,9 +483,14 @@ public function getAttribute($entityType, $code) if ($code instanceof \Magento\Eav\Model\Entity\Attribute\AttributeInterface) { return $code; } + \Magento\Framework\Profiler::start('EAV: ' . __METHOD__, ['group' => 'EAV', 'method' => __METHOD__]); $entityTypeCode = $this->getEntityType($entityType)->getEntityTypeCode(); + if (isset($this->attributes[$entityTypeCode][$code])) { + return $this->attributes[$entityTypeCode][$code]; + } + if (is_numeric($code)) { // if code is numeric, try to map attribute id to code $code = $this->_getAttributeReference($code, $entityTypeCode) ?: $code; } @@ -550,7 +556,7 @@ public function getEntityAttributes($entityType, $object = null) $attributeSetId = $object->getAttributeSetId() ?: $attributeSetId; $storeId = $object->getStoreId() ?: $storeId; } - $cacheKey = self::ATTRIBUTES_CODES_CACHE_ID . $entityType->getId() . '-' . $storeId . '-' . $attributeSetId; + $cacheKey = self::ATTRIBUTES_CACHE_ID . '-' . $entityType->getId() . '-' . $storeId . '-' . $attributeSetId; $attributesData = $this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey)) ? $this->serializer->unserialize($attributes) From 3d645155b3f19b4f47e883fc5bfd9aaefa344dff Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 19 Apr 2017 17:50:44 +0300 Subject: [PATCH 20/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index dc48ccda6d9fa..d0368e5912fa6 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -441,7 +441,7 @@ protected function _initAttributes($entityType) } // attributes should be reloaded via model to be processed by custom resource model $attributeObject = $this->_createAttribute($entityType, $attribute); - $this->saveAttribute($attribute, $entityTypeCode, $attribute->getAttributeCode()); + $this->saveAttribute($attributeObject, $entityTypeCode, $attributeObject->getAttributeCode()); $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attributeObject->toArray(); } if ($this->isCacheEnabled()) { From 868de8edb0c98ea312bb70070e55749d9b0f156a Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Thu, 20 Apr 2017 15:36:02 +0300 Subject: [PATCH 21/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index d0368e5912fa6..fbc17a2df9e0b 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -462,6 +462,9 @@ protected function _initAttributes($entityType) /** * Get attributes by entity type * + * @deprecated + * @see \Magento\Eav\Model\Config::getEntityAttributes + * * @param string $entityType * @return AbstractAttribute[] */ @@ -528,6 +531,9 @@ private function createAttribute($model) /** * Get codes of all entity type attributes * + * @deprecated + * @see \Magento\Eav\Model\Config::getEntityAttributes + * * @param mixed $entityType * @param \Magento\Framework\DataObject $object * @return array @@ -540,6 +546,8 @@ public function getEntityAttributeCodes($entityType, $object = null) return $attributes; } + private $attributesPerSet = []; + /** * Get all entity type attributes * @@ -558,6 +566,11 @@ public function getEntityAttributes($entityType, $object = null) } $cacheKey = self::ATTRIBUTES_CACHE_ID . '-' . $entityType->getId() . '-' . $storeId . '-' . $attributeSetId; + + if (isset($this->attributesPerSet[$cacheKey])) { + return $this->attributesPerSet[$cacheKey]; + } + $attributesData = $this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey)) ? $this->serializer->unserialize($attributes) : null; @@ -595,6 +608,8 @@ public function getEntityAttributes($entityType, $object = null) $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData); } + $this->attributesPerSet[$cacheKey] = $attributes; + return $attributes; } From 67c272bd606ffd7d366cb463cf86598e6f891fd3 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Thu, 20 Apr 2017 15:57:14 +0300 Subject: [PATCH 22/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index fbc17a2df9e0b..4504407add9ab 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -165,6 +165,7 @@ public function clear() $this->attributes = null; $this->_references = null; $this->_attributeCodes = null; + $this->attributesPerSet = []; $this->_cache->clean( [ \Magento\Eav\Model\Cache\Type::CACHE_TAG, From e04f7327628249c7d21c369628ee283cbb8177ab Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 21 Apr 2017 17:53:30 +0300 Subject: [PATCH 23/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 30 +++++++++++-------- .../Eav/Model/Entity/AbstractEntity.php | 1 - 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 4504407add9ab..d3f57156abbfa 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -116,6 +116,13 @@ class Config */ private $serializer; + /** + * Cache of attributes per set + * + * @var array + */ + private $attributesPerSet = []; + /** * @param \Magento\Framework\App\CacheInterface $cache * @param \Magento\Eav\Model\Entity\TypeFactory $entityTypeFactory @@ -547,8 +554,6 @@ public function getEntityAttributeCodes($entityType, $object = null) return $attributes; } - private $attributesPerSet = []; - /** * Get all entity type attributes * @@ -593,16 +598,17 @@ public function getEntityAttributes($entityType, $object = null) $this->_initAttributes($entityType); $attributesData = $this->_attributeData[$entityType->getEntityTypeCode()]; } - } - if ($this->isCacheEnabled()) { - $this->_cache->save( - $this->serializer->serialize($attributesData), - $cacheKey, - [ - \Magento\Eav\Model\Cache\Type::CACHE_TAG, - \Magento\Eav\Model\Entity\Attribute::CACHE_TAG - ] - ); + + if ($this->isCacheEnabled()) { + $this->_cache->save( + $this->serializer->serialize($attributesData), + $cacheKey, + [ + \Magento\Eav\Model\Cache\Type::CACHE_TAG, + \Magento\Eav\Model\Entity\Attribute::CACHE_TAG + ] + ); + } } foreach ($attributesData as $attributeData) { diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 192e4acafe93a..aaa1e0787b9e1 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -455,7 +455,6 @@ public function getAttribute($attribute) */ public function addAttribute(AbstractAttribute $attribute) { - $attribute = $attribute; //we change state of attribute, so lets make copy $attribute->setEntity($this); $attributeCode = $attribute->getAttributeCode(); From 61dd46921c8d1355fa463a58f86753770a89d961 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Fri, 21 Apr 2017 19:14:02 +0300 Subject: [PATCH 24/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index d3f57156abbfa..5a76d820c0104 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -498,14 +498,14 @@ public function getAttribute($entityType, $code) \Magento\Framework\Profiler::start('EAV: ' . __METHOD__, ['group' => 'EAV', 'method' => __METHOD__]); $entityTypeCode = $this->getEntityType($entityType)->getEntityTypeCode(); - if (isset($this->attributes[$entityTypeCode][$code])) { - return $this->attributes[$entityTypeCode][$code]; - } - if (is_numeric($code)) { // if code is numeric, try to map attribute id to code $code = $this->_getAttributeReference($code, $entityTypeCode) ?: $code; } + if (isset($this->attributes[$entityTypeCode][$code])) { + return $this->attributes[$entityTypeCode][$code]; + } + $attributes = $this->loadAttributes($entityTypeCode); $attribute = isset($attributes[$code]) ? $attributes[$code] : null; if (!$attribute) { From dd93eabd2ed78f52cd87a0800bdd4a3666cdfbba Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 25 Apr 2017 11:12:18 +0300 Subject: [PATCH 25/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Catalog/Model/ProductRepository.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 843549bb2671a..d495dff36e1c0 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -679,9 +679,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr $collection = $this->collectionFactory->create(); $this->extensionAttributesJoinProcessor->process($collection); - foreach ($this->metadataService->getList($this->searchCriteriaBuilder->create())->getItems() as $metadata) { - $collection->addAttributeToSelect($metadata->getAttributeCode()); - } + $collection->addAttributeToSelect('*'); $collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner'); $collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner'); From d047fa7291ea35f4a265be4f5116a4961867d5be Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 25 Apr 2017 13:19:58 +0300 Subject: [PATCH 26/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Customer/Model/Attribute/Data/Postcode.php | 2 +- app/code/Magento/Eav/Model/Attribute/Data/Date.php | 6 +++++- app/code/Magento/Eav/Model/Attribute/Data/File.php | 2 +- app/code/Magento/Eav/Model/Attribute/Data/Multiline.php | 4 +++- app/code/Magento/Eav/Model/Attribute/Data/Select.php | 2 +- app/code/Magento/Eav/Model/Attribute/Data/Text.php | 5 ++++- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php b/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php index 222a513dd927a..380b8a4d3446f 100644 --- a/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php +++ b/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php @@ -49,7 +49,6 @@ public function __construct( public function validateValue($value) { $attribute = $this->getAttribute(); - $label = __($attribute->getStoreLabel()); $countryId = $this->getExtractedData('country_id'); if ($this->directoryHelper->isZipCodeOptional($countryId)) { @@ -58,6 +57,7 @@ public function validateValue($value) $errors = []; if (empty($value) && $value !== '0') { + $label = __($attribute->getStoreLabel()); $errors[] = __('"%1" is a required value.', $label); } if (count($errors) == 0) { diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Date.php b/app/code/Magento/Eav/Model/Attribute/Data/Date.php index df7250b6bdbf8..be15b040955cd 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Date.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Date.php @@ -39,7 +39,7 @@ public function validateValue($value) { $errors = []; $attribute = $this->getAttribute(); - $label = $attribute->getStoreLabel(); + if ($value === false) { // try to load original value and validate it @@ -47,6 +47,7 @@ public function validateValue($value) } if ($attribute->getIsRequired() && empty($value)) { + $label = __($attribute->getStoreLabel()); $errors[] = __('"%1" is a required value.', $label); } @@ -68,6 +69,7 @@ public function validateValue($value) ) > $validateRules['date_range_max'] ) { if (!empty($validateRules['date_range_min']) && !empty($validateRules['date_range_max'])) { + $label = __($attribute->getStoreLabel()); $errors[] = __( 'Please enter a valid date between %1 and %2 at %3.', date('d/m/Y', $validateRules['date_range_min']), @@ -75,12 +77,14 @@ public function validateValue($value) $label ); } elseif (!empty($validateRules['date_range_min'])) { + $label = __($attribute->getStoreLabel()); $errors[] = __( 'Please enter a valid date equal to or greater than %1 at %2.', date('d/m/Y', $validateRules['date_range_min']), $label ); } elseif (!empty($validateRules['date_range_max'])) { + $label = __($attribute->getStoreLabel()); $errors[] = __( 'Please enter a valid date less than or equal to %1 at %2.', date('d/m/Y', $validateRules['date_range_max']), diff --git a/app/code/Magento/Eav/Model/Attribute/Data/File.php b/app/code/Magento/Eav/Model/Attribute/Data/File.php index 44cdcf30a3a55..24c4e53ea1f71 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/File.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/File.php @@ -176,7 +176,6 @@ public function validateValue($value) $errors = []; $attribute = $this->getAttribute(); - $label = $attribute->getStoreLabel(); $toDelete = !empty($value['delete']) ? true : false; $toUpload = !empty($value['tmp_name']) ? true : false; @@ -190,6 +189,7 @@ public function validateValue($value) } if ($attribute->getIsRequired() && !$toUpload) { + $label = __($attribute->getStoreLabel()); $errors[] = __('"%1" is a required value.', $label); } diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Multiline.php b/app/code/Magento/Eav/Model/Attribute/Data/Multiline.php index c365facacbef2..0eaa98c93067c 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Multiline.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Multiline.php @@ -43,13 +43,15 @@ public function validateValue($value) $errors = []; $lines = $this->processValue($value); $attribute = $this->getAttribute(); - $attributeLabel = __($attribute->getStoreLabel()); + if ($attribute->getIsRequired() && empty($lines)) { + $attributeLabel = __($attribute->getStoreLabel()); $errors[] = __('"%1" is a required value.', $attributeLabel); } $maxAllowedLineCount = $attribute->getMultilineCount(); if (count($lines) > $maxAllowedLineCount) { + $attributeLabel = __($attribute->getStoreLabel()); $errors[] = __('"%1" cannot contain more than %2 lines.', $attributeLabel, $maxAllowedLineCount); } diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Select.php b/app/code/Magento/Eav/Model/Attribute/Data/Select.php index e714eaa78d5ea..92aa09e7ccac6 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Select.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Select.php @@ -36,7 +36,6 @@ public function validateValue($value) { $errors = []; $attribute = $this->getAttribute(); - $label = __($attribute->getStoreLabel()); if ($value === false) { // try to load original value and validate it @@ -44,6 +43,7 @@ public function validateValue($value) } if ($attribute->getIsRequired() && empty($value) && $value != '0') { + $label = __($attribute->getStoreLabel()); $errors[] = __('"%1" is a required value.', $label); } diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Text.php b/app/code/Magento/Eav/Model/Attribute/Data/Text.php index fb2b0e1d06912..1403081f1ecb9 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Text.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Text.php @@ -61,7 +61,7 @@ public function validateValue($value) { $errors = []; $attribute = $this->getAttribute(); - $label = __($attribute->getStoreLabel()); + if ($value === false) { // try to load original value and validate it @@ -69,6 +69,7 @@ public function validateValue($value) } if ($attribute->getIsRequired() && empty($value) && $value !== '0') { + $label = __($attribute->getStoreLabel()); $errors[] = __('"%1" is a required value.', $label); } @@ -81,10 +82,12 @@ public function validateValue($value) $validateRules = $attribute->getValidateRules(); if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) { + $label = __($attribute->getStoreLabel()); $v = $validateRules['min_text_length']; $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $v); } if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) { + $label = __($attribute->getStoreLabel()); $v = $validateRules['max_text_length']; $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $v); } From 6b8d584ed3135a423eeb963b19524fe98b64c0e2 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Tue, 25 Apr 2017 16:15:08 +0300 Subject: [PATCH 27/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Attribute/Data/AbstractData.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Attribute/Data/AbstractData.php b/app/code/Magento/Eav/Model/Attribute/Data/AbstractData.php index aa569b35db9aa..3c28fa9afb299 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/AbstractData.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/AbstractData.php @@ -306,10 +306,10 @@ protected function _validateInputRule($value) return true; } - $label = $this->getAttribute()->getStoreLabel(); $validateRules = $this->getAttribute()->getValidateRules(); if (!empty($validateRules['input_validation'])) { + $label = $this->getAttribute()->getStoreLabel(); switch ($validateRules['input_validation']) { case 'alphanumeric': $validator = new \Zend_Validate_Alnum(true); From e64cc13aa8c418640c816a617f9025c95825ede7 Mon Sep 17 00:00:00 2001 From: Michail Slabko Date: Wed, 26 Apr 2017 14:34:16 +0300 Subject: [PATCH 28/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Model/ResourceModel/Entity/Attribute.php | 26 +++++++---- app/code/Magento/Swatches/Helper/Data.php | 43 +++++++++++-------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute.php b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute.php index 7a9ee184f872c..e7f41c21f05d2 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute.php +++ b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute.php @@ -662,6 +662,11 @@ protected function _afterLoad(AbstractModel $object) return $this; } + /** + * @var array + */ + private $storeLabelsCache = []; + /** * Retrieve store labels by given attribute id * @@ -670,16 +675,19 @@ protected function _afterLoad(AbstractModel $object) */ public function getStoreLabelsByAttributeId($attributeId) { - $connection = $this->getConnection(); - $bind = [':attribute_id' => $attributeId]; - $select = $connection->select()->from( - $this->getTable('eav_attribute_label'), - ['store_id', 'value'] - )->where( - 'attribute_id = :attribute_id' - ); + if (!isset($this->storeLabelsCache[$attributeId])) { + $connection = $this->getConnection(); + $bind = [':attribute_id' => $attributeId]; + $select = $connection->select()->from( + $this->getTable('eav_attribute_label'), + ['store_id', 'value'] + )->where( + 'attribute_id = :attribute_id' + ); + $this->storeLabelsCache[$attributeId] = $connection->fetchPairs($select, $bind); + } - return $connection->fetchPairs($select, $bind); + return $this->storeLabelsCache[$attributeId]; } /** diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index 143492ec76e41..a5da4eca2d238 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -416,6 +416,11 @@ public function getSwatchAttributesAsArray(Product $product) return $result; } + /** + * @var array + */ + private $swatchesCache = []; + /** * Get swatch options by option id's according to fallback logic * @@ -424,27 +429,31 @@ public function getSwatchAttributesAsArray(Product $product) */ public function getSwatchesByOptionsId(array $optionIds) { - /** @var \Magento\Swatches\Model\ResourceModel\Swatch\Collection $swatchCollection */ - $swatchCollection = $this->swatchCollectionFactory->create(); - $swatchCollection->addFilterByOptionsIds($optionIds); - - $swatches = []; - $currentStoreId = $this->storeManager->getStore()->getId(); - foreach ($swatchCollection as $item) { - if ($item['type'] != Swatch::SWATCH_TYPE_TEXTUAL) { - $swatches[$item['option_id']] = $item->getData(); - } elseif ($item['store_id'] == $currentStoreId && $item['value'] != '') { - $fallbackValues[$item['option_id']][$currentStoreId] = $item->getData(); - } elseif ($item['store_id'] == self::DEFAULT_STORE_ID) { - $fallbackValues[$item['option_id']][self::DEFAULT_STORE_ID] = $item->getData(); + $cacheKey = implode('-', $optionIds); + if (!isset($this->swatchesCache[$cacheKey])) { + /** @var \Magento\Swatches\Model\ResourceModel\Swatch\Collection $swatchCollection */ + $swatchCollection = $this->swatchCollectionFactory->create(); + $swatchCollection->addFilterByOptionsIds($optionIds); + + $swatches = []; + $currentStoreId = $this->storeManager->getStore()->getId(); + foreach ($swatchCollection as $item) { + if ($item['type'] != Swatch::SWATCH_TYPE_TEXTUAL) { + $swatches[$item['option_id']] = $item->getData(); + } elseif ($item['store_id'] == $currentStoreId && $item['value'] != '') { + $fallbackValues[$item['option_id']][$currentStoreId] = $item->getData(); + } elseif ($item['store_id'] == self::DEFAULT_STORE_ID) { + $fallbackValues[$item['option_id']][self::DEFAULT_STORE_ID] = $item->getData(); + } } - } - if (!empty($fallbackValues)) { - $swatches = $this->addFallbackOptions($fallbackValues, $swatches); + if (!empty($fallbackValues)) { + $swatches = $this->addFallbackOptions($fallbackValues, $swatches); + } + $this->swatchesCache[$cacheKey] = $swatches; } - return $swatches; + return $this->swatchesCache[$cacheKey]; } /** From d63a58446a7cdfc7807e544927619a8cc3dcd3e8 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 26 Apr 2017 18:06:49 +0300 Subject: [PATCH 29/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Test/Unit/Model/ProductRepositoryTest.php | 11 ++----- .../Model/Attribute/Data/PostcodeTest.php | 2 +- .../Magento/Eav/Model/Attribute/Data/Date.php | 1 - .../Magento/Eav/Model/Attribute/Data/Text.php | 1 - app/code/Magento/Eav/Model/Config.php | 6 ++-- .../Eav/Test/Unit/Model/ConfigTest.php | 29 +------------------ 6 files changed, 6 insertions(+), 44 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php index 9375cf0b22726..76dcf9a366052 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php @@ -715,7 +715,6 @@ public function testGetList() '', false ); - $extendedSearchCriteriaMock = $this->getMock(\Magento\Framework\Api\SearchCriteria::class, [], [], '', false); $productAttributeSearchResultsMock = $this->getMockBuilder(ProductAttributeInterface::class) ->disableOriginalConstructor() ->setMethods(['getItems']) @@ -729,14 +728,8 @@ public function testGetList() ); $this->collectionFactoryMock->expects($this->once())->method('create')->willReturn($collectionMock); - $this->searchCriteriaBuilderMock->expects($this->once())->method('create') - ->willReturn($extendedSearchCriteriaMock); - $this->metadataServiceMock->expects($this->once())->method('getList')->with($extendedSearchCriteriaMock) - ->willReturn($productAttributeSearchResultsMock); - $productAttributeSearchResultsMock->expects($this->once())->method('getItems') - ->willReturn([$productAttributeMock]); - $productAttributeMock->expects($this->once())->method('getAttributeCode')->willReturn($attributeCode); - $collectionMock->expects($this->once())->method('addAttributeToSelect')->with($attributeCode); + + $collectionMock->expects($this->once())->method('addAttributeToSelect')->with('*'); $collectionMock->expects($this->exactly(2))->method('joinAttribute')->withConsecutive( ['status', 'catalog_product/status', 'entity_id', null, 'inner'], ['visibility', 'catalog_product/visibility', 'entity_id', null, 'inner'] diff --git a/app/code/Magento/Customer/Test/Unit/Model/Attribute/Data/PostcodeTest.php b/app/code/Magento/Customer/Test/Unit/Model/Attribute/Data/PostcodeTest.php index 06b7391ece109..f2f1d7afa7e2a 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Attribute/Data/PostcodeTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Attribute/Data/PostcodeTest.php @@ -64,7 +64,7 @@ protected function setUp() public function testValidateValue($value, $expected, $countryId, $isOptional) { $storeLabel = 'Zip/Postal Code'; - $this->attributeMock->expects($this->once()) + $this->attributeMock->expects($this->any()) ->method('getStoreLabel') ->willReturn($storeLabel); diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Date.php b/app/code/Magento/Eav/Model/Attribute/Data/Date.php index be15b040955cd..a48885925733f 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Date.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Date.php @@ -40,7 +40,6 @@ public function validateValue($value) $errors = []; $attribute = $this->getAttribute(); - if ($value === false) { // try to load original value and validate it $value = $this->getEntity()->getDataUsingMethod($attribute->getAttributeCode()); diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Text.php b/app/code/Magento/Eav/Model/Attribute/Data/Text.php index 1403081f1ecb9..646216a4cc31a 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Text.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Text.php @@ -62,7 +62,6 @@ public function validateValue($value) $errors = []; $attribute = $this->getAttribute(); - if ($value === false) { // try to load original value and validate it $value = $this->getEntity()->getDataUsingMethod($attribute->getAttributeCode()); diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 5a76d820c0104..d30f222b7c76d 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -471,7 +471,7 @@ protected function _initAttributes($entityType) * Get attributes by entity type * * @deprecated - * @see \Magento\Eav\Model\Config::getEntityAttributes + * @see \Magento\Eav\Model\Config::getEntityAttributes * * @param string $entityType * @return AbstractAttribute[] @@ -540,7 +540,7 @@ private function createAttribute($model) * Get codes of all entity type attributes * * @deprecated - * @see \Magento\Eav\Model\Config::getEntityAttributes + * @see \Magento\Eav\Model\Config::getEntityAttributes * * @param mixed $entityType * @param \Magento\Framework\DataObject $object @@ -572,7 +572,6 @@ public function getEntityAttributes($entityType, $object = null) } $cacheKey = self::ATTRIBUTES_CACHE_ID . '-' . $entityType->getId() . '-' . $storeId . '-' . $attributeSetId; - if (isset($this->attributesPerSet[$cacheKey])) { return $this->attributesPerSet[$cacheKey]; } @@ -581,7 +580,6 @@ public function getEntityAttributes($entityType, $object = null) ? $this->serializer->unserialize($attributes) : null; - $attributes = []; if ($attributesData === null) { if ($attributeSetId) { diff --git a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php index ef5b7137e8c5b..03d11e0485145 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php @@ -120,8 +120,7 @@ public function testGetAttributeCache($cacheEnabled, $loadCalls, $unserializeCal ->willReturnSelf(); $entityAttributeMock->expects($this->atLeastOnce())->method('loadByCode') ->willReturnSelf(); - $entityAttributeMock->expects($this->atLeastOnce())->method('toArray') - ->willReturn($attributeData); + $factoryCalls = [ [ Collection::class, @@ -135,22 +134,6 @@ public function testGetAttributeCache($cacheEnabled, $loadCalls, $unserializeCal ], ]; - $this->cacheStateMock - ->expects($this->atLeastOnce()) - ->method('isEnabled') - ->with(Cache::TYPE_IDENTIFIER) - ->willReturn($cacheEnabled); - $this->cacheMock - ->expects($this->exactly($loadCalls)) - ->method('load') - ->with(Config::ATTRIBUTES_CACHE_ID . 'entity_type_code') - ->willReturn($cachedValue); - $this->serializerMock - ->expects($this->exactly($unserializeCalls)) - ->method('unserialize') - ->with($cachedValue) - ->willReturn([$attributeData]); - $entityTypeData = [ 'entity_type_id' => 'entity_type_id', 'entity_type_code' => 'entity_type_code' @@ -265,16 +248,6 @@ public function testGetAttributes($cacheEnabled, $loadCalls, $unserializeCalls, ->method('isEnabled') ->with(Cache::TYPE_IDENTIFIER) ->willReturn($cacheEnabled); - $this->cacheMock - ->expects($this->exactly($loadCalls)) - ->method('load') - ->with(Config::ATTRIBUTES_CACHE_ID . 'entity_type_code') - ->willReturn($cachedValue); - $this->serializerMock - ->expects($this->exactly($unserializeCalls)) - ->method('unserialize') - ->with($cachedValue) - ->willReturn([$attributeData]); $entityTypeData = [ 'entity_type_id' => 'entity_type_id', From dafcb2db65d4cdd31d3f24d1404234c719d18b0c Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Thu, 27 Apr 2017 12:07:58 +0300 Subject: [PATCH 30/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Customer/Model/AttributeMetadataConverter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/AttributeMetadataConverter.php b/app/code/Magento/Customer/Model/AttributeMetadataConverter.php index 44d104659e069..046ee00fa3c85 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataConverter.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataConverter.php @@ -87,7 +87,7 @@ public function createMetadataAttribute($attribute) } } $validationRules = []; - foreach ((array)$attribute->getValidateRules() as $name => $value) { + foreach ($attribute->getValidateRules() as $name => $value) { $validationRule = $this->validationRuleFactory->create() ->setName($name) ->setValue($value); From 13cd3cac65ba3161f53a356e2ac09c12203abe55 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Thu, 27 Apr 2017 14:09:12 +0300 Subject: [PATCH 31/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 5 ++--- app/code/Magento/Eav/Model/Entity/AbstractEntity.php | 8 ++++++-- app/code/Magento/Eav/Model/Entity/AttributeLoader.php | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index d30f222b7c76d..f138c5c66c1b2 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -544,14 +544,13 @@ private function createAttribute($model) * * @param mixed $entityType * @param \Magento\Framework\DataObject $object - * @return array + * @return string[] * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ public function getEntityAttributeCodes($entityType, $object = null) { - $attributes = array_keys($this->getEntityAttributes($entityType, $object)); - return $attributes; + return array_keys($this->getEntityAttributes($entityType, $object)); } /** diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index aaa1e0787b9e1..5653006cdc2c3 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -1186,7 +1186,7 @@ protected function _getOrigObject($object) * * @param array &$delete * @param AbstractAttribute $attribute - * @param \Magento\Eav\Model\Entity\AbstractEntity $object + * @param AbstractEntity $object * @return void */ private function _aggregateDeleteData(&$delete, $attribute, $object) @@ -1920,8 +1920,12 @@ public function afterDelete(\Magento\Framework\DataObject $object) } /** + * Load attributes for object + * if the object will not pass all attributes for this entity type will be loaded + * * @param array $attributes - * @param |null $object + * @param AbstractEntity|null $object + * @return void */ protected function loadAttributesForObject($attributes, $object = null) { diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php index bf6e2a3afdffb..65667af3daa26 100644 --- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php +++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php @@ -57,7 +57,7 @@ public function __construct( */ public function loadAllAttributes(AbstractEntity $resource, DataObject $object = null) { - $attributes = (array)$this->config->getEntityAttributes($resource->getEntityType(), $object); + $attributes = $this->config->getEntityAttributes($resource->getEntityType(), $object); $attributeCodes = array_keys($attributes); /** * Check and init default attributes From badbbb0d2d41838cf109e724757f6f439b76bb79 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 3 May 2017 11:50:24 +0300 Subject: [PATCH 32/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Customer/Model/AttributeMetadataConverter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/AttributeMetadataConverter.php b/app/code/Magento/Customer/Model/AttributeMetadataConverter.php index 046ee00fa3c85..44d104659e069 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataConverter.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataConverter.php @@ -87,7 +87,7 @@ public function createMetadataAttribute($attribute) } } $validationRules = []; - foreach ($attribute->getValidateRules() as $name => $value) { + foreach ((array)$attribute->getValidateRules() as $name => $value) { $validationRule = $this->validationRuleFactory->create() ->setName($name) ->setValue($value); From 1505a440a733ebc4b262d94040612cc37d05ea78 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 3 May 2017 17:11:57 +0300 Subject: [PATCH 33/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- .../Test/Unit/Model/ProductRepositoryTest.php | 12 ------------ app/code/Magento/Eav/Model/Config.php | 9 +++++---- app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php | 12 ++---------- app/code/Magento/Swatches/Helper/Data.php | 1 + 4 files changed, 8 insertions(+), 26 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php index 76dcf9a366052..a0c9f4c6c92e2 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php @@ -707,7 +707,6 @@ public function testDeleteById() public function testGetList() { $searchCriteriaMock = $this->getMock(\Magento\Framework\Api\SearchCriteriaInterface::class, [], [], '', false); - $attributeCode = 'attribute_code'; $collectionMock = $this->getMock( \Magento\Catalog\Model\ResourceModel\Product\Collection::class, [], @@ -715,17 +714,6 @@ public function testGetList() '', false ); - $productAttributeSearchResultsMock = $this->getMockBuilder(ProductAttributeInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getItems']) - ->getMockForAbstractClass(); - $productAttributeMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeInterface::class, - [], - [], - '', - false - ); $this->collectionFactoryMock->expects($this->once())->method('create')->willReturn($collectionMock); diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 2f339eaf3f6b7..8a609296b771f 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -543,11 +543,9 @@ private function createAttribute($model) * @deprecated * @see \Magento\Eav\Model\Config::getEntityAttributes * - * @param mixed $entityType - * @param \Magento\Framework\DataObject $object + * @param mixed $entityType + * @param \Magento\Framework\DataObject $object * @return string[] - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ public function getEntityAttributeCodes($entityType, $object = null) { @@ -560,6 +558,9 @@ public function getEntityAttributeCodes($entityType, $object = null) * @param int|string|Type $entityType * @param \Magento\Framework\DataObject|null $object * @return AbstractAttribute[] + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ public function getEntityAttributes($entityType, $object = null) { diff --git a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php index 03d11e0485145..da2b22143ad49 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php @@ -87,15 +87,7 @@ protected function setUp() ); } - /** - * @param boolean $cacheEnabled - * @param int $loadCalls - * @param int $cachedValue - * @param int $unserializeCalls - * @dataProvider getAttributeCacheDataProvider - * @return void - */ - public function testGetAttributeCache($cacheEnabled, $loadCalls, $unserializeCalls, $cachedValue) + public function testGetAttributeCache() { $attributeData = [ 'attribute_code' => 'attribute_code_1', @@ -201,7 +193,7 @@ public function getAttributeCacheDataProvider() * @dataProvider getAttributeCacheDataProvider * @return void */ - public function testGetAttributes($cacheEnabled, $loadCalls, $unserializeCalls, $cachedValue) + public function testGetAttributes($cacheEnabled) { $attributeData = [ 'attribute_code' => 'attribute_code_1', diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index a5da4eca2d238..5c06f3176e918 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -429,6 +429,7 @@ public function getSwatchAttributesAsArray(Product $product) */ public function getSwatchesByOptionsId(array $optionIds) { + sort($optionIds); $cacheKey = implode('-', $optionIds); if (!isset($this->swatchesCache[$cacheKey])) { /** @var \Magento\Swatches\Model\ResourceModel\Swatch\Collection $swatchCollection */ From 45abb782ecad096486ee4d9174edb20fd113ad0a Mon Sep 17 00:00:00 2001 From: Michail Slabko Date: Wed, 3 May 2017 20:46:00 +0300 Subject: [PATCH 34/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Swatches/Helper/Data.php | 37 +++++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index 5c06f3176e918..c4e7f0e90aa19 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -429,12 +429,13 @@ public function getSwatchAttributesAsArray(Product $product) */ public function getSwatchesByOptionsId(array $optionIds) { - sort($optionIds); - $cacheKey = implode('-', $optionIds); - if (!isset($this->swatchesCache[$cacheKey])) { + $swatches = $this->getCachedSwatches($optionIds); + + if (count($swatches) !== count($optionIds)) { + $swatchOptionIds = array_diff($optionIds, array_keys($swatches)); /** @var \Magento\Swatches\Model\ResourceModel\Swatch\Collection $swatchCollection */ $swatchCollection = $this->swatchCollectionFactory->create(); - $swatchCollection->addFilterByOptionsIds($optionIds); + $swatchCollection->addFilterByOptionsIds($swatchOptionIds); $swatches = []; $currentStoreId = $this->storeManager->getStore()->getId(); @@ -451,10 +452,34 @@ public function getSwatchesByOptionsId(array $optionIds) if (!empty($fallbackValues)) { $swatches = $this->addFallbackOptions($fallbackValues, $swatches); } - $this->swatchesCache[$cacheKey] = $swatches; + $this->setCachedSwatches($swatchOptionIds, $swatches); } - return $this->swatchesCache[$cacheKey]; + return array_filter($this->getCachedSwatches($optionIds)); + } + + /** + * Get cached swatches + * + * @param array $optionIds + * @return array + */ + private function getCachedSwatches(array $optionIds) + { + return array_intersect_key($this->swatchesCache, array_combine($optionIds, $optionIds)); + } + + /** + * Cache swatch. If no swathes found for specific option id - set null for prevent double call + * + * @param array $optionIds + * @param array $swatches + */ + private function setCachedSwatches(array $optionIds, array $swatches) + { + foreach ($optionIds as $optionId) { + $this->swatchesCache[$optionId] = isset($swatches[$optionId]) ? $swatches[$optionId] : null; + } } /** From 21a9516b87f8eafee9160f15c155c93a8dab77a7 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Thu, 4 May 2017 10:06:05 +0300 Subject: [PATCH 35/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Swatches/Helper/Data.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index c4e7f0e90aa19..e3a45c2bd8d0f 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -474,6 +474,7 @@ private function getCachedSwatches(array $optionIds) * * @param array $optionIds * @param array $swatches + * @return void */ private function setCachedSwatches(array $optionIds, array $swatches) { From c67b0e000a4ee487e2ccf37688a2a4673339bf08 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Wed, 10 May 2017 17:10:39 +0300 Subject: [PATCH 36/36] MAGETWO-62691: [Performance] EAV attributes caching optimization --- app/code/Magento/Eav/Model/Config.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php index 8a609296b771f..a1989fcec8c7d 100644 --- a/app/code/Magento/Eav/Model/Config.php +++ b/app/code/Magento/Eav/Model/Config.php @@ -448,7 +448,6 @@ protected function _initAttributes($entityType) if (empty($attribute['attribute_model'])) { $attribute['attribute_model'] = $entityType->getAttributeModel(); } - // attributes should be reloaded via model to be processed by custom resource model $attributeObject = $this->_createAttribute($entityType, $attribute); $this->saveAttribute($attributeObject, $entityTypeCode, $attributeObject->getAttributeCode()); $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attributeObject->toArray();
', $profiler->getTotalElapsedSecs(), 's ','', $profiler->getTotalNumQueries() , 'queries', '', microtime(1) - $_SERVER['REQUEST_TIME_FLOAT'], '
', number_format(1000 * $query->getElapsedSecs(), 2), 'ms', '', $query->getQuery(), '