Skip to content

Commit e2ab9c0

Browse files
authored
Merge pull request #7825 from magento-performance/ACPT-488-ACPT-489-ACPT-490
[performance] ACPT-490: Catalog Import attributes
2 parents bcb0fea + 557be9f commit e2ab9c0

File tree

17 files changed

+491
-496
lines changed

17 files changed

+491
-496
lines changed

app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php

Lines changed: 151 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
*/
66
namespace Magento\CatalogImportExport\Model\Import\Product\Type;
77

8-
use Magento\Framework\App\ResourceConnection;
8+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
99
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
10-
use Magento\CatalogImportExport\Model\Import\Product;
10+
use Magento\Eav\Model\Entity\Attribute\Source\Table;
11+
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory as AttributeOptionCollectionFactory;
12+
use Magento\Framework\App\ObjectManager;
13+
use Magento\Framework\App\ResourceConnection;
1114
use Magento\Framework\EntityManager\MetadataPool;
1215

1316
/**
@@ -151,6 +154,11 @@ abstract class AbstractType
151154
*/
152155
private $productEntityLinkField;
153156

157+
/**
158+
* @var AttributeOptionCollectionFactory
159+
*/
160+
private $attributeOptionCollectionFactory;
161+
154162
/**
155163
* AbstractType constructor
156164
*
@@ -159,20 +167,24 @@ abstract class AbstractType
159167
* @param ResourceConnection $resource
160168
* @param array $params
161169
* @param MetadataPool|null $metadataPool
170+
* @param AttributeOptionCollectionFactory|null $attributeOptionCollectionFactory
162171
* @throws \Magento\Framework\Exception\LocalizedException
163172
*/
164173
public function __construct(
165174
\Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attrSetColFac,
166175
\Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttrColFac,
167176
\Magento\Framework\App\ResourceConnection $resource,
168177
array $params,
169-
MetadataPool $metadataPool = null
178+
MetadataPool $metadataPool = null,
179+
AttributeOptionCollectionFactory $attributeOptionCollectionFactory = null
170180
) {
171181
$this->_attrSetColFac = $attrSetColFac;
172182
$this->_prodAttrColFac = $prodAttrColFac;
173183
$this->_resource = $resource;
174184
$this->connection = $resource->getConnection();
175185
$this->metadataPool = $metadataPool ?: $this->getMetadataPool();
186+
$this->attributeOptionCollectionFactory = $attributeOptionCollectionFactory
187+
?: ObjectManager::getInstance()->get(AttributeOptionCollectionFactory::class);
176188
if ($this->isSuitable()) {
177189
if (!isset($params[0])
178190
|| !isset($params[1])
@@ -183,11 +195,9 @@ public function __construct(
183195
}
184196
$this->_entityModel = $params[0];
185197
$this->_type = $params[1];
186-
187198
$this->initMessageTemplates(
188199
array_merge($this->_genericMessageTemplates, $this->_messageTemplates)
189200
);
190-
191201
$this->_initAttributes();
192202
}
193203
}
@@ -257,6 +267,10 @@ protected function _getProductAttributes($attrSetData)
257267
/**
258268
* Initialize attributes parameters for all attributes' sets.
259269
*
270+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
271+
* @SuppressWarnings(PHPMD.NPathComplexity)
272+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
273+
*
260274
* @return $this
261275
*/
262276
protected function _initAttributes()
@@ -284,80 +298,168 @@ protected function _initAttributes()
284298
$absentKeys[$attributeRow['attribute_set_name']][] = $attributeRow['attribute_id'];
285299
}
286300
}
287-
foreach ($absentKeys as $attributeSetName => $attributeIds) {
301+
$addedAttributes = [];
302+
foreach ($absentKeys as $attributeIds) {
288303
$unknownAttributeIds = array_diff(
289304
$attributeIds,
290305
array_keys(self::$commonAttributesCache),
291306
self::$invAttributesCache
292307
);
293-
if ($unknownAttributeIds || $this->_forcedAttributesCodes) {
294-
$this->attachAttributesById($attributeSetName, $attributeIds);
308+
if ($unknownAttributeIds) {
309+
$addedAttributes[] = $this->attachAttributesByOnlyId($unknownAttributeIds);
310+
}
311+
}
312+
if ($this->_forcedAttributesCodes) {
313+
$addedAttributes[] = $this->attachAttributesByForcedCodes();
314+
}
315+
$addedAttributes = array_merge(...$addedAttributes);
316+
$attributesToLoadFromTable = [];
317+
foreach ($addedAttributes as $addedAttribute) {
318+
if (isset($addedAttribute['options_use_table'])) {
319+
$attributesToLoadFromTable[] = $addedAttribute['id'];
320+
unset(self::$commonAttributesCache[$addedAttribute['id']]['options_use_table']);
321+
}
322+
}
323+
foreach (array_chunk($attributesToLoadFromTable, 1000) as $attributesToLoadFromTableChunk) {
324+
$collection = $this->attributeOptionCollectionFactory->create();
325+
$collection->setAttributeFilter(['in' => $attributesToLoadFromTableChunk]);
326+
$collection->setStoreFilter(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
327+
foreach ($collection as $option) {
328+
$attributeId = $option->getAttributeId();
329+
$value = strtolower($option->getValue());
330+
self::$commonAttributesCache[$attributeId]['options'][$value] = $option->getOptionId();
295331
}
296332
}
297333
foreach ($entityAttributes as $attributeRow) {
298334
if (isset(self::$commonAttributesCache[$attributeRow['attribute_id']])) {
299335
$attribute = self::$commonAttributesCache[$attributeRow['attribute_id']];
300-
$this->_addAttributeParams(
301-
$attributeRow['attribute_set_name'],
302-
self::$commonAttributesCache[$attributeRow['attribute_id']],
303-
$attribute
304-
);
336+
$this->_addAttributeParams($attributeRow['attribute_set_name'], $attribute, $attribute);
337+
}
338+
}
339+
foreach (array_keys($this->_attributes) as $setName) {
340+
foreach ($this->_forcedAttributesCodes as $code) {
341+
$attributeId = self::$attributeCodeToId[$code] ?? null;
342+
if (null === $attributeId) {
343+
continue;
344+
}
345+
if (isset($this->_attributes[$setName][$code])) {
346+
continue;
347+
}
348+
$attribute = self::$commonAttributesCache[$attributeId] ?? null;
349+
if (!$attribute) {
350+
continue;
351+
}
352+
$this->_addAttributeParams($setName, $attribute, $attribute);
305353
}
306354
}
307355
return $this;
308356
}
309357

310358
/**
311-
* Attach Attributes By Id
359+
* Attach Attributes By Id and _forcedAttributesCodes
312360
*
313361
* @param string $attributeSetName
314362
* @param array $attributeIds
315363
* @return void
364+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
365+
* @deprecated use attachAttributesByOnlyId and attachAttributesByForcedCodes
366+
* @see attachAttributesByOnlyId() and attachAttributesByForcedCodes()
316367
*/
317368
protected function attachAttributesById($attributeSetName, $attributeIds)
318369
{
319370
foreach ($this->_prodAttrColFac->create()->addFieldToFilter(
320371
['main_table.attribute_id', 'main_table.attribute_code'],
321-
[
322-
['in' => $attributeIds],
323-
['in' => $this->_forcedAttributesCodes]
324-
]
372+
[['in' => $attributeIds], ['in' => $this->_forcedAttributesCodes]]
325373
) as $attribute) {
326-
$attributeCode = $attribute->getAttributeCode();
327-
$attributeId = $attribute->getId();
328-
329-
if ($attribute->getIsVisible() || in_array($attributeCode, $this->_forcedAttributesCodes)) {
330-
if (!isset(self::$commonAttributesCache[$attributeId])) {
331-
$defaultValue = $attribute->getDefaultValue();
332-
self::$commonAttributesCache[$attributeId] = [
333-
'id' => $attributeId,
334-
'code' => $attributeCode,
335-
'is_global' => $attribute->getIsGlobal(),
336-
'is_required' => $attribute->getIsRequired(),
337-
'is_unique' => $attribute->getIsUnique(),
338-
'frontend_label' => $attribute->getFrontendLabel(),
339-
'is_static' => $attribute->isStatic(),
340-
'apply_to' => $attribute->getApplyTo(),
341-
'type' => \Magento\ImportExport\Model\Import::getAttributeType($attribute),
342-
'default_value' => (is_string($defaultValue) && strlen($defaultValue)) ?
343-
$attribute->getDefaultValue() : null,
344-
'options' => $this->_entityModel->getAttributeOptions(
345-
$attribute,
346-
$this->_indexValueAttributes
347-
),
348-
];
349-
}
374+
$this->attachAttribute($attribute);
375+
}
376+
}
377+
378+
/**
379+
* Attach Attributes By Id
380+
*
381+
* @param array $attributeIds
382+
* @return array
383+
*/
384+
private function attachAttributesByOnlyId(array $attributeIds) : array
385+
{
386+
$addedAttributes = [];
387+
foreach ($this->_prodAttrColFac->create()->addFieldToFilter(
388+
['main_table.attribute_id'],
389+
[['in' => $attributeIds]]
390+
) as $attribute) {
391+
$cachedAttribute = $this->attachAttribute($attribute);
392+
if (null !== $cachedAttribute) {
393+
$addedAttributes[] = $cachedAttribute;
394+
}
395+
}
396+
return $addedAttributes;
397+
}
350398

399+
/**
400+
* Attach Attributes By _forcedAttributesCodes
401+
*
402+
* @return array
403+
*/
404+
private function attachAttributesByForcedCodes() : array
405+
{
406+
$addedAttributes = [];
407+
foreach ($this->_prodAttrColFac->create()->addFieldToFilter(
408+
['main_table.attribute_code'],
409+
[['in' => $this->_forcedAttributesCodes]]
410+
) as $attribute) {
411+
$cachedAttribute = $this->attachAttribute($attribute);
412+
if (null !== $cachedAttribute) {
413+
$addedAttributes[] = $cachedAttribute;
414+
}
415+
}
416+
return $addedAttributes;
417+
}
418+
419+
/**
420+
* Attach Attribute to self::$commonAttributesCache or self::$invAttributesCache
421+
*
422+
* @param Attribute $attribute
423+
* @return array|null
424+
*/
425+
private function attachAttribute(Attribute $attribute)
426+
{
427+
$cachedAttribute = null;
428+
$attributeCode = $attribute->getAttributeCode();
429+
$attributeId = $attribute->getId();
430+
if ($attribute->getIsVisible() || in_array($attributeCode, $this->_forcedAttributesCodes)) {
431+
if (!isset(self::$commonAttributesCache[$attributeId])) {
432+
$defaultValue = $attribute->getDefaultValue();
433+
$cachedAttribute = [
434+
'id' => $attributeId,
435+
'code' => $attributeCode,
436+
'is_global' => $attribute->getIsGlobal(),
437+
'is_required' => $attribute->getIsRequired(),
438+
'is_unique' => $attribute->getIsUnique(),
439+
'frontend_label' => $attribute->getFrontendLabel(),
440+
'is_static' => $attribute->isStatic(),
441+
'apply_to' => $attribute->getApplyTo(),
442+
'type' => \Magento\ImportExport\Model\Import::getAttributeType($attribute),
443+
'default_value' => (is_string($defaultValue) && strlen($defaultValue)) ?
444+
$attribute->getDefaultValue() : null,
445+
'options' => [],
446+
];
447+
$sourceModel = $attribute->getSourceModel();
448+
if (Table::class === $sourceModel) {
449+
$cachedAttribute['options_use_table'] = true;
450+
} else {
451+
$cachedAttribute['options'] = $this->_entityModel->getAttributeOptions(
452+
$attribute,
453+
$this->_indexValueAttributes
454+
);
455+
}
456+
self::$commonAttributesCache[$attributeId] = $cachedAttribute;
351457
self::$attributeCodeToId[$attributeCode] = $attributeId;
352-
$this->_addAttributeParams(
353-
$attributeSetName,
354-
self::$commonAttributesCache[$attributeId],
355-
$attribute
356-
);
357-
} else {
358-
self::$invAttributesCache[] = $attributeId;
359458
}
459+
} else {
460+
self::$invAttributesCache[] = $attributeId;
360461
}
462+
return $cachedAttribute;
361463
}
362464

363465
/**
@@ -524,7 +626,6 @@ public function isSuitable()
524626
public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDefaultValue = true)
525627
{
526628
$resultAttrs = [];
527-
528629
foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
529630
if ($attrParams['is_static']) {
530631
continue;
@@ -548,7 +649,6 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe
548649
$resultAttrs[$attrCode] = $attrParams['default_value'];
549650
}
550651
}
551-
552652
return $resultAttrs;
553653
}
554654

0 commit comments

Comments
 (0)