123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Eav\Model;
- use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
- use Magento\Eav\Model\Entity\Type;
- use Magento\Framework\App\ObjectManager;
- use Magento\Framework\Serialize\SerializerInterface;
- /**
- * @api
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @since 100.0.2
- */
- class Config
- {
- /**#@+
- * EAV cache ids
- */
- const ENTITIES_CACHE_ID = 'EAV_ENTITY_TYPES';
- const ATTRIBUTES_CACHE_ID = 'EAV_ENTITY_ATTRIBUTES';
- const ATTRIBUTES_CODES_CACHE_ID = 'EAV_ENTITY_ATTRIBUTES_CODES';
- /**#@-*/
- /**#@-*/
- protected $_entityTypeData;
- /**
- * Attributes data
- *
- * @var array
- */
- protected $_attributeData;
- /**
- * Attribute codes cache array
- *
- * @var array
- */
- protected $_attributeCodes;
- /**
- * Initialized objects
- *
- * array ($objectId => $object)
- *
- * @var \Magento\Eav\Model\Entity\Type[]
- */
- protected $_objects;
- /**
- * Initialized attributes
- *
- * array ($entityTypeCode =>
- * ($attributeCode => $object)
- * )
- *
- * @var AbstractAttribute[][]
- */
- private $attributes;
- /**
- * References between codes and identifiers
- *
- * array (
- * 'attributes'=> array ($attributeId => $attributeCode),
- * 'entities' => array ($entityId => $entityCode)
- * )
- *
- * @var array
- */
- protected $_references;
- /**
- * Cache flag
- *
- * @var bool|null
- */
- protected $_isCacheEnabled = null;
- /**
- * @var \Magento\Framework\App\CacheInterface
- */
- protected $_cache;
- /**
- * @var \Magento\Framework\App\Cache\StateInterface
- */
- protected $_cacheState;
- /**
- * @var \Magento\Eav\Model\Entity\TypeFactory
- */
- protected $_entityTypeFactory;
- /**
- * @var \Magento\Eav\Model\ResourceModel\Entity\Type\CollectionFactory
- */
- protected $entityTypeCollectionFactory;
- /**
- * @var \Magento\Framework\Validator\UniversalFactory
- */
- protected $_universalFactory;
- /**
- * @var AbstractAttribute[]
- */
- private $attributeProto = [];
- /**
- * @var SerializerInterface
- */
- private $serializer;
- /**
- * Cache of attributes per set
- *
- * @var array
- */
- private $attributesPerSet = [];
- /**
- * @param \Magento\Framework\App\CacheInterface $cache
- * @param \Magento\Eav\Model\Entity\TypeFactory $entityTypeFactory
- * @param \Magento\Eav\Model\ResourceModel\Entity\Type\CollectionFactory $entityTypeCollectionFactory
- * @param \Magento\Framework\App\Cache\StateInterface $cacheState
- * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
- * @param SerializerInterface $serializer
- * @codeCoverageIgnore
- */
- public function __construct(
- \Magento\Framework\App\CacheInterface $cache,
- \Magento\Eav\Model\Entity\TypeFactory $entityTypeFactory,
- \Magento\Eav\Model\ResourceModel\Entity\Type\CollectionFactory $entityTypeCollectionFactory,
- \Magento\Framework\App\Cache\StateInterface $cacheState,
- \Magento\Framework\Validator\UniversalFactory $universalFactory,
- SerializerInterface $serializer = null
- ) {
- $this->_cache = $cache;
- $this->_entityTypeFactory = $entityTypeFactory;
- $this->entityTypeCollectionFactory = $entityTypeCollectionFactory;
- $this->_cacheState = $cacheState;
- $this->_universalFactory = $universalFactory;
- $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);
- }
- /**
- * Get cache interface
- *
- * @return \Magento\Framework\App\CacheInterface
- * @codeCoverageIgnore
- */
- public function getCache()
- {
- return $this->_cache;
- }
- /**
- * Reset object state
- *
- * @return $this
- */
- public function clear()
- {
- $this->_entityTypeData = null;
- $this->_attributeData = null;
- $this->_objects = null;
- $this->attributes = null;
- $this->_references = null;
- $this->_attributeCodes = null;
- $this->attributesPerSet = [];
- $this->_cache->clean(
- [
- \Magento\Eav\Model\Cache\Type::CACHE_TAG,
- \Magento\Eav\Model\Entity\Attribute::CACHE_TAG,
- ]
- );
- return $this;
- }
- /**
- * Get object by identifier
- *
- * @param mixed $id
- * @return mixed
- */
- protected function _load($id)
- {
- return isset($this->_objects[$id]) ? $this->_objects[$id] : null;
- }
- /**
- * Get attributes by entity type code
- *
- * @param string $entityTypeCode
- * @return AbstractAttribute[]
- */
- private function loadAttributes($entityTypeCode)
- {
- return isset($this->attributes[$entityTypeCode]) ? $this->attributes[$entityTypeCode] : [];
- }
- /**
- * Associate object with identifier
- *
- * @param mixed $obj
- * @param mixed $id
- * @return void
- * @codeCoverageIgnore
- */
- protected function _save($obj, $id)
- {
- $this->_objects[$id] = $obj;
- }
- /**
- * Associate object with identifier
- *
- * @param AbstractAttribute $attribute
- * @param string $entityTypeCode
- * @param string $attributeCode
- * @return void
- */
- private function saveAttribute(AbstractAttribute $attribute, $entityTypeCode, $attributeCode)
- {
- $this->attributes[$entityTypeCode][$attributeCode] = $attribute;
- }
- /**
- * Specify reference for entity type id
- *
- * @param int $id
- * @param string $code
- * @return $this
- * @codeCoverageIgnore
- */
- protected function _addEntityTypeReference($id, $code)
- {
- $this->_references['entity'][$id] = $code;
- return $this;
- }
- /**
- * Get entity type code by id
- *
- * @param int $id
- * @return string
- */
- protected function _getEntityTypeReference($id)
- {
- return isset($this->_references['entity'][$id]) ? $this->_references['entity'][$id] : null;
- }
- /**
- * Specify reference between entity attribute id and attribute code
- *
- * @param int $id
- * @param string $code
- * @param string $entityTypeCode
- * @return $this
- */
- protected function _addAttributeReference($id, $code, $entityTypeCode)
- {
- $this->_references['attribute'][$entityTypeCode][$id] = $code;
- return $this;
- }
- /**
- * Get attribute code by attribute id
- *
- * @param int $id
- * @param string $entityTypeCode
- * @return string|null
- */
- protected function _getAttributeReference($id, $entityTypeCode)
- {
- if (isset($this->_references['attribute'][$entityTypeCode][$id])) {
- return $this->_references['attribute'][$entityTypeCode][$id];
- }
- return null;
- }
- /**
- * Get internal cache key for entity type code
- *
- * @param string $code
- * @return string
- * @codeCoverageIgnore
- */
- protected function _getEntityKey($code)
- {
- return 'ENTITY/' . $code;
- }
- /**
- * Get internal cache key for attribute object cache
- *
- * @param string $entityTypeCode
- * @param string $attributeCode
- * @return string
- * @codeCoverageIgnore
- */
- protected function _getAttributeKey($entityTypeCode, $attributeCode)
- {
- $codeSegments = explode('.', $attributeCode);
- return 'ATTRIBUTE/' . $entityTypeCode . '/' . array_pop($codeSegments);
- }
- /**
- * Check EAV cache availability
- *
- * @return bool
- */
- public function isCacheEnabled()
- {
- if ($this->_isCacheEnabled === null) {
- $this->_isCacheEnabled = $this->_cacheState->isEnabled(\Magento\Eav\Model\Cache\Type::TYPE_IDENTIFIER);
- }
- return $this->_isCacheEnabled;
- }
- /**
- * Initialize all entity types data
- *
- * @return $this
- */
- protected function _initEntityTypes()
- {
- if (is_array($this->_entityTypeData)) {
- return $this;
- }
- \Magento\Framework\Profiler::start('EAV: ' . __METHOD__, ['group' => 'EAV', 'method' => __METHOD__]);
- if ($this->isCacheEnabled() && ($cache = $this->_cache->load(self::ENTITIES_CACHE_ID))) {
- $this->_entityTypeData = $this->serializer->unserialize($cache);
- foreach ($this->_entityTypeData as $typeCode => $data) {
- $typeId = $data['entity_type_id'];
- $this->_addEntityTypeReference($typeId, $typeCode);
- }
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $this;
- }
- $entityTypesData = $this->entityTypeCollectionFactory->create()->getData();
- foreach ($entityTypesData as $typeData) {
- if (!isset($typeData['attribute_model'])) {
- $typeData['attribute_model'] = \Magento\Eav\Model\Entity\Attribute::class;
- }
- $typeCode = $typeData['entity_type_code'];
- $typeId = $typeData['entity_type_id'];
- $this->_addEntityTypeReference($typeId, $typeCode);
- $this->_entityTypeData[$typeCode] = $typeData;
- }
- if ($this->isCacheEnabled()) {
- $this->_cache->save(
- $this->serializer->serialize($this->_entityTypeData),
- self::ENTITIES_CACHE_ID,
- [
- \Magento\Eav\Model\Cache\Type::CACHE_TAG,
- \Magento\Eav\Model\Entity\Attribute::CACHE_TAG
- ]
- );
- }
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $this;
- }
- /**
- * Get entity type object by entity type code/identifier
- *
- * @param int|string|Type $code
- * @return Type
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- public function getEntityType($code)
- {
- if ($code instanceof Type) {
- return $code;
- }
- $this->_initEntityTypes();
- \Magento\Framework\Profiler::start('EAV: ' . __METHOD__, ['group' => 'EAV', 'method' => __METHOD__]);
- if (is_numeric($code)) {
- $entityCode = $this->_getEntityTypeReference($code);
- if ($entityCode !== null) {
- $code = $entityCode;
- }
- }
- $entityKey = $this->_getEntityKey($code);
- $entityType = $this->_load($entityKey);
- if ($entityType) {
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $entityType;
- }
- $entityType = $this->_entityTypeFactory->create(
- ['data' => isset($this->_entityTypeData[$code]) ? $this->_entityTypeData[$code] : []]
- );
- if (!$entityType->getId()) {
- throw new \Magento\Framework\Exception\LocalizedException(__('Invalid entity_type specified: %1', $code));
- }
- $this->_addEntityTypeReference($entityType->getId(), $entityType->getEntityTypeCode());
- $this->_save($entityType, $entityKey);
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $entityType;
- }
- /**
- * Initialize all attributes for entity type
- *
- * @param string $entityType
- * @return $this
- */
- protected function _initAttributes($entityType)
- {
- $entityType = $this->getEntityType($entityType);
- $entityTypeCode = $entityType->getEntityTypeCode();
- if (is_array($this->_attributeData) && isset($this->_attributeData[$entityTypeCode])) {
- return $this;
- }
- if ($this->initAttributesFromCache($entityType)) {
- return $this;
- }
- \Magento\Framework\Profiler::start('EAV: ' . __METHOD__, ['group' => 'EAV', 'method' => __METHOD__]);
- $attributes = $this->_universalFactory->create(
- $entityType->getEntityAttributeCollection()
- )->setEntityTypeFilter(
- $entityType
- )->getData();
- $this->_attributeData[$entityTypeCode] = [];
- foreach ($attributes as $attribute) {
- if (empty($attribute['attribute_model'])) {
- $attribute['attribute_model'] = $entityType->getAttributeModel();
- }
- $attributeObject = $this->_createAttribute($entityType, $attribute);
- $this->saveAttribute($attributeObject, $entityTypeCode, $attributeObject->getAttributeCode());
- $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attributeObject->toArray();
- }
- if ($this->isCacheEnabled()) {
- $this->_cache->save(
- $this->serializer->serialize($this->_attributeData[$entityTypeCode]),
- self::ATTRIBUTES_CACHE_ID . $entityTypeCode,
- [
- \Magento\Eav\Model\Cache\Type::CACHE_TAG,
- \Magento\Eav\Model\Entity\Attribute::CACHE_TAG
- ]
- );
- }
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $this;
- }
- /**
- * Get attributes by entity type
- *
- * @deprecated 101.0.0
- * @see \Magento\Eav\Model\Config::getEntityAttributes
- *
- * @param string $entityType
- * @return AbstractAttribute[]
- * @since 101.0.0
- */
- public function getAttributes($entityType)
- {
- return $this->getEntityAttributes($entityType);
- }
- /**
- * Get attribute by code for entity type
- *
- * @param mixed $entityType
- * @param mixed $code
- * @return AbstractAttribute
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- 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 (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])) {
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $this->attributes[$entityTypeCode][$code];
- }
- $attributes = $this->loadAttributes($entityTypeCode);
- $attribute = isset($attributes[$code]) ? $attributes[$code] : null;
- if (!$attribute) {
- $attribute = $this->createAttributeByAttributeCode($entityType, $code);
- $this->_addAttributeReference(
- $attribute->getAttributeId(),
- $attribute->getAttributeCode(),
- $entityTypeCode
- );
- $this->saveAttribute($attribute, $entityTypeCode, $attribute->getAttributeCode());
- }
- \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
- return $attribute;
- }
- /**
- * Create attribute
- *
- * @param string $model
- * @return Entity\Attribute\AbstractAttribute
- */
- private function createAttribute($model)
- {
- if (!isset($this->attributeProto[$model])) {
- /** @var AbstractAttribute $attribute */
- $this->attributeProto[$model] = $this->_universalFactory->create($model);
- }
- return clone $this->attributeProto[$model];
- }
- /**
- * Get codes of all entity type attributes
- *
- * @deprecated 101.0.0
- * @see \Magento\Eav\Model\Config::getEntityAttributes
- *
- * @param mixed $entityType
- * @param \Magento\Framework\DataObject $object
- * @return string[]
- */
- public function getEntityAttributeCodes($entityType, $object = null)
- {
- return array_keys($this->getEntityAttributes($entityType, $object));
- }
- /**
- * Get all entity type attributes
- *
- * @param int|string|Type $entityType
- * @param \Magento\Framework\DataObject|null $object
- * @return AbstractAttribute[]
- *
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- * @since 101.0.0
- */
- 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;
- }
- $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;
- $attributes = [];
- if ($attributesData === 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($attributesData),
- $cacheKey,
- [
- \Magento\Eav\Model\Cache\Type::CACHE_TAG,
- \Magento\Eav\Model\Entity\Attribute::CACHE_TAG
- ]
- );
- }
- }
- foreach ($attributesData as $attributeData) {
- $attributes[$attributeData['attribute_code']] = $this->_createAttribute($entityType, $attributeData);
- }
- $this->attributesPerSet[$cacheKey] = $attributes;
- return $attributes;
- }
- /**
- * Create attribute from attribute data array
- *
- * @param string $entityType
- * @param array $attributeData
- * @return AbstractAttribute
- */
- protected function _createAttribute($entityType, $attributeData)
- {
- $entityType = $this->getEntityType($entityType);
- $entityTypeCode = $entityType->getEntityTypeCode();
- $code = $attributeData['attribute_code'];
- $attributes = $this->loadAttributes($entityTypeCode);
- $attribute = isset($attributes[$code]) ? $attributes[$code] : null;
- 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();
- }
- /** @var AbstractAttribute $attribute */
- $attribute = $this->createAttribute($model)->setData($attributeData);
- $this->_addAttributeReference(
- $attributeData['attribute_id'],
- $code,
- $entityTypeCode
- );
- $this->saveAttribute($attribute, $entityTypeCode, $code);
- 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|Type $entityType
- * @param array $attributes
- * @return $this
- */
- 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;
- }
- /**
- * Create attribute by attribute code
- *
- * @param string $entityType
- * @param string $attributeCode
- * @return AbstractAttribute
- */
- private function createAttributeByAttributeCode($entityType, $attributeCode)
- {
- $entityType = $this->getEntityType($entityType);
- $attribute = $this->createAttribute($entityType->getAttributeModel());
- 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 instanceof \Magento\Eav\Model\ResourceModel\Attribute\DefaultEntityAttributes\ProviderInterface
- && in_array($attribute->getAttributeCode(), $entity->getDefaultAttributes(), true)
- ) {
- $attribute->setBackendType(AbstractAttribute::TYPE_STATIC)->setIsGlobal(1);
- }
- $attribute->setEntityType($entityType)->setEntityTypeId($entityType->getId());
- return $attribute;
- }
- /**
- * Initialize attributes from cache for given entity type
- *
- * @param Type $entityType
- * @return bool
- */
- private function initAttributesFromCache(Type $entityType)
- {
- $entityTypeCode = $entityType->getEntityTypeCode();
- $cacheKey = self::ATTRIBUTES_CACHE_ID . $entityTypeCode;
- if ($this->isCacheEnabled() && ($attributes = $this->_cache->load($cacheKey))) {
- $attributes = $this->serializer->unserialize($attributes);
- if ($attributes) {
- foreach ($attributes as $attribute) {
- $this->_createAttribute($entityType, $attribute);
- $this->_attributeData[$entityTypeCode][$attribute['attribute_code']] = $attribute;
- }
- return true;
- }
- }
- return false;
- }
- }
|