diff --git a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
index b65cdafbe26f4..b9a23e9d08ec3 100644
--- a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
+++ b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
@@ -14,6 +14,37 @@
*/
interface CategoryInterface extends \Magento\Framework\Api\CustomAttributesDataInterface
{
+ /**#@+
+ * Constants defined for keys of data array
+ */
+ const KEY_PARENT_ID = 'parent_id';
+ const KEY_NAME = 'name';
+ const KEY_IS_ACTIVE = 'is_active';
+ const KEY_POSITION = 'position';
+ const KEY_LEVEL = 'level';
+ const KEY_UPDATED_AT = 'updated_at';
+ const KEY_CREATED_AT = 'created_at';
+ const KEY_PATH = 'path';
+ const KEY_AVAILABLE_SORT_BY = 'available_sort_by';
+ const KEY_INCLUDE_IN_MENU = 'include_in_menu';
+ const KEY_PRODUCT_COUNT = 'product_count';
+ const KEY_CHILDREN_DATA = 'children_data';
+
+ const ATTRIBUTES = [
+ 'id',
+ self::KEY_PARENT_ID,
+ self::KEY_NAME,
+ self::KEY_IS_ACTIVE,
+ self::KEY_POSITION,
+ self::KEY_LEVEL,
+ self::KEY_UPDATED_AT,
+ self::KEY_CREATED_AT,
+ self::KEY_AVAILABLE_SORT_BY,
+ self::KEY_INCLUDE_IN_MENU,
+ self::KEY_CHILDREN_DATA,
+ ];
+ /**#@-*/
+
/**
* @return int|null
*/
diff --git a/app/code/Magento/Catalog/Api/Data/ProductInterface.php b/app/code/Magento/Catalog/Api/Data/ProductInterface.php
index a79c76fd8e2b6..4968f49fd20dc 100644
--- a/app/code/Magento/Catalog/Api/Data/ProductInterface.php
+++ b/app/code/Magento/Catalog/Api/Data/ProductInterface.php
@@ -36,6 +36,24 @@ interface ProductInterface extends \Magento\Framework\Api\CustomAttributesDataIn
const UPDATED_AT = 'updated_at';
+ const MEDIA_GALLERY = 'media_gallery';
+
+ const TIER_PRICE = 'tier_price';
+
+ const ATTRIBUTES = [
+ self::SKU,
+ self::NAME,
+ self::PRICE,
+ self::WEIGHT,
+ self::STATUS,
+ self::VISIBILITY,
+ self::ATTRIBUTE_SET_ID,
+ self::TYPE_ID,
+ self::CREATED_AT,
+ self::UPDATED_AT,
+ self::MEDIA_GALLERY,
+ self::TIER_PRICE,
+ ];
/**#@-*/
/**
diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php
index ff840635e4c70..e35846e69a29e 100644
--- a/app/code/Magento/Catalog/Model/Category.php
+++ b/app/code/Magento/Catalog/Model/Category.php
@@ -6,8 +6,12 @@
namespace Magento\Catalog\Model;
use Magento\Catalog\Api\CategoryRepositoryInterface;
+use Magento\Catalog\Api\Data\CategoryInterface;
+use Magento\Catalog\Model\Entity\GetCategoryCustomAttributeCodes;
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
+use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface;
use Magento\Framework\Api\AttributeValueFactory;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\Convert\ConvertArray;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Profiler;
@@ -69,23 +73,6 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
const CACHE_TAG = 'cat_c';
- /**#@+
- * Constants
- */
- const KEY_PARENT_ID = 'parent_id';
- const KEY_NAME = 'name';
- const KEY_IS_ACTIVE = 'is_active';
- const KEY_POSITION = 'position';
- const KEY_LEVEL = 'level';
- const KEY_UPDATED_AT = 'updated_at';
- const KEY_CREATED_AT = 'created_at';
- const KEY_PATH = 'path';
- const KEY_AVAILABLE_SORT_BY = 'available_sort_by';
- const KEY_INCLUDE_IN_MENU = 'include_in_menu';
- const KEY_PRODUCT_COUNT = 'product_count';
- const KEY_CHILDREN_DATA = 'children_data';
- /**#@-*/
-
/**#@-*/
protected $_eventPrefix = 'catalog_category';
@@ -142,21 +129,11 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
/**
* Attributes are that part of interface
*
+ * @deprecated
+ * @see CategoryInterface::ATTRIBUTES
* @var array
*/
- protected $interfaceAttributes = [
- 'id',
- self::KEY_PARENT_ID,
- self::KEY_NAME,
- self::KEY_IS_ACTIVE,
- self::KEY_POSITION,
- self::KEY_LEVEL,
- self::KEY_UPDATED_AT,
- self::KEY_CREATED_AT,
- self::KEY_AVAILABLE_SORT_BY,
- self::KEY_INCLUDE_IN_MENU,
- self::KEY_CHILDREN_DATA,
- ];
+ protected $interfaceAttributes = CategoryInterface::ATTRIBUTES;
/**
* Category tree model
@@ -230,6 +207,11 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
*/
protected $metadataService;
+ /**
+ * @var GetCustomAttributeCodesInterface
+ */
+ private $getCustomAttributeCodes;
+
/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
@@ -252,6 +234,7 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
+ * @param GetCustomAttributeCodesInterface|null $getCustomAttributeCodes
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -275,7 +258,8 @@ public function __construct(
CategoryRepositoryInterface $categoryRepository,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
- array $data = []
+ array $data = [],
+ GetCustomAttributeCodesInterface $getCustomAttributeCodes = null
) {
$this->metadataService = $metadataService;
$this->_treeModel = $categoryTreeResource;
@@ -290,6 +274,9 @@ public function __construct(
$this->urlFinder = $urlFinder;
$this->indexerRegistry = $indexerRegistry;
$this->categoryRepository = $categoryRepository;
+ $this->getCustomAttributeCodes = $getCustomAttributeCodes ?? ObjectManager::getInstance()->get(
+ GetCategoryCustomAttributeCodes::class
+ );
parent::__construct(
$context,
$registry,
@@ -323,11 +310,7 @@ protected function _construct()
*/
protected function getCustomAttributesCodes()
{
- if ($this->customAttributesCodes === null) {
- $this->customAttributesCodes = $this->getEavAttributesCodes($this->metadataService);
- $this->customAttributesCodes = array_diff($this->customAttributesCodes, $this->interfaceAttributes);
- }
- return $this->customAttributesCodes;
+ return $this->getCustomAttributeCodes->execute($this->metadataService);
}
/**
diff --git a/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php b/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php
new file mode 100644
index 0000000000000..b2b9199cc56b4
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php
@@ -0,0 +1,37 @@
+baseCustomAttributeCodes = $baseCustomAttributeCodes;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function execute(MetadataServiceInterface $metadataService): array
+ {
+ $customAttributesCodes = $this->baseCustomAttributeCodes->execute($metadataService);
+ return array_diff($customAttributesCodes, CategoryInterface::ATTRIBUTES);
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php b/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php
new file mode 100644
index 0000000000000..23678ffcf48b7
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php
@@ -0,0 +1,37 @@
+baseCustomAttributeCodes = $baseCustomAttributeCodes;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function execute(MetadataServiceInterface $metadataService): array
+ {
+ $customAttributesCodes = $this->baseCustomAttributeCodes->execute($metadataService);
+ return array_diff($customAttributesCodes, ProductInterface::ATTRIBUTES);
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index cb5669a4bb42e..db16c34f123f2 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -9,9 +9,12 @@
use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductLinkRepositoryInterface;
+use Magento\Catalog\Model\Entity\GetProductCustomAttributeCodes;
use Magento\Catalog\Model\Product\Attribute\Backend\Media\EntryConverterPool;
+use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface;
use Magento\Framework\Api\AttributeValueFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\DataObject\IdentityInterface;
use Magento\Framework\Pricing\SaleableInterface;
@@ -305,22 +308,12 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
/**
* List of attributes in ProductInterface
+ *
+ * @deprecated
+ * @see ProductInterface::ATTRIBUTES
* @var array
*/
- protected $interfaceAttributes = [
- ProductInterface::SKU,
- ProductInterface::NAME,
- ProductInterface::PRICE,
- ProductInterface::WEIGHT,
- ProductInterface::STATUS,
- ProductInterface::VISIBILITY,
- ProductInterface::ATTRIBUTE_SET_ID,
- ProductInterface::TYPE_ID,
- ProductInterface::CREATED_AT,
- ProductInterface::UPDATED_AT,
- 'media_gallery',
- 'tier_price',
- ];
+ protected $interfaceAttributes = ProductInterface::ATTRIBUTES;
/**
* @var \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface
@@ -346,6 +339,11 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
*/
protected $linkTypeProvider;
+ /**
+ * @var GetCustomAttributeCodesInterface
+ */
+ private $getCustomAttributeCodes;
+
/**
* Product constructor.
* @param \Magento\Framework\Model\Context $context
@@ -383,7 +381,7 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
* @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper
* @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor
* @param array $data
- *
+ * @param GetCustomAttributeCodesInterface|null $getCustomAttributeCodes
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@@ -422,7 +420,8 @@ public function __construct(
EntryConverterPool $mediaGalleryEntryConverterPool,
\Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor,
- array $data = []
+ array $data = [],
+ GetCustomAttributeCodesInterface $getCustomAttributeCodes = null
) {
$this->metadataService = $metadataService;
$this->_itemOptionFactory = $itemOptionFactory;
@@ -451,6 +450,9 @@ public function __construct(
$this->mediaGalleryEntryConverterPool = $mediaGalleryEntryConverterPool;
$this->dataObjectHelper = $dataObjectHelper;
$this->joinProcessor = $joinProcessor;
+ $this->getCustomAttributeCodes = $getCustomAttributeCodes ?? ObjectManager::getInstance()->get(
+ GetProductCustomAttributeCodes::class
+ );
parent::__construct(
$context,
$registry,
@@ -478,11 +480,7 @@ protected function _construct()
*/
protected function getCustomAttributesCodes()
{
- if ($this->customAttributesCodes === null) {
- $this->customAttributesCodes = $this->getEavAttributesCodes($this->metadataService);
- $this->customAttributesCodes = array_diff($this->customAttributesCodes, $this->interfaceAttributes);
- }
- return $this->customAttributesCodes;
+ return $this->getCustomAttributeCodes->execute($this->metadataService);
}
/**
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
index d96ac4bfaab0a..9f5f3313c6859 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
@@ -7,7 +7,7 @@
namespace Magento\Catalog\Test\Unit\Model;
use Magento\Catalog\Model\Indexer;
-use Magento\Catalog\Model\Category;
+use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface;
/**
* @SuppressWarnings(PHPMD.TooManyFields)
@@ -120,6 +120,11 @@ class CategoryTest extends \PHPUnit\Framework\TestCase
*/
private $objectManager;
+ /**
+ * @var GetCustomAttributeCodesInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $getCustomAttributeCodes;
+
protected function setUp()
{
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -160,6 +165,10 @@ protected function setUp()
);
$this->attributeValueFactory = $this->getMockBuilder(\Magento\Framework\Api\AttributeValueFactory::class)
->disableOriginalConstructor()->getMock();
+ $this->getCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class)
+ ->setMethods(['execute'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
$this->category = $this->getCategoryModel();
}
@@ -309,6 +318,7 @@ protected function getCategoryModel()
'indexerRegistry' => $this->indexerRegistry,
'metadataService' => $this->metadataServiceMock,
'customAttributeFactory' => $this->attributeValueFactory,
+ 'getCustomAttributeCodes' => $this->getCustomAttributeCodes
]
);
}
@@ -433,25 +443,15 @@ public function testGetCustomAttributes()
{
$nameAttributeCode = 'name';
$descriptionAttributeCode = 'description';
- $interfaceAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class);
- $interfaceAttribute->expects($this->once())
- ->method('getAttributeCode')
- ->willReturn($nameAttributeCode);
- $descriptionAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class);
- $descriptionAttribute->expects($this->once())
- ->method('getAttributeCode')
- ->willReturn($descriptionAttributeCode);
- $customAttributesMetadata = [$interfaceAttribute, $descriptionAttribute];
-
- $this->metadataServiceMock->expects($this->once())
- ->method('getCustomAttributesMetadata')
- ->willReturn($customAttributesMetadata);
+ $this->getCustomAttributeCodes->expects($this->exactly(3))
+ ->method('execute')
+ ->willReturn([$descriptionAttributeCode]);
$this->category->setData($nameAttributeCode, "sub");
- //The color attribute is not set, expect empty custom attribute array
+ //The description attribute is not set, expect empty custom attribute array
$this->assertEquals([], $this->category->getCustomAttributes());
- //Set the color attribute;
+ //Set the description attribute;
$this->category->setData($descriptionAttributeCode, "description");
$attributeValue = new \Magento\Framework\Api\AttributeValue();
$attributeValue2 = new \Magento\Framework\Api\AttributeValue();
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetCategoryCustomAttributeCodesTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetCategoryCustomAttributeCodesTest.php
new file mode 100644
index 0000000000000..465063dccd3d5
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetCategoryCustomAttributeCodesTest.php
@@ -0,0 +1,66 @@
+baseCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['execute'])
+ ->getMockForAbstractClass();
+ $objectManager = new ObjectManager($this);
+ $this->getCategoryCustomAttributeCodes = $objectManager->getObject(
+ GetCategoryCustomAttributeCodes::class,
+ ['baseCustomAttributeCodes' => $this->baseCustomAttributeCodes]
+ );
+ }
+
+ /**
+ * Test GetCategoryCustomAttributeCodes::execute() will return only custom category attribute codes.
+ */
+ public function testExecute()
+ {
+ /** @var MetadataServiceInterface|\PHPUnit_Framework_MockObject_MockObject $metadataService */
+ $metadataService = $this->getMockBuilder(MetadataServiceInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->baseCustomAttributeCodes->expects($this->once())
+ ->method('execute')
+ ->with($this->identicalTo($metadataService))
+ ->willReturn(['test_custom_attribute_code', 'name']);
+ $this->assertEquals(
+ ['test_custom_attribute_code'],
+ $this->getCategoryCustomAttributeCodes->execute($metadataService)
+ );
+ }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetProductCustomAttributeCodesTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetProductCustomAttributeCodesTest.php
new file mode 100644
index 0000000000000..a37e1c6df0908
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetProductCustomAttributeCodesTest.php
@@ -0,0 +1,66 @@
+baseCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['execute'])
+ ->getMockForAbstractClass();
+ $objectManager = new ObjectManager($this);
+ $this->getProductCustomAttributeCodes = $objectManager->getObject(
+ GetProductCustomAttributeCodes::class,
+ ['baseCustomAttributeCodes' => $this->baseCustomAttributeCodes]
+ );
+ }
+
+ /**
+ * Test GetProductCustomAttributeCodes::execute() will return only custom product attribute codes.
+ */
+ public function testExecute()
+ {
+ /** @var MetadataServiceInterface|\PHPUnit_Framework_MockObject_MockObject $metadataService */
+ $metadataService = $this->getMockBuilder(MetadataServiceInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->baseCustomAttributeCodes->expects($this->once())
+ ->method('execute')
+ ->with($this->identicalTo($metadataService))
+ ->willReturn(['test_custom_attribute_code', 'name']);
+ $this->assertEquals(
+ ['test_custom_attribute_code'],
+ $this->getProductCustomAttributeCodes->execute($metadataService)
+ );
+ }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
index 8d7e3dfb3f2fd..74a71a2828e1d 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
@@ -9,6 +9,7 @@
use Magento\Catalog\Api\Data\ProductExtensionFactory;
use Magento\Catalog\Api\Data\ProductExtensionInterface;
use Magento\Catalog\Model\Product;
+use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface;
use Magento\Framework\Api\Data\ImageContentInterface;
use Magento\Framework\Api\ExtensibleDataInterface;
use Magento\Framework\Api\ExtensionAttributesFactory;
@@ -198,6 +199,11 @@ class ProductTest extends \PHPUnit\Framework\TestCase
*/
private $extensionAttributes;
+ /**
+ * @var GetCustomAttributeCodesInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $getCustomAttributeCodes;
+
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
@@ -369,6 +375,10 @@ protected function setUp()
->expects($this->any())
->method('create')
->willReturn($this->extensionAttributes);
+ $this->getCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['execute'])
+ ->getMockForAbstractClass();
$this->objectManagerHelper = new ObjectManagerHelper($this);
$this->model = $this->objectManagerHelper->getObject(
@@ -398,7 +408,8 @@ protected function setUp()
'catalogProductMediaConfig' => $this->mediaConfig,
'_filesystem' => $this->filesystemMock,
'_collectionFactory' => $this->collectionFactoryMock,
- 'data' => ['id' => 1]
+ 'data' => ['id' => 1],
+ 'getCustomAttributeCodes' => $this->getCustomAttributeCodes
]
);
}
@@ -1269,19 +1280,9 @@ public function testGetCustomAttributes()
{
$priceCode = 'price';
$colorAttributeCode = 'color';
- $interfaceAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class);
- $interfaceAttribute->expects($this->once())
- ->method('getAttributeCode')
- ->willReturn($priceCode);
- $colorAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class);
- $colorAttribute->expects($this->once())
- ->method('getAttributeCode')
- ->willReturn($colorAttributeCode);
- $customAttributesMetadata = [$interfaceAttribute, $colorAttribute];
-
- $this->metadataServiceMock->expects($this->once())
- ->method('getCustomAttributesMetadata')
- ->willReturn($customAttributesMetadata);
+ $this->getCustomAttributeCodes->expects($this->exactly(3))
+ ->method('execute')
+ ->willReturn([$colorAttributeCode]);
$this->model->setData($priceCode, 10);
//The color attribute is not set, expect empty custom attribute array
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index 29b1cdfc7d15a..a7502d12e1f7b 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -143,6 +143,12 @@
Magento\Catalog\Model\Product\Attribute\Source\Status\Proxy
Magento\Catalog\Model\Product\Link\Proxy
+ Magento\Catalog\Model\Entity\GetProductCustomAttributeCodes
+
+
+
+
+ Magento\Catalog\Model\Entity\GetCategoryCustomAttributeCodes
diff --git a/app/code/Magento/Eav/Model/Entity/GetCustomAttributeCodes.php b/app/code/Magento/Eav/Model/Entity/GetCustomAttributeCodes.php
new file mode 100644
index 0000000000000..a77b298f5d209
--- /dev/null
+++ b/app/code/Magento/Eav/Model/Entity/GetCustomAttributeCodes.php
@@ -0,0 +1,52 @@
+customAttributesCodes[$cacheKey])) {
+ $this->customAttributesCodes[$cacheKey] = $this->getEavAttributesCodes($metadataService);
+ }
+ return $this->customAttributesCodes[$cacheKey];
+ }
+
+ /**
+ * Receive a list of EAV attributes using provided metadata service.
+ *
+ * @param MetadataServiceInterface $metadataService
+ * @param string|null $entityType
+ * @return string[]
+ */
+ private function getEavAttributesCodes(MetadataServiceInterface $metadataService, string $entityType = null)
+ {
+ $attributeCodes = [];
+ $customAttributesMetadata = $metadataService->getCustomAttributesMetadata($entityType);
+ if (is_array($customAttributesMetadata)) {
+ /** @var $attribute \Magento\Framework\Api\MetadataObjectInterface */
+ foreach ($customAttributesMetadata as $attribute) {
+ $attributeCodes[] = $attribute->getAttributeCode();
+ }
+ }
+ return $attributeCodes;
+ }
+}
diff --git a/app/code/Magento/Eav/Model/Entity/GetCustomAttributeCodesInterface.php b/app/code/Magento/Eav/Model/Entity/GetCustomAttributeCodesInterface.php
new file mode 100644
index 0000000000000..c73d626e7364d
--- /dev/null
+++ b/app/code/Magento/Eav/Model/Entity/GetCustomAttributeCodesInterface.php
@@ -0,0 +1,20 @@
+getCustomAttributeCodes = new GetCustomAttributeCodes();
+ }
+
+ /**
+ * Test GetCustomAttributeCodes::execute() will return attribute codes from attributes metadata.
+ *
+ * @return void
+ */
+ public function testExecute()
+ {
+ $attributeCode = 'testCode';
+ $attributeMetadata = $this->getMockBuilder(MetadataObjectInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getAttributeCode'])
+ ->getMockForAbstractClass();
+ $attributeMetadata->expects($this->once())
+ ->method('getAttributeCode')
+ ->willReturn($attributeCode);
+ /** @var MetadataServiceInterface|\PHPUnit_Framework_MockObject_MockObject $metadataService */
+ $metadataService = $this->getMockBuilder(MetadataServiceInterface::class)
+ ->setMethods(['getCustomAttributesMetadata'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $metadataService->expects($this->once())
+ ->method('getCustomAttributesMetadata')
+ ->willReturn([$attributeMetadata]);
+ $this->assertEquals([$attributeCode], $this->getCustomAttributeCodes->execute($metadataService));
+ }
+}
diff --git a/app/code/Magento/Eav/etc/di.xml b/app/code/Magento/Eav/etc/di.xml
index 8e897b979d2f0..ae4663cfc236a 100644
--- a/app/code/Magento/Eav/etc/di.xml
+++ b/app/code/Magento/Eav/etc/di.xml
@@ -8,6 +8,7 @@
+
diff --git a/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php b/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php
index dab0650fc7f6e..e1a4431783da6 100644
--- a/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php
+++ b/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php
@@ -49,7 +49,7 @@ public function create($extensibleClassName, $data = [])
$interfaceReflection = new \ReflectionClass($this->getExtensibleInterfaceName($extensibleClassName));
$methodReflection = $interfaceReflection->getMethod('getExtensionAttributes');
- if ($methodReflection->getDeclaringClass() == self::EXTENSIBLE_INTERFACE_NAME) {
+ if ($methodReflection->getDeclaringClass()->getName() === self::EXTENSIBLE_INTERFACE_NAME) {
throw new \LogicException(
"Method 'getExtensionAttributes' must be overridden in the interfaces "
. "which extend '" . self::EXTENSIBLE_INTERFACE_NAME . "'. "