diff --git a/.all-contributorsrc b/.all-contributorsrc index 66437446208..e2ce8b9ae93 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1373,6 +1373,15 @@ "contributions": [ "code" ] + }, + { + "login": "davidhiendl", + "name": "David Hiendl", + "avatar_url": "https://avatars.githubusercontent.com/u/11006964?v=4", + "profile": "https://github.com/davidhiendl", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index 0ece0a8a413..bf985eaf2af 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-All Contributors +All Contributors Total Downloads License @@ -207,6 +207,7 @@ Do not use 20.x.x if you need IE support. - removed support for `global/sales/old_fields_map` defined in XML ([#921](https://github.com/OpenMage/magento-lts/pull/921)) - enabled website level config cache ([#2355](https://github.com/OpenMage/magento-lts/pull/2355)) - make overrides of Mage_Core_Model_Resource_Db_Abstract::delete respect parent api ([#1257](https://github.com/OpenMage/magento-lts/pull/1257)) +- rewrite Mage_Eav_Model_Config as cache for all eav entity and attribute reads ([#2993](https://github.com/OpenMage/magento-lts/pull/2993)) For full list of changes, you can [compare tags](https://github.com/OpenMage/magento-lts/compare/1.9.4.x...20.0). @@ -550,6 +551,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Scott Moore

Roger Feese

Alexander Gelzer
+
David Hiendl
diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php index ad875a675e2..acd3eb4950d 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php @@ -390,8 +390,8 @@ public function getIsCurrentSetDefault() { $isDefault = $this->getData('is_current_set_default'); if (is_null($isDefault)) { - $defaultSetId = Mage::getModel('eav/entity_type') - ->load(Mage::registry('entityType')) + $defaultSetId = Mage::getSingleton('eav/config') + ->getEntityType(Mage::registry('entityType')) ->getDefaultAttributeSetId(); $isDefault = $this->_getSetId() == $defaultSetId; $this->setData('is_current_set_default', $isDefault); diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main/Formgroup.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main/Formgroup.php index 44b952212af..868e1b5be03 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main/Formgroup.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main/Formgroup.php @@ -76,8 +76,7 @@ protected function _getSetId() { return ((int) $this->getRequest()->getParam('id') > 0) ? (int) $this->getRequest()->getParam('id') - : Mage::getModel('eav/entity_type') - ->load(Mage::registry('entityType')) + : Mage::getSingleton('eav/config')->getEntityType(Mage::registry('entityType')) ->getDefaultAttributeSetId(); } } diff --git a/app/code/core/Mage/Api2/Model/Resource.php b/app/code/core/Mage/Api2/Model/Resource.php index 200dbbf1a22..c811c9f001a 100644 --- a/app/code/core/Mage/Api2/Model/Resource.php +++ b/app/code/core/Mage/Api2/Model/Resource.php @@ -1030,7 +1030,7 @@ public function getEavAttributes($onlyVisible = false, $excludeSystem = false) $model = $this->getConfig()->getResourceWorkingModel($this->getResourceType()); /** @var Mage_Eav_Model_Entity_Type $entityType */ - $entityType = Mage::getModel('eav/entity_type')->load($model, 'entity_model'); + $entityType = Mage::getSingleton('eav/config')->getEntityType($model, 'entity_model'); /** @var Mage_Eav_Model_Entity_Attribute $attribute */ foreach ($entityType->getAttributeCollection() as $attribute) { diff --git a/app/code/core/Mage/Catalog/Block/Product/Compare/List.php b/app/code/core/Mage/Catalog/Block/Product/Compare/List.php index e8ba5497160..ea9d75576b3 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Compare/List.php +++ b/app/code/core/Mage/Catalog/Block/Product/Compare/List.php @@ -126,7 +126,7 @@ public function getItems() /** * Retrieve Product Compare Attributes * - * @return array + * @return Mage_Eav_Model_Entity_Attribute_Abstract[] */ public function getAttributes() { diff --git a/app/code/core/Mage/Catalog/Helper/Data.php b/app/code/core/Mage/Catalog/Helper/Data.php index 45d0f8de5d3..8c6d078c1f7 100644 --- a/app/code/core/Mage/Catalog/Helper/Data.php +++ b/app/code/core/Mage/Catalog/Helper/Data.php @@ -416,8 +416,8 @@ public function canApplyMsrpToProductType($product) { if ($this->_mapApplyToProductType === null) { /** @var Mage_Catalog_Model_Resource_Eav_Attribute $attribute */ - $attribute = Mage::getModel('catalog/resource_eav_attribute') - ->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'msrp_enabled'); + $attribute = Mage::getSingleton('eav/config') + ->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'msrp_enabled'); $this->_mapApplyToProductType = $attribute->getApplyTo(); } return empty($this->_mapApplyToProductType) || in_array($product->getTypeId(), $this->_mapApplyToProductType); diff --git a/app/code/core/Mage/Catalog/Model/Api2/Product.php b/app/code/core/Mage/Catalog/Model/Api2/Product.php index 347af285458..1d034d7062a 100644 --- a/app/code/core/Mage/Catalog/Model/Api2/Product.php +++ b/app/code/core/Mage/Catalog/Model/Api2/Product.php @@ -39,7 +39,7 @@ public function getAvailableAttributes($userType, $operation) { $attributes = $this->getAvailableAttributesFromConfig(); /** @var Mage_Eav_Model_Entity_Type $entityType */ - $entityType = Mage::getModel('eav/entity_type')->loadByCode('catalog_product'); + $entityType = Mage::getSingleton('eav/config')->getEntityType(Mage_Catalog_Model_Product::ENTITY); $entityOnlyAttrs = $this->getEntityOnlyAttributes($userType, $operation); /** @var Mage_Catalog_Model_Resource_Eav_Attribute $attribute */ foreach ($entityType->getAttributeCollection() as $attribute) { diff --git a/app/code/core/Mage/Catalog/Model/Api2/Product/Validator/Product.php b/app/code/core/Mage/Catalog/Model/Api2/Product/Validator/Product.php index 14ea4e60014..900e891f77a 100644 --- a/app/code/core/Mage/Catalog/Model/Api2/Product/Validator/Product.php +++ b/app/code/core/Mage/Catalog/Model/Api2/Product/Validator/Product.php @@ -107,7 +107,7 @@ public function isValidData(array $data) try { $this->_validateProductType($data); /** @var Mage_Eav_Model_Entity_Type $productEntity */ - $productEntity = Mage::getModel('eav/entity_type')->loadByCode(Mage_Catalog_Model_Product::ENTITY); + $productEntity = Mage::getSingleton('eav/config')->getEntityType(Mage_Catalog_Model_Product::ENTITY); $this->_validateAttributeSet($data, $productEntity); $this->_validateSku($data); $this->_validateGiftOptions($data); diff --git a/app/code/core/Mage/Catalog/Model/Config.php b/app/code/core/Mage/Catalog/Model/Config.php index 3241fab17df..6f21d8b03f6 100644 --- a/app/code/core/Mage/Catalog/Model/Config.php +++ b/app/code/core/Mage/Catalog/Model/Config.php @@ -330,17 +330,13 @@ protected function _getResource() public function getAttributesUsedInProductListing() { if (is_null($this->_usedInProductListing)) { + $allAttributes = Mage::getSingleton('eav/config') + ->getAttributes(Mage_Catalog_Model_Product::ENTITY); $this->_usedInProductListing = []; - $entityType = Mage_Catalog_Model_Product::ENTITY; - $attributesData = $this->_getResource() - ->setStoreId($this->getStoreId()) - ->getAttributesUsedInListing(); - Mage::getSingleton('eav/config') - ->importAttributesData($entityType, $attributesData); - foreach ($attributesData as $attributeData) { - $attributeCode = $attributeData['attribute_code']; - $this->_usedInProductListing[$attributeCode] = Mage::getSingleton('eav/config') - ->getAttribute($entityType, $attributeCode); + foreach ($allAttributes as $attribute) { + if ($attribute->getData('used_in_product_listing')) { + $this->_usedInProductListing[$attribute->getAttributeCode()] = $attribute; + } } } return $this->_usedInProductListing; @@ -354,16 +350,13 @@ public function getAttributesUsedInProductListing() public function getAttributesUsedForSortBy() { if (is_null($this->_usedForSortBy)) { + $allAttributes = Mage::getSingleton('eav/config') + ->getAttributes(Mage_Catalog_Model_Product::ENTITY); $this->_usedForSortBy = []; - $entityType = Mage_Catalog_Model_Product::ENTITY; - $attributesData = $this->_getResource() - ->getAttributesUsedForSortBy(); - Mage::getSingleton('eav/config') - ->importAttributesData($entityType, $attributesData); - foreach ($attributesData as $attributeData) { - $attributeCode = $attributeData['attribute_code']; - $this->_usedForSortBy[$attributeCode] = Mage::getSingleton('eav/config') - ->getAttribute($entityType, $attributeCode); + foreach ($allAttributes as $attribute) { + if ($attribute->getData('used_for_sort_by')) { + $this->_usedForSortBy[$attribute->getAttributeCode()] = $attribute; + } } } return $this->_usedForSortBy; diff --git a/app/code/core/Mage/Catalog/Model/Layer.php b/app/code/core/Mage/Catalog/Model/Layer.php index bb267c0215d..262f9fab244 100644 --- a/app/code/core/Mage/Catalog/Model/Layer.php +++ b/app/code/core/Mage/Catalog/Model/Layer.php @@ -202,7 +202,7 @@ public function getCurrentStore() /** * Get collection of all filterable attributes for layer products set * - * @return Mage_Catalog_Model_Resource_Product_Attribute_Collection|array + * @return Mage_Catalog_Model_Resource_Eav_Attribute[] */ public function getFilterableAttributes() { @@ -210,17 +210,26 @@ public function getFilterableAttributes() if (!$setIds) { return []; } - /** @var Mage_Catalog_Model_Resource_Product_Attribute_Collection $collection */ - $collection = Mage::getResourceModel('catalog/product_attribute_collection'); - $collection - ->setItemObjectClass('catalog/resource_eav_attribute') - ->setAttributeSetFilter($setIds) - ->addStoreLabel(Mage::app()->getStore()->getId()) - ->setOrder('position', 'ASC'); - $collection = $this->_prepareAttributeCollection($collection); - $collection->load(); - return $collection; + $eavConfig = Mage::getSingleton('eav/config'); + /** @var Mage_Catalog_Model_Resource_Eav_Attribute[] $attributes */ + $attributes = []; + foreach ($setIds as $setId) { + $setAttributeIds = $eavConfig->getAttributeSetAttributeIds($setId); + foreach ($setAttributeIds as $attributeId) { + if (!isset($attributes[$attributeId])) { + $attribute = $eavConfig->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeId); + if ($attribute instanceof Mage_Catalog_Model_Resource_Eav_Attribute && $attribute->getIsFilterable()) { + $attributes[$attributeId] = $attribute; + } + } + } + } + usort($attributes, function ($a, $b) { + return $a->getPosition() - $b->getPosition(); + }); + + return $attributes; } /** diff --git a/app/code/core/Mage/Catalog/Model/Layer/Filter/Attribute.php b/app/code/core/Mage/Catalog/Model/Layer/Filter/Attribute.php index e45217892e4..69d42bbba91 100644 --- a/app/code/core/Mage/Catalog/Model/Layer/Filter/Attribute.php +++ b/app/code/core/Mage/Catalog/Model/Layer/Filter/Attribute.php @@ -97,7 +97,7 @@ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) * Check whether specified attribute can be used in LN * * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute - * @return Mage_Catalog_Model_Resource_Eav_Attribute + * @return int */ protected function _getIsFilterableAttribute($attribute) { diff --git a/app/code/core/Mage/Catalog/Model/Resource/Category.php b/app/code/core/Mage/Catalog/Model/Resource/Category.php index 0d032fe9b11..3821d793cb3 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Category.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Category.php @@ -483,17 +483,13 @@ public function getChildrenAmount($category, $isActiveFlag = true) protected function _getIsActiveAttributeId() { if ($this->_isActiveAttributeId === null) { - $bind = [ - 'catalog_category' => Mage_Catalog_Model_Category::ENTITY, - 'is_active' => 'is_active', - ]; - $select = $this->_getReadAdapter()->select() - ->from(['a' => $this->getTable('eav/attribute')], ['attribute_id']) - ->join(['t' => $this->getTable('eav/entity_type')], 'a.entity_type_id = t.entity_type_id') - ->where('entity_type_code = :catalog_category') - ->where('attribute_code = :is_active'); - - $this->_isActiveAttributeId = $this->_getReadAdapter()->fetchOne($select, $bind); + $attributeId = Mage::getSingleton('eav/config') + ->getAttribute(Mage_Catalog_Model_Category::ENTITY, 'is_active') + ->getId(); + if (!is_int($attributeId)) { + Mage::throwException("Failed to find category attribute is_active"); + } + $this->_isActiveAttributeId = $attributeId; } return $this->_isActiveAttributeId; diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Attribute.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Attribute.php index 91eaf6a8ac2..afaef44d8e1 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Attribute.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Attribute.php @@ -37,7 +37,6 @@ * @method $this setIsSearchable(int $value) * @method int getSearchWeight() * @method $this setSearchWeight(int $value) - * @method int getIsFilterable() * @method $this setIsFilterable(int $value) * @method int getIsComparable() * @method $this setIsComparable(int $value) @@ -288,6 +287,15 @@ public function getFrontendLabel() return $this->_getData('frontend_label'); } + /** + * Retrieve is_filterable value + * @return int + */ + public function getIsFilterable() + { + return $this->_getData('is_filterable'); + } + /** * Get Attribute translated label for store * diff --git a/app/code/core/Mage/Catalog/Model/Resource/Product/Compare/Item/Collection.php b/app/code/core/Mage/Catalog/Model/Resource/Product/Compare/Item/Collection.php index 7f6986918d7..212c2aa00d2 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Product/Compare/Item/Collection.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Product/Compare/Item/Collection.php @@ -45,7 +45,7 @@ class Mage_Catalog_Model_Resource_Product_Compare_Item_Collection extends Mage_C /** * Comparable attributes cache * - * @var array|null + * @var Mage_Eav_Model_Entity_Attribute_Abstract[]|null */ protected $_comparableAttributes; @@ -211,7 +211,7 @@ protected function _getAttributeIdsBySetIds(array $setIds) /** * Retrieve Merged comparable attributes for compared product items * - * @return array + * @return Mage_Eav_Model_Entity_Attribute_Abstract[] */ public function getComparableAttributes() { @@ -219,36 +219,19 @@ public function getComparableAttributes() $this->_comparableAttributes = []; $setIds = $this->_getAttributeSetIds(); if ($setIds) { - $select = $this->getConnection()->select() - ->from(['main_table' => $this->getTable('eav/attribute')]) - ->join( - ['additional_table' => $this->getTable('catalog/eav_attribute')], - 'additional_table.attribute_id=main_table.attribute_id' - ) - ->joinLeft( - ['al' => $this->getTable('eav/attribute_label')], - 'al.attribute_id = main_table.attribute_id AND al.store_id = ' . (int) $this->getStoreId(), - ['store_label' => new Zend_Db_Expr('IFNULL(al.value, main_table.frontend_label)')] - ) - ->joinLeft( - ['ai' => $this->getTable('eav/entity_attribute')], - 'ai.attribute_id = main_table.attribute_id' - ) - ->where('additional_table.is_comparable=?', 1) - ->where('ai.attribute_set_id IN(?)', $setIds) - ->order(['ai.attribute_group_id ASC', 'ai.sort_order ASC']); - $attributesData = $this->getConnection()->fetchAll($select); - if ($attributesData) { - $entityType = Mage_Catalog_Model_Product::ENTITY; - Mage::getSingleton('eav/config') - ->importAttributesData($entityType, $attributesData); - foreach ($attributesData as $data) { - $attribute = Mage::getSingleton('eav/config') - ->getAttribute($entityType, $data['attribute_code']); + $eavConfig = Mage::getSingleton('eav/config'); + $attributeIds = $eavConfig->getAttributeSetAttributeIds($setIds); + $this->_comparableAttributes = []; + foreach ($attributeIds as $attributeId) { + $attribute = $eavConfig->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeId); + if ($attribute->getData('is_comparable')) { $this->_comparableAttributes[$attribute->getAttributeCode()] = $attribute; } - unset($attributesData); } + + usort($this->_comparableAttributes, function ($a, $b) { + return $a->getPosition() - $b->getPosition(); + }); } } return $this->_comparableAttributes; diff --git a/app/code/core/Mage/Catalog/Model/Resource/Product/Flat/Indexer.php b/app/code/core/Mage/Catalog/Model/Resource/Product/Flat/Indexer.php index 7784e548bed..17adc97b28a 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Product/Flat/Indexer.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Product/Flat/Indexer.php @@ -184,8 +184,6 @@ public function getAttributeCodes() $select->where(implode(' OR ', $whereCondition)); $attributesData = $adapter->fetchAll($select, $bind); - Mage::getSingleton('eav/config') - ->importAttributesData($this->getEntityType(), $attributesData); foreach ($attributesData as $data) { $this->_attributeCodes[$data['attribute_id']] = $data['attribute_code']; @@ -264,8 +262,8 @@ public function getAttribute($attributeCode) { $attributes = $this->getAttributes(); if (!isset($attributes[$attributeCode])) { - $attribute = Mage::getModel('catalog/resource_eav_attribute') - ->loadByCode($this->getEntityTypeId(), $attributeCode); + $attribute = Mage::getSingleton('eav/config') + ->getAttribute($this->getEntityTypeId(), $attributeCode); if (!$attribute->getId()) { Mage::throwException(Mage::helper('catalog')->__('Invalid attribute %s', $attributeCode)); } @@ -274,6 +272,10 @@ public function getAttribute($attributeCode) ->getEntity(); $attribute->setEntity($entity); + if (!($attribute instanceof Mage_Eav_Model_Entity_Attribute)) { + throw new Exception('Product attribute(code=' . $attributeCode . ') is expected to be of type Mage_Eav_Model_Entity_Attribute'); + } + return $attribute; } diff --git a/app/code/core/Mage/CatalogIndex/Model/Indexer/Minimalprice.php b/app/code/core/Mage/CatalogIndex/Model/Indexer/Minimalprice.php index 309db7e9f23..0091235d6bb 100644 --- a/app/code/core/Mage/CatalogIndex/Model/Indexer/Minimalprice.php +++ b/app/code/core/Mage/CatalogIndex/Model/Indexer/Minimalprice.php @@ -65,7 +65,7 @@ public function getTierPriceAttribute() { $data = $this->getData('tier_price_attribute'); if (is_null($data)) { - $data = Mage::getModel('eav/entity_attribute')->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'tier_price'); + $data = Mage::getSingleton('eav/config')->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'tier_price'); $this->setData('tier_price_attribute', $data); } return $data; @@ -79,7 +79,7 @@ public function getPriceAttribute() { $data = $this->getData('price_attribute'); if (is_null($data)) { - $data = Mage::getModel('eav/entity_attribute')->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'price'); + $data = Mage::getSingleton('eav/config')->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'price'); $this->setData('price_attribute', $data); } return $data; diff --git a/app/code/core/Mage/CatalogSearch/Model/Layer/Filter/Attribute.php b/app/code/core/Mage/CatalogSearch/Model/Layer/Filter/Attribute.php index 31c489f3ef0..0da2fae3b3b 100644 --- a/app/code/core/Mage/CatalogSearch/Model/Layer/Filter/Attribute.php +++ b/app/code/core/Mage/CatalogSearch/Model/Layer/Filter/Attribute.php @@ -33,7 +33,7 @@ class Mage_CatalogSearch_Model_Layer_Filter_Attribute extends Mage_Catalog_Model * Check whether specified attribute can be used in LN * * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute - * @return bool + * @return int */ protected function _getIsFilterableAttribute($attribute) { diff --git a/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php b/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php index e1edf6a32ed..22f5d9b71cf 100644 --- a/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php +++ b/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php @@ -67,11 +67,15 @@ public function getProduct() */ public function getPurchasedSeparatelyAttribute() { - if (is_null($this->_purchasedSeparatelyAttribute)) { + if ($this->_purchasedSeparatelyAttribute === null) { $_attributeCode = 'links_purchased_separately'; - $this->_purchasedSeparatelyAttribute = Mage::getModel('eav/entity_attribute') - ->loadByCode(Mage_Catalog_Model_Product::ENTITY, $_attributeCode); + $attribute = Mage::getSingleton('eav/config') + ->getAttribute(Mage_Catalog_Model_Product::ENTITY, $_attributeCode); + if (!($attribute instanceof Mage_Catalog_Model_Resource_Eav_Attribute)) { + Mage::throwException('Attribute links_purchased_separately must be of type Mage_Catalog_Model_Resource_Eav_Attribute'); + } + $this->_purchasedSeparatelyAttribute = $attribute; } return $this->_purchasedSeparatelyAttribute; diff --git a/app/code/core/Mage/Eav/Model/Config.php b/app/code/core/Mage/Eav/Model/Config.php index 4704b6dec7b..d73ac825f8a 100644 --- a/app/code/core/Mage/Eav/Model/Config.php +++ b/app/code/core/Mage/Eav/Model/Config.php @@ -28,191 +28,296 @@ */ class Mage_Eav_Model_Config { - public const ENTITIES_CACHE_ID = 'EAV_ENTITY_TYPES'; - public const ATTRIBUTES_CACHE_ID = 'EAV_ENTITY_ATTRIBUTES'; - /** - * Entity types data - * - * @var array|null + * Cache key for storing: + * - EAV entities + * - EAV attributes + * - EAV attribute extension table data */ - protected $_entityData; + public const EAV_DATA_CACHE = 'EAV_DATA_CACHE'; + + public const ENTITIES_CACHE_ID = 'EAV_ENTITY_TYPES'; + + public const NUMERIC_ATTRIBUTE_COLUMNS = [ + // from table eav_attribute + 'attribute_id', + 'entity_type_id', + 'is_required', + 'is_user_defined', + 'is_unique', + ]; + + protected $_storeInitialized = []; /** - * Attributes data - * - * @var array|null + * @var Mage_Eav_Model_Entity_Type[]|null */ - protected $_attributeData; + protected $_entityTypes; /** - * Information about preloaded attributes - * - * @var array + * @var Mage_Eav_Model_Entity_Type[]|null */ - protected $_preloadedAttributes = []; + protected $_entityTypeByCode; /** - * Information about entity types with initialized attributes - * - * @var array + * @var Mage_Eav_Model_Entity_Attribute_Abstract[][][]|mixed[][][]|null */ - protected $_initializedAttributes = []; + protected $_entityTypeAttributes; /** - * Attribute codes cache array - * - * @var array + * @var Mage_Eav_Model_Entity_Attribute_Abstract[][][]|null */ - protected $_attributeCodes = []; + protected $_entityTypeAttributeIdByCode; /** - * Initialized objects - * - * array ($objectId => $object) - * - * @var array|null + * Attribute set relation information. Structure: + *
+ * [ + * int attribute_id => [ + * int set_id => [ + * int group_id, + * int group_sort, + * int sort, + * ] + * ] + * @var mixed[][][][]|null */ - protected $_objects; + protected $_attributeSetInfo; /** - * References between codes and identifiers - * - * array ( - * 'attributes'=> array ($attributeId => $attributeCode), - * 'entities' => array ($entityId => $entityCode) - * ) - * - * @var array|null + * Special local cache for default attributes to avoid re-hydrating them + * @var Mage_Eav_Model_Entity_Attribute_Abstract[][][]|false[][][] */ - protected $_references; + protected $_defaultAttributes = []; /** * Cache flag * * @var bool */ - protected $_isCacheEnabled = null; + protected $_isCacheEnabled = null; /** - * Array of attributes objects used in collections - * - * @var array + * @var int|false|null */ - protected $_collectionAttributes = []; + protected $_currentStoreId; + /** * Reset object state * - * @deprecated * @return $this + * @deprecated */ public function clear() { - $this->_entityData = null; - $this->_attributeData = null; - $this->_objects = null; - $this->_references = null; - $this->_preloadedAttributes = []; - $this->_initializedAttributes = []; + $this->_storeInitialized = []; + $this->_entityTypes = null; + $this->_entityTypeByCode = null; + $this->_entityTypeAttributes = null; + $this->_entityTypeAttributeIdByCode = null; + $this->_attributeSetInfo = null; + $this->_defaultAttributes = []; + + Mage::app()->cleanCache([self::ENTITIES_CACHE_ID]); + return $this; } /** - * Get object by identifier - * - * @param mixed $id - * @return mixed + * @param int|false|null $storeId + * @return void */ - protected function _load($id) + public function setCurrentStoreId($storeId) { - return $this->_objects[$id] ?? null; + $this->_currentStoreId = $storeId; } - /** - * Associate object with identifier - * - * @param mixed $obj - * @param mixed $id - * @return Mage_Eav_Model_Config - */ - protected function _save($obj, $id) + protected function _storeId() { - $this->_objects[$id] = $obj; - return $this; + if (isset($this->_currentStoreId) && $this->_currentStoreId !== false) { + return $this->_currentStoreId; + } + return Mage::app()->getStore()->getId(); } - /** - * Specify reference for entity type id - * - * @param int $id - * @param string $code - * @return Mage_Eav_Model_Config - */ - protected function _addEntityTypeReference($id, $code) + protected function _initializeStore($storeId = null) { - $this->_references['entity'][$id] = $code; - return $this; + if ($storeId === null) { + $storeId = $this->_storeId(); + } else { + // ensure store id is consistent + $storeId = (int)$storeId; + } + if (isset($this->_storeInitialized[$storeId]) && $this->_storeInitialized[$storeId]) { + return; + } + + Varien_Profiler::start('EAV: ' . __METHOD__); + + if ($this->_isCacheEnabled() && $this->_loadFromCache($storeId)) { + $this->_storeInitialized[$storeId] = true; + return; + } + + if (empty($this->_entityTypes)) { + $this->_loadEntityTypes(); + $this->_loadAttributeSetInfo(); + } + + // load each entity attributes for given storeId + if (empty($this->_entityTypeAttributes[$storeId])) { + $this->_entityTypeAttributes[$storeId] = []; + foreach ($this->_entityTypes as $entityType) { + $this->_loadEntityAttributes($entityType, $storeId); + } + } + + if ($this->_isCacheEnabled()) { + $this->_saveToCache($storeId); + } + + $this->_storeInitialized[$storeId] = true; + + Varien_Profiler::stop('EAV: ' . __METHOD__); } /** - * Get entity type code by id - * - * @param int $id - * @return string + * @param $storeId + * @return void + * @throws Exception */ - protected function _getEntityTypeReference($id) + protected function _loadEntityTypes() { - return $this->_references['entity'][$id] ?? null; + // load entity types + $this->_entityTypes = []; + $this->_entityTypeByCode = []; + $entityTypeCollection = Mage::getResourceModel('eav/entity_type_collection'); + /** @var Mage_Eav_Model_Entity_Type $entityType */ + foreach ($entityTypeCollection as $entityType) { + $this->_entityTypes[$entityType->getId()] = $entityType; + $this->_entityTypeByCode[$entityType->getEntityTypeCode()] = $entityType; + } } /** - * Specify reference between entity attribute id and attribute code - * - * @param int $id - * @param string $code - * @param string $entityTypeCode - * @return Mage_Eav_Model_Config + * @param Mage_Eav_Model_Entity_Type $entityType + * @param int $storeId + * @return void + * @throws Exception */ - protected function _addAttributeReference($id, $code, $entityTypeCode) + protected function _loadEntityAttributes($entityType, $storeId) { - $this->_references['attribute'][$entityTypeCode][$id] = $code; - return $this; + // preload attributes in array form to avoid instantiating models for every attribute even if it is never accessed + $entityAttributes = $entityType->getAttributeCollection() + ->addStoreLabel($storeId) + ->getData(); + + $this->_entityTypeAttributes[$storeId][$entityType->getId()] = []; + $attributeCodes = []; + + /** @var Mage_Eav_Model_Entity_Attribute_Abstract $entityAttributeData */ + foreach ($entityAttributes as $entityAttributeData) { + $attributeId = $entityAttributeData['attribute_id']; + $attributeCode = $entityAttributeData['attribute_code']; + + // workaround for getAttributeCollection()->getData() returning all columns as string + foreach (self::NUMERIC_ATTRIBUTE_COLUMNS as $key) { + if (!isset($entityAttributeData[$key])) { + continue; + } + $entityAttributeData[$key] = (int)$entityAttributeData[$key]; + } + + $this->_entityTypeAttributes[$storeId][$entityType->getId()][$attributeId] = $entityAttributeData; + $this->_entityTypeAttributeIdByCode[$storeId][$entityType->getId()][$attributeCode] = $attributeId; + $attributeCodes[] = $attributeCode; + } + + $entityType->setAttributeCodes($attributeCodes); } /** - * Get attribute code by attribute id - * - * @param int $id - * @param string $entityTypeCode - * @return string + * @param $storeId + * @return void + * @throws Exception */ - protected function _getAttributeReference($id, $entityTypeCode) + protected function _loadAttributeSetInfo() { - return $this->_references['attribute'][$entityTypeCode][$id] ?? null; + $this->_attributeSetInfo = Mage::getResourceModel('eav/entity_attribute_set')->getSetInfo(); } /** - * Get internal cache key for entity type code - * - * @param string $code - * @return string + * @param int $storeId + * @return bool true if successfully loaded from cache, false otherwise + * @throws Exception */ - protected function _getEntityKey($code) + protected function _loadFromCache($storeId) { - return 'ENTITY/' . $code; + Varien_Profiler::start('EAV: ' . __METHOD__); + + $cacheData = Mage::app()->loadCache(self::ENTITIES_CACHE_ID . '_' . $storeId); + if ($cacheData === false) { + Varien_Profiler::stop('EAV: ' . __METHOD__); + return false; + } + $cacheData = unserialize($cacheData); + + $this->_entityTypes = []; + $this->_entityTypeByCode = []; + /** @var array $entityTypeData */ + foreach ($cacheData['_entityTypes'] as $entityTypeData) { + $entityType = Mage::getModel('eav/entity_type') + ->setData($entityTypeData); + $this->_entityTypes[$entityType->getId()] = $entityType; + $this->_entityTypeByCode[$entityType->getEntityTypeCode()] = $entityType; + } + + $this->_entityTypeAttributes[$storeId] = []; + /** @var int $entityTypeId */ + /** @var array $entityTypeAttributes */ + foreach ($cacheData['_entityTypeAttributes'] as $entityTypeId => $entityTypeAttributes) { + /** @var array $attributeData */ + foreach ($entityTypeAttributes as $attributeData) { + $attributeId = $attributeData['attribute_id']; + $attributeCode = $attributeData['attribute_code']; + $this->_entityTypeAttributes[$storeId][$entityTypeId][$attributeId] = $attributeData; + $this->_entityTypeAttributeIdByCode[$storeId][$entityTypeId][$attributeCode] = $attributeId; + } + } + + $this->_attributeSetInfo = $cacheData['_attributeSetInfo']; + + Varien_Profiler::stop('EAV: ' . __METHOD__); + return true; } - /** - * Get internal cache key for attribute object cache - * - * @param string $entityTypeCode - * @param string $attributeCode - * @return string - */ - protected function _getAttributeKey($entityTypeCode, $attributeCode) + protected function _saveToCache($storeId) { - return 'ATTRIBUTE/' . $entityTypeCode . '/' . $attributeCode; + $cacheData = [ + '_entityTypes' => [], + '_entityTypeAttributes' => [], + '_attributeSetInfo' => $this->_attributeSetInfo, + ]; + + foreach ($this->_entityTypes as $entityType) { + $cacheData['_entityTypes'][$entityType->getId()] = $entityType->getData(); + } + + foreach ($this->_entityTypeAttributes[$storeId] as $entityTypeId => $attributes) { + $cacheData['_entityTypeAttributes'][$entityTypeId] = []; + foreach ($attributes as $attribute) { + $attributeId = is_array($attribute) ? $attribute['attribute_id'] : $attribute->getId(); + $attributeData = is_array($attribute) ? $attribute : $attribute->getData(); + $cacheData['_entityTypeAttributes'][$entityTypeId][$attributeId] = $attributeData; + } + } + + Mage::app()->saveCache( + serialize($cacheData), + self::ENTITIES_CACHE_ID . '_' . $storeId, + ['eav', self::ENTITIES_CACHE_ID, Mage_Eav_Model_Entity_Attribute::CACHE_TAG] + ); } /** @@ -229,486 +334,277 @@ protected function _isCacheEnabled() } /** - * Initialize all entity types data + * Create model instance from array * - * @return $this + * @param array $attributeData + * @return Mage_Eav_Model_Entity_Attribute_Abstract|false */ - protected function _initEntityTypes() + protected function _hydrateAttribute($attributeData) { - if (is_array($this->_entityData)) { - return $this; - } - Varien_Profiler::start('EAV: ' . __METHOD__); - - /** - * try load information about entity types from cache - */ - if ($this->_isCacheEnabled() - && ($cache = Mage::app()->loadCache(self::ENTITIES_CACHE_ID)) - ) { - $this->_entityData = unserialize($cache, ['allowed_classes' => false]); - foreach ($this->_entityData as $typeCode => $data) { - $typeId = $data['entity_type_id']; - $this->_addEntityTypeReference($typeId, $typeCode); - } - Varien_Profiler::stop('EAV: ' . __METHOD__); - return $this; + $entityType = $this->getEntityType($attributeData['entity_type_id']); + if (!empty($attributeData['attribute_model'])) { + $model = $attributeData['attribute_model']; + } else { + $model = $entityType->getAttributeModel(); } + /** @var Mage_Eav_Model_Entity_Attribute_Abstract|false $attribute */ + $attribute = Mage::getModel($model); + if ($attribute) { + $attribute->setData($attributeData); - $entityTypesData = Mage::getModel('eav/entity_type')->getCollection()->getData(); - $types = []; - - /** - * prepare entity type data - */ - foreach ($entityTypesData as $typeData) { - if (!isset($typeData['attribute_model'])) { - $typeData['attribute_model'] = 'eav/entity_attribute'; + $entity = $entityType->getEntity(); + if (in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes())) { + $attribute + ->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC) + ->setIsGlobal(1); } - - $typeCode = $typeData['entity_type_code']; - $typeId = $typeData['entity_type_id']; - - $this->_addEntityTypeReference($typeId, $typeCode); - $types[$typeCode] = $typeData; + $attribute + ->setEntityType($entityType) + ->setEntityTypeId($entityType->getId()); } - $this->_entityData = $types; - - if ($this->_isCacheEnabled()) { - Mage::app()->saveCache( - serialize($this->_entityData), - self::ENTITIES_CACHE_ID, - ['eav', Mage_Eav_Model_Entity_Attribute::CACHE_TAG] - ); - } - Varien_Profiler::stop('EAV: ' . __METHOD__); - return $this; + return $attribute; } /** * Get entity type object by entity type code/identifier * - * @param mixed $code - * @return Mage_Eav_Model_Entity_Type + * @param mixed $code + * @param string|null $code + * @param string $field + * @return Mage_Eav_Model_Entity_Type + * @throws Mage_Core_Exception */ - public function getEntityType($code) + public function getEntityType($code, $field = null) { if ($code instanceof Mage_Eav_Model_Entity_Type) { return $code; } - Varien_Profiler::start('EAV: ' . __METHOD__); - if (is_numeric($code)) { - $entityCode = $this->_getEntityTypeReference($code); - if ($entityCode !== null) { - $code = $entityCode; - } + // initialize entity type cache + if (!isset($this->_entityTypes)) { + $this->_initializeStore(); } - $entityKey = $this->_getEntityKey($code); - $entityType = $this->_load($entityKey); - if ($entityType) { - Varien_Profiler::stop('EAV: ' . __METHOD__); - return $entityType; + // lookup by id + if (empty($field) && is_numeric($code)) { + if (isset($this->_entityTypes[$code])) { + return $this->_entityTypes[$code]; + } else { + Mage::throwException('Invalid entity type: ' . $code); + } } - $entityType = Mage::getModel('eav/entity_type'); - if (isset($this->_entityData[$code])) { - $entityType->setData($this->_entityData[$code]); - } else { - if (is_numeric($code)) { - $entityType->load($code); + // lookup by code + if (empty($field) || $field == 'entity_type_code') { + if (isset($this->_entityTypeByCode[$code])) { + return $this->_entityTypeByCode[$code]; } else { - $entityType->loadByCode($code); + Mage::throwException('Invalid entity type: ' . $code); } + } - if (!$entityType->getId()) { - Mage::throwException(Mage::helper('eav')->__('Invalid entity_type specified: %s', $code)); + // lookup by other field + foreach ($this->_entityTypes as $entityType) { + if ($entityType->getData($field) == $code) { + return $entityType; } } - $this->_addEntityTypeReference($entityType->getId(), $entityType->getEntityTypeCode()); - $this->_save($entityType, $entityKey); - Varien_Profiler::stop('EAV: ' . __METHOD__); - return $entityType; + Mage::throwException('Failed to find entity eav/entity_type for ' . $field . '=' . $code); } /** - * Initialize all attributes for entity type + * Default attributes are loaded only on getAttribute(...) call to avoid infinite loading loop between + * Entity_Type->getEntity() which itself requires this class and re-triggers loading. * - * @param string $entityType - * @return Mage_Eav_Model_Config + * @param Mage_Eav_Model_Entity_Type $entityType + * @param int $storeId + * @param string $attributeCode + * @return Mage_Eav_Model_Entity_Attribute_Abstract|false */ - protected function _initAttributes($entityType) + protected function _getDefaultAttributeIfExists($entityType, $attributeCode, $storeId) { - $entityType = $this->getEntityType($entityType); - $entityTypeCode = $entityType->getEntityTypeCode(); - - if (isset($this->_initializedAttributes[$entityTypeCode])) { - return $this; - } - Varien_Profiler::start('EAV: ' . __METHOD__); - - /** @var Mage_Eav_Model_Resource_Entity_Attribute_Collection $attributesInfo */ - $attributesInfo = Mage::getResourceModel($entityType->getEntityAttributeCollection()); - $attributesInfo->setEntityTypeFilter($entityType); - $attributesInfoData = $attributesInfo->getData(); - - $codes = []; - foreach ($attributesInfoData as $attribute) { - $this->_createAttribute($entityType, $attribute); - $codes[] = $attribute['attribute_code']; + if (isset($this->_defaultAttributes[$storeId][$entityType->getId()][$attributeCode])) { + return $this->_defaultAttributes[$storeId][$entityType->getId()][$attributeCode]; + } + + $entity = $entityType->getEntity(); + if (method_exists($entity, 'getDefaultAttributes')) { + if (in_array($attributeCode, $entity->getDefaultAttributes())) { + $attributeData = [ + 'entity_type_id' => $entityType->getId(), + 'attribute_code' => $attributeCode, + ]; + $attribute = $this->_hydrateAttribute($attributeData); + $this->_defaultAttributes[$storeId][$entityType->getId()][$attributeCode] = $attribute; + return $attribute; + } } - $entityType->setAttributeCodes($codes); - $this->_initializedAttributes[$entityTypeCode] = true; - - Varien_Profiler::stop('EAV: ' . __METHOD__); - return $this; + // cache a miss as well + $this->_defaultAttributes[$storeId][$entityType->getId()][$attributeCode] = false; + return false; } /** * Get attribute by code for entity type * - * @param mixed $entityType - * @param mixed $code - * @return Mage_Eav_Model_Entity_Attribute_Abstract|false + * @param mixed $entityType + * @param mixed $code + * @param int|null $storeId + * @return Mage_Eav_Model_Entity_Attribute_Abstract|false */ - public function getAttribute($entityType, $code) + public function getAttribute($entityType, $code, $storeId = null) { if ($code instanceof Mage_Eav_Model_Entity_Attribute_Interface) { return $code; } - Varien_Profiler::start('EAV: ' . __METHOD__); - - $entityTypeCode = $this->getEntityType($entityType)->getEntityTypeCode(); - $entityType = $this->getEntityType($entityType); - - /** - * Validate attribute code - */ - if (is_numeric($code)) { - $attributeCode = $this->_getAttributeReference($code, $entityTypeCode); - if ($attributeCode) { - $code = $attributeCode; - } - } - $attributeKey = $this->_getAttributeKey($entityTypeCode, $code); + $storeId = $storeId !== null ? $storeId : $this->_storeId(); + $this->_initializeStore($storeId); + $entityType = $this->getEntityType($entityType); - /** - * Try use loaded attribute - */ - $attribute = $this->_load($attributeKey); - if ($attribute) { - Varien_Profiler::stop('EAV: ' . __METHOD__); - return $attribute; + // lookup id by code + if (!is_numeric($code) && isset($this->_entityTypeAttributeIdByCode[$storeId][$entityType->getId()][$code])) { + $code = $this->_entityTypeAttributeIdByCode[$storeId][$entityType->getId()][$code]; } - if (isset($this->_attributeData[$entityTypeCode][$code])) { - $data = $this->_attributeData[$entityTypeCode][$code]; - unset($this->_attributeData[$entityTypeCode][$code]); - $attribute = Mage::getModel($data['attribute_model'], $data); - } else { - if (is_numeric($code)) { - /** @var Mage_Eav_Model_Entity_Attribute_Abstract $attribute */ - $attribute = Mage::getModel($entityType->getAttributeModel())->load($code); - if ($attribute->getEntityTypeId() != $entityType->getId()) { - return false; - } - $attributeKey = $this->_getAttributeKey($entityTypeCode, $attribute->getAttributeCode()); + // get model + $attribute = null; + if (isset($this->_entityTypeAttributes[$storeId][$entityType->getId()][$code])) { + $attributeData = $this->_entityTypeAttributes[$storeId][$entityType->getId()][$code]; + if (is_array($attributeData)) { + $attribute = $this->_hydrateAttribute($attributeData); + $this->_entityTypeAttributes[$storeId][$entityType->getId()][$attribute->getId()] = $attribute; } else { - $attribute = Mage::getModel($entityType->getAttributeModel()) - ->loadByCode($entityType, $code) - ->setAttributeCode($code); + $attribute = $attributeData; } + } else { + $attribute = $this->_getDefaultAttributeIfExists($entityType, $code, $storeId); } - if ($attribute) { - $entity = $entityType->getEntity(); - if ($entity && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes())) { - $attribute->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC) - ->setIsGlobal(1); - } - $attribute->setEntityType($entityType) - ->setEntityTypeId($entityType->getId()); - $this->_addAttributeReference($attribute->getId(), $attribute->getAttributeCode(), $entityTypeCode); - $this->_save($attribute, $attributeKey); + return $attribute; + } + + /** + * @param mixed $entityType + * @return Mage_Eav_Model_Entity_Attribute_Abstract[] + */ + public function getAttributes($entityType) + { + Varien_Profiler::start('EAV: ' . __METHOD__); + + $entityType = $this->getEntityType($entityType); + $attributes = []; + $storeId = $this->_storeId(); + // need to access attributes to ensure they are hydrated and initialized + foreach (array_keys($this->_entityTypeAttributes[$storeId][$entityType->getId()]) as $attributeId) { + $attributes[] = $this->getAttribute($entityType, $attributeId, $storeId); } + Varien_Profiler::stop('EAV: ' . __METHOD__); - return $attribute; + return $attributes; } /** * Get codes of all entity type attributes * - * @param Mage_Eav_Model_Entity_Type $entityType - * @param Varien_Object $object + * @param Mage_Eav_Model_Entity_Type $entityType + * @param Varien_Object $object * @return array */ public function getEntityAttributeCodes($entityType, $object = null) { - $entityType = $this->getEntityType($entityType); + $entityType = $this->getEntityType($entityType); $attributeSetId = 0; if (($object instanceof Varien_Object) && $object->getAttributeSetId()) { $attributeSetId = $object->getAttributeSetId(); } - $storeId = 0; + + // Technically store id is irrelevant for attribute sets, they are the same in all store scopes. + // Use current store id when not specified to avoid loading two store-scope attribute data sets from cache + $storeId = $this->_storeId(); if (($object instanceof Varien_Object) && $object->getStoreId()) { $storeId = $object->getStoreId(); } - $cacheKey = sprintf('%d-%d', $entityType->getId(), $attributeSetId); - if (isset($this->_attributeCodes[$cacheKey])) { - return $this->_attributeCodes[$cacheKey]; - } + $this->_initializeStore($storeId); if ($attributeSetId) { - /** @var Mage_Eav_Model_Resource_Entity_Attribute_Collection $attributesInfo */ - $attributesInfo = Mage::getResourceModel($entityType->getEntityAttributeCollection()); - $attributesInfo - ->setEntityTypeFilter($entityType) - ->setAttributeSetFilter($attributeSetId) - ->addStoreLabel($storeId); - $attributesInfoData = $attributesInfo->getData(); - $attributes = []; - foreach ($attributesInfoData as $attributeData) { - $attributes[] = $attributeData['attribute_code']; - $this->_createAttribute($entityType, $attributeData); + $attributeIds = $this->getAttributeSetAttributeIds($attributeSetId); + $attributeCodes = []; + foreach ($attributeIds as $attributeId) { + $attribute = $this->getAttribute($entityType, $attributeId, $storeId); + // need to verify attribute actually exists to avoid problems with deleted attributes that left behind some remnants + if ($attribute) { + $attributeCodes[] = $attribute->getAttributeCode(); + } } + return $attributeCodes; } else { - $this->_initAttributes($entityType); - $attributes = $this->getEntityType($entityType)->getAttributeCodes(); + return array_keys($this->_entityTypeAttributeIdByCode[$storeId][$entityType->getId()]); } - - $this->_attributeCodes[$cacheKey] = $attributes; - - return $attributes; } /** - * Preload entity type attributes for performance optimization - * - * @param mixed $entityType - * @param mixed $attributes - * @return Mage_Eav_Model_Config + * @param int|int[] $attributeSetId + * @return int[] + * @throws Mage_Core_Model_Store_Exception */ - public function preloadAttributes($entityType, $attributes) + public function getAttributeSetAttributeIds($attributeSetId) { - if (is_string($attributes)) { - $attributes = [$attributes]; - } - - $entityType = $this->getEntityType($entityType); - $entityTypeCode = $entityType->getEntityTypeCode(); - - if (!isset($this->_preloadedAttributes[$entityTypeCode])) { - $this->_preloadedAttributes[$entityTypeCode] = $attributes; - } else { - $attributes = array_diff($attributes, $this->_preloadedAttributes[$entityTypeCode]); - $this->_preloadedAttributes[$entityTypeCode] = array_merge( - $this->_preloadedAttributes[$entityTypeCode], - $attributes - ); - } - - if (empty($attributes)) { - return $this; - } - Varien_Profiler::start('EAV: ' . __METHOD__ . ':' . $entityTypeCode); - - /** @var Mage_Eav_Model_Resource_Entity_Attribute_Collection $attributesInfo */ - $attributesInfo = Mage::getResourceModel($entityType->getEntityAttributeCollection()); - $attributesInfo - ->setEntityTypeFilter($entityType) - ->setCodeFilter($attributes); - $attributesInfoData = $attributesInfo->getData(); - - if (!$attributesInfoData) { - Varien_Profiler::stop('EAV: ' . __METHOD__ . ':' . $entityTypeCode); - return $this; + if (!is_array($attributeSetId)) { + $attributeSetId = [$attributeSetId]; } - $attributesData = $codes = []; + $attributes = []; - foreach ($attributesInfoData as $attribute) { - if (empty($attribute['attribute_model'])) { - $attribute['attribute_model'] = $entityType->getAttributeModel(); + foreach ($attributeSetId as $setId) { + foreach ($this->_attributeSetInfo as $attributeId => $sets) { + if (isset($sets[$setId])) { + $attributes[$attributeId] = true; + } } - - $attributeCode = $attribute['attribute_code']; - $attributeId = $attribute['attribute_id']; - - $this->_addAttributeReference($attributeId, $attributeCode, $entityTypeCode); - $attributesData[$attributeCode] = $attribute; - $codes[] = $attributeCode; } - $this->_attributeData[$entityTypeCode] = $attributesData; - Varien_Profiler::stop('EAV: ' . __METHOD__ . ':' . $entityTypeCode); - return $this; + return array_keys($attributes); } /** - * Get attribute object for colection usage - * - * @param mixed $entityType - * @param string $attribute + * @param mixed $entityType + * @param string $attribute * @return Mage_Eav_Model_Entity_Attribute_Abstract|null + * @deprecated Equivalent to getAttribute(...), use getAttribute(...) instead + * Get attribute object for collection usage + * */ public function getCollectionAttribute($entityType, $attribute) { - $entityType = $this->getEntityType($entityType); - $entityTypeCode = $entityType->getEntityTypeCode(); - - if (is_numeric($attribute)) { - $attribute = $this->_getAttributeReference($attribute, $entityTypeCode); - if (!$attribute) { - return null; - } - } - - $attributeKey = $this->_getAttributeKey($entityTypeCode, $attribute); - $attributeObject = $this->_load($attributeKey); - if ($attributeObject) { - return $attributeObject; - } - return $this->getAttribute($entityType, $attribute); } /** + * @param mixed $entityType + * @param array $attributes + * @return Mage_Eav_Model_Config + * @deprecated No longer required to preload only collection attributes explicitly * Prepare attributes for usage in EAV collection * - * @param mixed $entityType - * @param array $attributes - * @return Mage_Eav_Model_Config */ public function loadCollectionAttributes($entityType, $attributes) { - $entityType = $this->getEntityType($entityType); - $entityTypeCode = $entityType->getEntityTypeCode(); - - if (!isset($this->_collectionAttributes[$entityTypeCode])) { - $this->_collectionAttributes[$entityTypeCode] = []; - } - $loadedAttributes = array_keys($this->_collectionAttributes[$entityTypeCode]); - $attributes = array_diff($attributes, $loadedAttributes); - - foreach ($attributes as $k => $attribute) { - if (is_numeric($attribute)) { - $attribute = $this->_getAttributeReference($attribute, $entityTypeCode); - } - $attributeKey = $this->_getAttributeKey($entityTypeCode, $attribute); - if ($this->_load($attributeKey)) { - unset($attributes[$k]); - } - } - - if (empty($attributes)) { - return $this; - } - $attributeCollection = $entityType->getEntityAttributeCollection(); - /** @var Mage_Eav_Model_Resource_Entity_Attribute_Collection $attributesInfo */ - $attributesInfo = Mage::getResourceModel($attributeCollection); - $attributesInfo - ->useLoadDataFields() - ->setEntityTypeFilter($entityType) - ->setCodeFilter($attributes); - $attributesInfoData = $attributesInfo->getData(); - - foreach ($attributesInfoData as $attributeData) { - $attribute = $this->_createAttribute($entityType, $attributeData); - $this->_collectionAttributes[$entityTypeCode][$attribute->getAttributeCode()] = $attribute; - } - return $this; } /** - * Create attribute from attribute data array - * - * @param string $entityType - * @param array $attributeData - * @return false|Mage_Core_Model_Abstract - */ - protected function _createAttribute($entityType, $attributeData) - { - $entityType = $this->getEntityType($entityType); - $entityTypeCode = $entityType->getEntityTypeCode(); - - $attributeKey = $this->_getAttributeKey($entityTypeCode, $attributeData['attribute_code']); - $attribute = $this->_load($attributeKey); - if ($attribute) { - $existsFullAttribute = $attribute->hasIsRequired(); - $fullAttributeData = array_key_exists('is_required', $attributeData); - - if ($existsFullAttribute || (!$existsFullAttribute && !$fullAttributeData)) { - return $attribute; - } - } - - if (!empty($attributeData['attribute_model'])) { - $model = $attributeData['attribute_model']; - } else { - $model = $entityType->getAttributeModel(); - } - $attribute = Mage::getModel($model)->setData($attributeData); - $this->_addAttributeReference( - $attributeData['attribute_id'], - $attributeData['attribute_code'], - $entityTypeCode - ); - $attributeKey = $this->_getAttributeKey($entityTypeCode, $attributeData['attribute_code']); - $this->_save($attribute, $attributeKey); - - return $attribute; - } - - /** - * Validate attribute data from import - * - * @param array $attributeData - * @return bool - */ - protected function _validateAttributeData($attributeData = null) - { - if (!is_array($attributeData)) { - return false; - } - $requiredKeys = [ - 'attribute_id', - 'attribute_code', - 'entity_type_id', - 'attribute_model' - ]; - foreach ($requiredKeys as $key) { - if (!array_key_exists($key, $attributeData)) { - return false; - } - } - - return true; - } - - /** - * Import attributes data from external source - * * @param string|Mage_Eav_Model_Entity_Type $entityType * @param array $attributes * @return $this + * @deprecated No longer required. All attribute data is cached on-access. */ public function importAttributesData($entityType, array $attributes) { - $entityType = $this->getEntityType($entityType); - foreach ($attributes as $attributeData) { - if (!$this->_validateAttributeData($attributeData)) { - continue; - } - $this->_createAttribute($entityType, $attributeData); - } - return $this; } } diff --git a/app/code/core/Mage/Eav/Model/Entity/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Abstract.php index 463fca82918..84dda689dd1 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Abstract.php @@ -372,7 +372,7 @@ public function getAttribute($attribute) } $attributeInstance = Mage::getSingleton('eav/config') ->getAttribute($this->getEntityType(), $attributeCode); - if (!$attributeInstance->getAttributeCode() && in_array($attribute, $this->getDefaultAttributes())) { + if ($attributeInstance && !$attributeInstance->getAttributeCode() && in_array($attribute, $this->getDefaultAttributes())) { $attributeInstance ->setAttributeCode($attribute) ->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC) diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php index 3604bf150e9..57992cedc6d 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php @@ -57,6 +57,7 @@ * @method string getStoreLabel() * @method string getUsedForSortBy() * @method array getValidateRules() + * @method Mage_Eav_Model_Resource_Entity_Attribute _getResource() */ abstract class Mage_Eav_Model_Entity_Attribute_Abstract extends Mage_Core_Model_Abstract implements Mage_Eav_Model_Entity_Attribute_Interface { @@ -133,18 +134,23 @@ protected function _construct() public function loadByCode($entityType, $code) { Varien_Profiler::start('_LOAD_ATTRIBUTE_BY_CODE__'); - if (is_numeric($entityType)) { - $entityTypeId = $entityType; - } elseif (is_string($entityType)) { - $entityType = Mage::getModel('eav/entity_type')->loadByCode($entityType); - } - if ($entityType instanceof Mage_Eav_Model_Entity_Type) { - $entityTypeId = $entityType->getId(); - } - if (empty($entityTypeId)) { - throw Mage::exception('Mage_Eav', Mage::helper('eav')->__('Invalid entity supplied.')); + $model = Mage::getSingleton('eav/config')->getAttribute($entityType, $code); + if ($model) { + $this->setData($model->getData()); + } else { + if (is_numeric($entityType)) { + $entityTypeId = $entityType; + } elseif (is_string($entityType)) { + $entityType = Mage::getSingleton('eav/config')->getEntityType($entityType); + } + if ($entityType instanceof Mage_Eav_Model_Entity_Type) { + $entityTypeId = $entityType->getId(); + } + if (empty($entityTypeId)) { + throw Mage::exception('Mage_Eav', Mage::helper('eav')->__('Invalid entity supplied.')); + } + $this->_getResource()->loadByCode($this, $entityTypeId, $code); } - $this->_getResource()->loadByCode($this, $entityTypeId, $code); $this->_afterLoad(); Varien_Profiler::stop('_LOAD_ATTRIBUTE_BY_CODE__'); return $this; @@ -191,7 +197,7 @@ public function setAttributeId($data) } /** - * Get attribute identifuer + * Get attribute identifier * * @return int|null */ diff --git a/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php index 94bee878a77..c6ff2e91992 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php @@ -417,7 +417,6 @@ protected function _prepareOrderExpression($field) public function addAttributeToSelect($attribute, $joinType = false) { if (is_array($attribute)) { - Mage::getSingleton('eav/config')->loadCollectionAttributes($this->getEntity()->getType(), $attribute); foreach ($attribute as $a) { $this->addAttributeToSelect($a, $joinType); } @@ -438,7 +437,7 @@ public function addAttributeToSelect($attribute, $joinType = false) $attrInstance = $this->_joinAttributes[$attribute]['attribute']; } else { $attrInstance = Mage::getSingleton('eav/config') - ->getCollectionAttribute($this->getEntity()->getType(), $attribute); + ->getAttribute($this->getEntity()->getType(), $attribute); } if (empty($attrInstance)) { throw Mage::exception( @@ -1098,7 +1097,7 @@ public function _loadAttributes($printQuery = false, $logQuery = false) if (!$attributeId) { continue; } - $attribute = Mage::getSingleton('eav/config')->getCollectionAttribute($entity->getType(), $attributeCode); + $attribute = Mage::getSingleton('eav/config')->getAttribute($entity->getType(), $attributeCode); if ($attribute && !$attribute->isStatic()) { $tableAttributes[$attribute->getBackendTable()][] = $attributeId; if (!isset($attributeTypes[$attribute->getBackendTable()])) { @@ -1205,7 +1204,7 @@ protected function _setItemAttributeValue($valueInfo) } $attributeCode = array_search($valueInfo['attribute_id'], $this->_selectAttributes); if (!$attributeCode) { - $attribute = Mage::getSingleton('eav/config')->getCollectionAttribute( + $attribute = Mage::getSingleton('eav/config')->getAttribute( $this->getEntity()->getType(), $valueInfo['attribute_id'] ); diff --git a/app/code/core/Mage/Eav/Model/Observer.php b/app/code/core/Mage/Eav/Model/Observer.php new file mode 100644 index 00000000000..708ebf24bf6 --- /dev/null +++ b/app/code/core/Mage/Eav/Model/Observer.php @@ -0,0 +1,45 @@ +getData('controller_action'); + + // initialize cached store_id for frontend controllers only to avoid issues with cron jobs and admin controllers which sometimes change store view + if ($controllerAction instanceof Mage_Core_Controller_Front_Action) { + Mage::getSingleton('eav/config')->setCurrentStoreId(Mage::app()->getStore()->getId()); + } + } +} diff --git a/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Collection.php b/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Collection.php index df60f2bedb0..f5738d498bc 100644 --- a/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Collection.php +++ b/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Collection.php @@ -41,6 +41,13 @@ class Mage_Eav_Model_Resource_Entity_Attribute_Collection extends Mage_Core_Mode */ protected $_addSetInfoFlag = false; + /** + * Tracks if addStoreLabel has been called to avoid conflicts on duplicate calls + * + * @var bool|int + */ + protected $_addedStoreLabelsFlag = false; + /** * Resource model initialization * @@ -418,14 +425,21 @@ public function setCodeFilter($code) */ public function addStoreLabel($storeId) { - $adapter = $this->getConnection(); - $joinExpression = $adapter - ->quoteInto('al.attribute_id = main_table.attribute_id AND al.store_id = ?', (int) $storeId); - $this->getSelect()->joinLeft( - ['al' => $this->getTable('eav/attribute_label')], - $joinExpression, - ['store_label' => $adapter->getIfNullSql('al.value', 'main_table.frontend_label')] - ); + // if not called previously + if ($this->_addedStoreLabelsFlag === false) { + $adapter = $this->getConnection(); + $joinExpression = $adapter + ->quoteInto('al.attribute_id = main_table.attribute_id AND al.store_id = ?', (int)$storeId); + $this->getSelect()->joinLeft( + ['al' => $this->getTable('eav/attribute_label')], + $joinExpression, + ['store_label' => $adapter->getIfNullSql('al.value', 'main_table.frontend_label')] + ); + $this->_addedStoreLabelsFlag = $storeId; + } // check that previous call $storeId matches current call + elseif ($this->_addedStoreLabelsFlag !== $storeId) { + throw new Exception('Cannot call addStoreLabel for different store views on the same collection'); + } return $this; } diff --git a/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Set.php b/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Set.php index 4dce913fdd8..e22a4768312 100644 --- a/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Set.php +++ b/app/code/core/Mage/Eav/Model/Resource/Entity/Attribute/Set.php @@ -96,46 +96,50 @@ public function validate($object, $attributeSetName) * Retrieve Set info by attributes * * @param array $attributeIds - * @param int $setId + * @param int|null $setId * @return array */ - public function getSetInfo(array $attributeIds, $setId = null) + public function getSetInfo(array $attributeIds = [], $setId = null) { $adapter = $this->_getReadAdapter(); $setInfo = []; $attributeToSetInfo = []; + $select = $adapter->select() + ->from( + ['entity' => $this->getTable('eav/entity_attribute')], + ['attribute_id', 'attribute_set_id', 'attribute_group_id', 'sort_order'] + ) + ->joinLeft( + ['attribute_group' => $this->getTable('eav/attribute_group')], + 'entity.attribute_group_id = attribute_group.attribute_group_id', + ['group_sort_order' => 'sort_order'] + ); if (count($attributeIds) > 0) { - $select = $adapter->select() - ->from( - ['entity' => $this->getTable('eav/entity_attribute')], - ['attribute_id', 'attribute_set_id', 'attribute_group_id', 'sort_order'] - ) - ->joinLeft( - ['attribute_group' => $this->getTable('eav/attribute_group')], - 'entity.attribute_group_id = attribute_group.attribute_group_id', - ['group_sort_order' => 'sort_order'] - ) - ->where('entity.attribute_id IN (?)', $attributeIds); - $bind = []; - if (is_numeric($setId)) { - $bind[':attribute_set_id'] = $setId; - $select->where('entity.attribute_set_id = :attribute_set_id'); - } - $result = $adapter->fetchAll($select, $bind); + $select->where('entity.attribute_id IN (?)', $attributeIds); + } + $bind = []; + if (is_numeric($setId)) { + $bind[':attribute_set_id'] = $setId; + $select->where('entity.attribute_set_id = :attribute_set_id'); + } + $result = $adapter->fetchAll($select, $bind); - foreach ($result as $row) { - $data = [ - 'group_id' => $row['attribute_group_id'], - 'group_sort' => $row['group_sort_order'], - 'sort' => $row['sort_order'] - ]; - $attributeToSetInfo[$row['attribute_id']][$row['attribute_set_id']] = $data; - } + foreach ($result as $row) { + $data = [ + 'group_id' => $row['attribute_group_id'], + 'group_sort' => $row['group_sort_order'], + 'sort' => $row['sort_order'] + ]; + $attributeToSetInfo[$row['attribute_id']][$row['attribute_set_id']] = $data; } - foreach ($attributeIds as $atttibuteId) { - $setInfo[$atttibuteId] = $attributeToSetInfo[$atttibuteId] ?? []; + if (count($attributeIds)) { + foreach ($attributeIds as $atttibuteId) { + $setInfo[$atttibuteId] = $attributeToSetInfo[$atttibuteId] ?? []; + } + } else { + return $attributeToSetInfo; } return $setInfo; diff --git a/app/code/core/Mage/Eav/etc/config.xml b/app/code/core/Mage/Eav/etc/config.xml index 0a69d58c67f..1d0518aae4a 100644 --- a/app/code/core/Mage/Eav/etc/config.xml +++ b/app/code/core/Mage/Eav/etc/config.xml @@ -108,6 +108,16 @@ + + + + + eav/observer + onControllerActionPredispatch + + + + diff --git a/app/code/core/Mage/Sales/Model/Entity/Quote.php b/app/code/core/Mage/Sales/Model/Entity/Quote.php index 6cf0cc1b8f2..dec7bbc5d44 100644 --- a/app/code/core/Mage/Sales/Model/Entity/Quote.php +++ b/app/code/core/Mage/Sales/Model/Entity/Quote.php @@ -116,6 +116,6 @@ public function loadByIdWithoutStore($quote, $quoteId) */ public function getReservedOrderId($quote) { - return Mage::getSingleton('eav/config')->getEntityType('order')->fetchNewIncrementId($quote->getStoreId()); + return Mage::getSingleton('eav/config')->getEntityType(Mage_Sales_Model_Order::ENTITY)->fetchNewIncrementId($quote->getStoreId()); } } diff --git a/app/code/core/Mage/Sales/Model/Resource/Order/Abstract.php b/app/code/core/Mage/Sales/Model/Resource/Order/Abstract.php index 6836603f48c..e4ced9b47ab 100644 --- a/app/code/core/Mage/Sales/Model/Resource/Order/Abstract.php +++ b/app/code/core/Mage/Sales/Model/Resource/Order/Abstract.php @@ -363,7 +363,7 @@ protected function _beforeSave(Mage_Core_Model_Abstract $object) { if ($this->_useIncrementId && !$object->getIncrementId()) { /** @var Mage_Eav_Model_Entity_Type $entityType */ - $entityType = Mage::getModel('eav/entity_type')->loadByCode($this->_entityTypeForIncrementId); + $entityType = Mage::getSingleton('eav/config')->getEntityType($this->_entityTypeForIncrementId); $object->setIncrementId($entityType->fetchNewIncrementId($object->getStoreId())); } parent::_beforeSave($object); diff --git a/app/code/core/Mage/Tax/Helper/Data.php b/app/code/core/Mage/Tax/Helper/Data.php index 308dced7f9e..b686152e4b4 100644 --- a/app/code/core/Mage/Tax/Helper/Data.php +++ b/app/code/core/Mage/Tax/Helper/Data.php @@ -877,8 +877,8 @@ public function getPriceTaxSql($priceField, $taxClassField) */ public function joinTaxClass($select, $storeId, $priceTable = 'main_table') { - $taxClassAttribute = Mage::getModel('eav/entity_attribute') - ->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'tax_class_id'); + $taxClassAttribute = Mage::getSingleton('eav/config') + ->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'tax_class_id'); $joinConditionD = implode(' AND ', [ "tax_class_d.entity_id = {$priceTable}.entity_id", $select->getAdapter()->quoteInto('tax_class_d.attribute_id = ?', (int)$taxClassAttribute->getId()), diff --git a/phpstan.dist.baseline.neon b/phpstan.dist.baseline.neon index 15cdb3bfd1f..81276db8a49 100644 --- a/phpstan.dist.baseline.neon +++ b/phpstan.dist.baseline.neon @@ -1995,11 +1995,6 @@ parameters: count: 1 path: app/code/core/Mage/Catalog/Model/Factory.php - - - message: "#^Comparison operation \"\\=\\=\" between Mage_Catalog_Model_Resource_Eav_Attribute and 1 results in an error\\.$#" - count: 1 - path: app/code/core/Mage/Catalog/Model/Layer/Filter/Attribute.php - - message: "#^Parameter \\#2 \\$filterBlock \\(Varien_Object\\) of method Mage_Catalog_Model_Layer_Filter_Attribute\\:\\:apply\\(\\) should be compatible with parameter \\$filterBlock \\(null\\) of method Mage_Catalog_Model_Layer_Filter_Abstract\\:\\:apply\\(\\)$#" count: 1 @@ -2270,11 +2265,6 @@ parameters: count: 1 path: app/code/core/Mage/Catalog/Model/Resource/Category.php - - - message: "#^Property Mage_Catalog_Model_Resource_Category\\:\\:\\$_isActiveAttributeId \\(int\\) does not accept string\\|false\\|null\\.$#" - count: 1 - path: app/code/core/Mage/Catalog/Model/Resource/Category.php - - message: "#^Property Mage_Catalog_Model_Resource_Category\\:\\:\\$_storeId \\(int\\) on left side of \\?\\? is not nullable\\.$#" count: 1 @@ -2700,11 +2690,6 @@ parameters: count: 1 path: app/code/core/Mage/CatalogSearch/Model/Advanced.php - - - message: "#^Return type \\(bool\\) of method Mage_CatalogSearch_Model_Layer_Filter_Attribute\\:\\:_getIsFilterableAttribute\\(\\) should be compatible with return type \\(Mage_Catalog_Model_Resource_Eav_Attribute\\) of method Mage_Catalog_Model_Layer_Filter_Attribute\\:\\:_getIsFilterableAttribute\\(\\)$#" - count: 1 - path: app/code/core/Mage/CatalogSearch/Model/Layer/Filter/Attribute.php - - message: "#^Call to function is_array\\(\\) with bool\\|string will always evaluate to false\\.$#" count: 1 @@ -4150,16 +4135,6 @@ parameters: count: 1 path: app/code/core/Mage/Directory/Model/Resource/Country/Collection.php - - - message: "#^Method Mage_Downloadable_Block_Adminhtml_Catalog_Product_Edit_Tab_Downloadable_Links\\:\\:getPurchasedSeparatelyAttribute\\(\\) should return Mage_Catalog_Model_Resource_Eav_Attribute but returns Mage_Eav_Model_Entity_Attribute\\.$#" - count: 1 - path: app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php - - - - message: "#^Property Mage_Downloadable_Block_Adminhtml_Catalog_Product_Edit_Tab_Downloadable_Links\\:\\:\\$_purchasedSeparatelyAttribute \\(Mage_Catalog_Model_Resource_Eav_Attribute\\|null\\) does not accept Mage_Eav_Model_Entity_Attribute\\.$#" - count: 1 - path: app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php - - message: "#^Left side of && is always true\\.$#" count: 1 @@ -4270,26 +4245,11 @@ parameters: count: 1 path: app/code/core/Mage/Eav/Model/Config.php - - - message: "#^Cannot call method loadByCode\\(\\) on Mage_Core_Model_Abstract\\|false\\.$#" - count: 1 - path: app/code/core/Mage/Eav/Model/Config.php - - - - message: "#^Left side of && is always true\\.$#" - count: 1 - path: app/code/core/Mage/Eav/Model/Config.php - - message: "#^Method Mage_Eav_Model_Config\\:\\:getAttribute\\(\\) should return Mage_Eav_Model_Entity_Attribute_Abstract\\|false but returns Mage_Eav_Model_Entity_Attribute_Interface\\.$#" count: 1 path: app/code/core/Mage/Eav/Model/Config.php - - - message: "#^Negated boolean expression is always true\\.$#" - count: 1 - path: app/code/core/Mage/Eav/Model/Config.php - - message: "#^Method Mage_Eav_Model_Convert_Adapter_Entity\\:\\:_getCollectionForLoad\\(\\) should return Mage_Eav_Model_Entity_Collection but returns Mage_Core_Model_Resource_Db_Collection_Abstract\\|false\\.$#" count: 1