123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework\Model;
- use Magento\Framework\Api\AttributeValueFactory;
- use Magento\Framework\Api\ExtensionAttributesFactory;
- /**
- * Abstract model with custom attributes support.
- *
- * This class defines basic data structure of how custom attributes are stored in an ExtensibleModel.
- * Implementations may choose to process custom attributes as their persistence requires them to.
- * @SuppressWarnings(PHPMD.NumberOfChildren)
- */
- abstract class AbstractExtensibleModel extends AbstractModel implements
- \Magento\Framework\Api\CustomAttributesDataInterface
- {
- /**
- * @var ExtensionAttributesFactory
- */
- protected $extensionAttributesFactory;
- /**
- * @var \Magento\Framework\Api\ExtensionAttributesInterface
- */
- protected $extensionAttributes;
- /**
- * @var AttributeValueFactory
- */
- protected $customAttributeFactory;
- /**
- * @var string[]
- */
- protected $customAttributesCodes = null;
- /**
- * @var bool
- */
- protected $customAttributesChanged = false;
- /**
- * @param \Magento\Framework\Model\Context $context
- * @param \Magento\Framework\Registry $registry
- * @param ExtensionAttributesFactory $extensionFactory
- * @param AttributeValueFactory $customAttributeFactory
- * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
- * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
- * @param array $data
- */
- public function __construct(
- \Magento\Framework\Model\Context $context,
- \Magento\Framework\Registry $registry,
- ExtensionAttributesFactory $extensionFactory,
- AttributeValueFactory $customAttributeFactory,
- \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
- \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
- array $data = []
- ) {
- $this->extensionAttributesFactory = $extensionFactory;
- $this->customAttributeFactory = $customAttributeFactory;
- $data = $this->filterCustomAttributes($data);
- parent::__construct($context, $registry, $resource, $resourceCollection, $data);
- if (isset($data['id'])) {
- $this->setId($data['id']);
- }
- if (isset($data[self::EXTENSION_ATTRIBUTES_KEY]) && is_array($data[self::EXTENSION_ATTRIBUTES_KEY])) {
- $this->populateExtensionAttributes($data[self::EXTENSION_ATTRIBUTES_KEY]);
- }
- }
- /**
- * Verify custom attributes set on $data and unset if not a valid custom attribute
- *
- * @param array $data
- * @return array processed data
- */
- protected function filterCustomAttributes($data)
- {
- if (empty($data[self::CUSTOM_ATTRIBUTES])) {
- return $data;
- }
- $customAttributesCodes = $this->getCustomAttributesCodes();
- $data[self::CUSTOM_ATTRIBUTES] = array_intersect_key(
- (array)$data[self::CUSTOM_ATTRIBUTES],
- array_flip($customAttributesCodes)
- );
- foreach ($data[self::CUSTOM_ATTRIBUTES] as $code => $value) {
- if (!($value instanceof \Magento\Framework\Api\AttributeInterface)) {
- $data[self::CUSTOM_ATTRIBUTES][$code] = $this->customAttributeFactory->create()
- ->setAttributeCode($code)
- ->setValue($value);
- }
- }
- return $data;
- }
- /**
- * Initialize customAttributes based on existing data
- *
- * @return $this
- */
- protected function initializeCustomAttributes()
- {
- if (!isset($this->_data[self::CUSTOM_ATTRIBUTES]) || $this->customAttributesChanged) {
- if (!empty($this->_data[self::CUSTOM_ATTRIBUTES])) {
- $customAttributes = $this->_data[self::CUSTOM_ATTRIBUTES];
- } else {
- $customAttributes = [];
- }
- $customAttributeCodes = $this->getCustomAttributesCodes();
- foreach ($customAttributeCodes as $customAttributeCode) {
- if (isset($this->_data[self::CUSTOM_ATTRIBUTES][$customAttributeCode])) {
- $customAttribute = $this->customAttributeFactory->create()
- ->setAttributeCode($customAttributeCode)
- ->setValue($this->_data[self::CUSTOM_ATTRIBUTES][$customAttributeCode]->getValue());
- $customAttributes[$customAttributeCode] = $customAttribute;
- } elseif (isset($this->_data[$customAttributeCode])) {
- $customAttribute = $this->customAttributeFactory->create()
- ->setAttributeCode($customAttributeCode)
- ->setValue($this->_data[$customAttributeCode]);
- $customAttributes[$customAttributeCode] = $customAttribute;
- }
- }
- $this->_data[self::CUSTOM_ATTRIBUTES] = $customAttributes;
- $this->customAttributesChanged = false;
- }
- }
- /**
- * Retrieve custom attributes values.
- *
- * @return \Magento\Framework\Api\AttributeInterface[]|null
- */
- public function getCustomAttributes()
- {
- $this->initializeCustomAttributes();
- // Returning as a sequential array (instead of stored associative array) to be compatible with the interface
- return array_values($this->_data[self::CUSTOM_ATTRIBUTES]);
- }
- /**
- * Get an attribute value.
- *
- * @param string $attributeCode
- * @return \Magento\Framework\Api\AttributeInterface|null null if the attribute has not been set
- */
- public function getCustomAttribute($attributeCode)
- {
- $this->initializeCustomAttributes();
- return $this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode] ?? null;
- }
- /**
- * {@inheritdoc}
- */
- public function setCustomAttributes(array $attributes)
- {
- return $this->setData(self::CUSTOM_ATTRIBUTES, $attributes);
- }
- /**
- * {@inheritdoc}
- */
- public function setCustomAttribute($attributeCode, $attributeValue)
- {
- $customAttributesCodes = $this->getCustomAttributesCodes();
- /* If key corresponds to custom attribute code, populate custom attributes */
- if (in_array($attributeCode, $customAttributesCodes)) {
- $attribute = $this->customAttributeFactory->create();
- $attribute->setAttributeCode($attributeCode)
- ->setValue($attributeValue);
- $this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode] = $attribute;
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- *
- * Added custom attributes support.
- */
- public function setData($key, $value = null)
- {
- if (is_array($key)) {
- $key = $this->filterCustomAttributes($key);
- } elseif ($key == self::CUSTOM_ATTRIBUTES) {
- $filteredData = $this->filterCustomAttributes([self::CUSTOM_ATTRIBUTES => $value]);
- $value = $filteredData[self::CUSTOM_ATTRIBUTES];
- }
- $this->customAttributesChanged = true;
- parent::setData($key, $value);
- return $this;
- }
- /**
- * {@inheritdoc}
- *
- * Unset customAttributesChanged flag
- */
- public function unsetData($key = null)
- {
- if (is_string($key) && isset($this->_data[self::CUSTOM_ATTRIBUTES][$key])) {
- unset($this->_data[self::CUSTOM_ATTRIBUTES][$key]);
- }
- return parent::unsetData($key);
- }
- /**
- * Convert custom values if necessary
- *
- * @param array $customAttributes
- * @return void
- */
- protected function convertCustomAttributeValues(array &$customAttributes)
- {
- foreach ($customAttributes as $attributeCode => $attributeValue) {
- if ($attributeValue instanceof \Magento\Framework\Api\AttributeValue) {
- $customAttributes[$attributeCode] = $attributeValue->getValue();
- }
- }
- }
- /**
- * Object data getter
- *
- * If $key is not defined will return all the data as an array.
- * Otherwise it will return value of the element specified by $key.
- * It is possible to use keys like a/b/c for access nested array data
- *
- * If $index is specified it will assume that attribute data is an array
- * and retrieve corresponding member. If data is the string - it will be explode
- * by new line character and converted to array.
- *
- * In addition to parent implementation custom attributes support is added.
- *
- * @param string $key
- * @param string|int $index
- * @return mixed
- */
- public function getData($key = '', $index = null)
- {
- if ($key === self::CUSTOM_ATTRIBUTES) {
- throw new \LogicException("Custom attributes array should be retrieved via getCustomAttributes() only.");
- } elseif ($key === '') {
- /** Represent model data and custom attributes as a flat array */
- $customAttributes = isset($this->_data[self::CUSTOM_ATTRIBUTES])
- ? $this->_data[self::CUSTOM_ATTRIBUTES]
- : [];
- $this->convertCustomAttributeValues($customAttributes);
- $data = array_merge($this->_data, $customAttributes);
- unset($data[self::CUSTOM_ATTRIBUTES]);
- } else {
- $data = parent::getData($key, $index);
- if ($data === null) {
- /** Try to find necessary data in custom attributes */
- $data = isset($this->_data[self::CUSTOM_ATTRIBUTES][$key])
- ? $this->_data[self::CUSTOM_ATTRIBUTES][$key]
- : null;
- if ($data instanceof \Magento\Framework\Api\AttributeValue) {
- $data = $data->getValue();
- }
- if (null !== $index && isset($data[$index])) {
- return $data[$index];
- }
- }
- }
- return $data;
- }
- /**
- * Get a list of custom attribute codes.
- *
- * By default, entity can be extended only using extension attributes functionality.
- *
- * @return string[]
- */
- protected function getCustomAttributesCodes()
- {
- return [];
- }
- /**
- * Receive a list of EAV attributes using provided metadata service.
- *
- * Can be used in child classes, which represent EAV entities.
- *
- * @param \Magento\Framework\Api\MetadataServiceInterface $metadataService
- * @return string[]
- */
- protected function getEavAttributesCodes(\Magento\Framework\Api\MetadataServiceInterface $metadataService)
- {
- $attributeCodes = [];
- $customAttributesMetadata = $metadataService->getCustomAttributesMetadata(get_class($this));
- if (is_array($customAttributesMetadata)) {
- /** @var $attribute \Magento\Framework\Api\MetadataObjectInterface */
- foreach ($customAttributesMetadata as $attribute) {
- $attributeCodes[] = $attribute->getAttributeCode();
- }
- }
- return $attributeCodes;
- }
- /**
- * Identifier setter
- *
- * @param mixed $value
- * @return $this
- */
- public function setId($value)
- {
- parent::setId($value);
- return $this->setData('id', $value);
- }
- /**
- * Set an extension attributes object.
- *
- * @param \Magento\Framework\Api\ExtensionAttributesInterface $extensionAttributes
- * @return $this
- */
- protected function _setExtensionAttributes(\Magento\Framework\Api\ExtensionAttributesInterface $extensionAttributes)
- {
- $this->_data[self::EXTENSION_ATTRIBUTES_KEY] = $extensionAttributes;
- return $this;
- }
- /**
- * Retrieve existing extension attributes object or create a new one.
- *
- * @return \Magento\Framework\Api\ExtensionAttributesInterface
- */
- protected function _getExtensionAttributes()
- {
- if (!$this->getData(self::EXTENSION_ATTRIBUTES_KEY)) {
- $this->populateExtensionAttributes([]);
- }
- return $this->getData(self::EXTENSION_ATTRIBUTES_KEY);
- }
- /**
- * Instantiate extension attributes object and populate it with the provided data.
- *
- * @param array $extensionAttributesData
- * @return void
- */
- private function populateExtensionAttributes(array $extensionAttributesData = [])
- {
- $extensionAttributes = $this->extensionAttributesFactory->create(get_class($this), $extensionAttributesData);
- $this->_setExtensionAttributes($extensionAttributes);
- }
- /**
- * @inheritdoc
- */
- public function __sleep()
- {
- return array_diff(parent::__sleep(), ['extensionAttributesFactory', 'customAttributeFactory']);
- }
- /**
- * @inheritdoc
- */
- public function __wakeup()
- {
- parent::__wakeup();
- $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
- $this->extensionAttributesFactory = $objectManager->get(ExtensionAttributesFactory::class);
- $this->customAttributeFactory = $objectManager->get(AttributeValueFactory::class);
- }
- }
|