Skip to content

Commit 995e192

Browse files
MAGETWO-92693: Some improvements on product create|edit page in admin area
1 parent 38d7977 commit 995e192

File tree

6 files changed

+144
-35
lines changed

6 files changed

+144
-35
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Builder.php

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
use Magento\Store\Model\StoreFactory;
1212
use Psr\Log\LoggerInterface as Logger;
1313
use Magento\Framework\Registry;
14+
use Magento\Catalog\Api\ProductRepositoryInterface;
15+
use Magento\Catalog\Model\Product;
16+
use Magento\Catalog\Model\Product\Type as ProductTypes;
1417

1518
class Builder
1619
{
@@ -39,6 +42,11 @@ class Builder
3942
*/
4043
protected $storeFactory;
4144

45+
/**
46+
* @var ProductRepositoryInterface
47+
*/
48+
protected $productRepository;
49+
4250
/**
4351
* Constructor
4452
*
@@ -53,55 +61,80 @@ public function __construct(
5361
Logger $logger,
5462
Registry $registry,
5563
WysiwygModel\Config $wysiwygConfig,
56-
StoreFactory $storeFactory = null
64+
StoreFactory $storeFactory = null,
65+
ProductRepositoryInterface $productRepository = null
5766
) {
5867
$this->productFactory = $productFactory;
5968
$this->logger = $logger;
6069
$this->registry = $registry;
6170
$this->wysiwygConfig = $wysiwygConfig;
6271
$this->storeFactory = $storeFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
6372
->get(\Magento\Store\Model\StoreFactory::class);
73+
$this->productRepository = $productRepository ?: \Magento\Framework\App\ObjectManager::getInstance()
74+
->get(ProductRepositoryInterface::class);
6475
}
6576

6677
/**
6778
* Build product based on user request
6879
*
6980
* @param RequestInterface $request
7081
* @return \Magento\Catalog\Model\Product
82+
* @throws \RuntimeException
7183
*/
7284
public function build(RequestInterface $request)
7385
{
74-
$productId = (int)$request->getParam('id');
75-
/** @var $product \Magento\Catalog\Model\Product */
76-
$product = $this->productFactory->create();
77-
$product->setStoreId($request->getParam('store', 0));
78-
$store = $this->storeFactory->create();
79-
$store->load($request->getParam('store', 0));
80-
86+
$productId = (int) $request->getParam('id');
87+
$storeId = (int) $request->getParam('store', 0);
88+
$attributeSetId = (int) $request->getParam('set');
8189
$typeId = $request->getParam('type');
82-
if (!$productId && $typeId) {
83-
$product->setTypeId($typeId);
84-
}
8590

86-
$product->setData('_edit_mode', true);
8791
if ($productId) {
8892
try {
89-
$product->load($productId);
93+
$product = $this->productRepository->getById($productId, true, $storeId);
9094
} catch (\Exception $e) {
91-
$product->setTypeId(\Magento\Catalog\Model\Product\Type::DEFAULT_TYPE);
95+
$product = $this->createEmptyProduct(ProductTypes::DEFAULT_TYPE, $attributeSetId, $storeId);
9296
$this->logger->critical($e);
9397
}
98+
} else {
99+
$product = $this->createEmptyProduct($typeId, $attributeSetId, $storeId);
94100
}
95101

96-
$setId = (int)$request->getParam('set');
97-
if ($setId) {
98-
$product->setAttributeSetId($setId);
99-
}
102+
$store = $this->storeFactory->create();
103+
$store->load($storeId);
100104

101105
$this->registry->register('product', $product);
102106
$this->registry->register('current_product', $product);
103107
$this->registry->register('current_store', $store);
104-
$this->wysiwygConfig->setStoreId($request->getParam('store'));
108+
109+
$this->wysiwygConfig->setStoreId($storeId);
110+
111+
return $product;
112+
}
113+
114+
/**
115+
* @param int $typeId
116+
* @param int $attributeSetId
117+
* @param int $storeId
118+
* @return \Magento\Catalog\Model\Product
119+
*/
120+
private function createEmptyProduct($typeId, $attributeSetId, $storeId): Product
121+
{
122+
/** @var $product \Magento\Catalog\Model\Product */
123+
$product = $this->productFactory->create();
124+
$product->setData('_edit_mode', true);
125+
126+
if ($typeId !== null) {
127+
$product->setTypeId($typeId);
128+
}
129+
130+
if ($storeId !== null) {
131+
$product->setStoreId($storeId);
132+
}
133+
134+
if ($attributeSetId !== null) {
135+
$product->setAttributeSetId($attributeSetId);
136+
}
137+
105138
return $product;
106139
}
107140
}

app/code/Magento/Catalog/Model/ProductRepository.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -234,19 +234,13 @@ public function get($sku, $editMode = false, $storeId = null, $forceReload = fal
234234
$cacheKey = $this->getCacheKey([$editMode, $storeId]);
235235
$cachedProduct = $this->getProductFromLocalCache($sku, $cacheKey);
236236
if ($cachedProduct === null || $forceReload) {
237-
$product = $this->productFactory->create();
238-
239237
$productId = $this->resourceModel->getIdBySku($sku);
240238
if (!$productId) {
241239
throw new NoSuchEntityException(__('Requested product doesn\'t exist'));
242240
}
243-
if ($editMode) {
244-
$product->setData('_edit_mode', true);
245-
}
246-
if ($storeId !== null) {
247-
$product->setData('store_id', $storeId);
248-
}
249-
$product->load($productId);
241+
242+
$product = $this->getById($productId, $editMode, $storeId, $forceReload);
243+
250244
$this->cacheProduct($cacheKey, $product);
251245
$cachedProduct = $product;
252246
}

app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Magento\Ui\Component\Form\Fieldset;
3232
use Magento\Ui\DataProvider\Mapper\FormElement as FormElementMapper;
3333
use Magento\Ui\DataProvider\Mapper\MetaProperties as MetaPropertiesMapper;
34+
use Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory as AttributeCollectionFactory;
3435

3536
/**
3637
* Class Eav
@@ -187,6 +188,12 @@ class Eav extends AbstractModifier
187188
*/
188189
private $localeCurrency;
189190

191+
/**
192+
* internal cache for attribute models
193+
* @var array
194+
*/
195+
private $attributesCache = [];
196+
190197
/**
191198
* @param LocatorInterface $locator
192199
* @param CatalogEavValidationRules $catalogEavValidationRules
@@ -228,7 +235,8 @@ public function __construct(
228235
ScopeOverriddenValue $scopeOverriddenValue,
229236
DataPersistorInterface $dataPersistor,
230237
$attributesToDisable = [],
231-
$attributesToEliminate = []
238+
$attributesToEliminate = [],
239+
AttributeCollectionFactory $attributeCollectionFactory = null
232240
) {
233241
$this->locator = $locator;
234242
$this->catalogEavValidationRules = $catalogEavValidationRules;
@@ -249,6 +257,8 @@ public function __construct(
249257
$this->dataPersistor = $dataPersistor;
250258
$this->attributesToDisable = $attributesToDisable;
251259
$this->attributesToEliminate = $attributesToEliminate;
260+
$this->attributeCollectionFactory = $attributeCollectionFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
261+
->get(AttributeCollectionFactory::class);
252262
}
253263

254264
/**
@@ -485,9 +495,7 @@ private function getAttributeSetId()
485495
private function getAttributes()
486496
{
487497
if (!$this->attributes) {
488-
foreach ($this->getGroups() as $group) {
489-
$this->attributes[$this->calculateGroupCode($group)] = $this->loadAttributes($group);
490-
}
498+
$this->attributes = $this->loadAttributesForGroups($this->getGroups());
491499
}
492500

493501
return $this->attributes;
@@ -524,6 +532,60 @@ private function loadAttributes(AttributeGroupInterface $group)
524532
return $attributes;
525533
}
526534

535+
/**
536+
* @param AttributeGroupInterface[] ...$groups
537+
* @return @return ProductAttributeInterface[]
538+
*/
539+
private function loadAttributesForGroups(array $groups)
540+
{
541+
$attributes = [];
542+
$groupIds = [];
543+
544+
// foreach just works faster than array_walk() or array_column()
545+
foreach ($groups as $group) {
546+
$groupIds[$group->getAttributeGroupId()] = $this->calculateGroupCode($group);
547+
$attributes[$this->calculateGroupCode($group)] = [];
548+
}
549+
550+
$collection = $this->attributeCollectionFactory->create();
551+
$collection->setAttributeGroupFilter(array_keys($groupIds));
552+
553+
$attrs = $collection->getItems();
554+
555+
$map = [];
556+
557+
foreach ($attrs as $a) {
558+
$map[$a->getAttributeId()] = $a->getAttributeGroupId();
559+
}
560+
561+
$sortOrder = $this->sortOrderBuilder
562+
->setField('sort_order')
563+
->setAscendingDirection()
564+
->create();
565+
566+
$searchCriteria = $this->searchCriteriaBuilder
567+
->addFilter(AttributeGroupInterface::GROUP_ID, array_keys($groupIds), 'in')
568+
->addFilter(ProductAttributeInterface::IS_VISIBLE, 1)
569+
->addSortOrder($sortOrder)
570+
->create();
571+
572+
$groupAttributes = $this->attributeRepository->getList($searchCriteria)->getItems();
573+
574+
$productType = $this->getProductType();
575+
576+
foreach ($groupAttributes as $attribute) {
577+
$applyTo = $attribute->getApplyTo();
578+
$isRelated = !$applyTo || in_array($productType, $applyTo);
579+
if ($isRelated) {
580+
$attributeGroupId = $map[$attribute->getAttributeId()];
581+
$attributeGroupCode = $groupIds[$attributeGroupId];
582+
$attributes[$attributeGroupCode][] = $attribute;
583+
}
584+
}
585+
586+
return $attributes;
587+
}
588+
527589
/**
528590
* Get attribute codes of prev set
529591
*
@@ -905,7 +967,13 @@ private function isScopeGlobal($attribute)
905967
*/
906968
private function getAttributeModel($attribute)
907969
{
908-
return $this->eavAttributeFactory->create()->load($attribute->getAttributeId());
970+
$attributeId = $attribute->getAttributeId();
971+
972+
if (!array_key_exists($attributeId, $this->attributesCache)) {
973+
$this->attributesCache[$attributeId] = $this->eavAttributeFactory->create()->load($attributeId);
974+
}
975+
976+
return $this->attributesCache[$attributeId];
909977
}
910978

911979
/**

app/code/Magento/Eav/Model/AttributeRepository.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,16 @@ public function getList($entityTypeCode, \Magento\Framework\Api\SearchCriteriaIn
141141
$searchResults = $this->searchResultsFactory->create();
142142
$searchResults->setSearchCriteria($searchCriteria);
143143
$searchResults->setItems($attributes);
144-
$searchResults->setTotalCount($attributeCollection->getSize());
144+
145+
// if $searchCriteria has no page size - we can use count() on $attributeCollection
146+
// otherwise - we have to use getSize() on $attributeCollection
147+
// with this approach we can eliminate excessive COUNT requests in case page size is empty
148+
if ($searchCriteria->getPageSize()) {
149+
$searchResults->setTotalCount($attributeCollection->getSize());
150+
} else {
151+
$searchResults->setTotalCount(count($attributeCollection));
152+
}
153+
145154
return $searchResults;
146155
}
147156

app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ public function _loadAttributes($printQuery = false, $logQuery = false)
11751175
$attributeTypes[$table]
11761176
);
11771177
}
1178-
$selectGroups = $this->_resourceHelper->getLoadAttributesSelectGroups($selects);
1178+
$selectGroups = $this->_resourceHelper->mergeToOneGroup($selects);
11791179
foreach ($selectGroups as $selects) {
11801180
if (!empty($selects)) {
11811181
try {

app/code/Magento/Eav/Model/ResourceModel/Helper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,9 @@ public function getLoadAttributesSelectGroups($selects)
8383
}
8484
return $mainGroup;
8585
}
86+
87+
public function mergeToOneGroup($selects)
88+
{
89+
return [$this->getLoadAttributesSelectGroups($selects)];
90+
}
8691
}

0 commit comments

Comments
 (0)