Skip to content

Commit 0db4606

Browse files
[Magento Community Engineering] Community Contributions - 2.3-develop-prs
- merged with '2.3-develop-fast-lane-prs' branch
2 parents 86d0bac + e22a305 commit 0db4606

File tree

6 files changed

+317
-30
lines changed

6 files changed

+317
-30
lines changed

app/code/Magento/Catalog/Model/Product/Option.php

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
use Magento\Catalog\Api\Data\ProductCustomOptionValuesInterfaceFactory;
1212
use Magento\Catalog\Api\Data\ProductInterface;
1313
use Magento\Catalog\Model\Product;
14+
use Magento\Catalog\Model\Product\Option\Type\Date;
15+
use Magento\Catalog\Model\Product\Option\Type\DefaultType;
16+
use Magento\Catalog\Model\Product\Option\Type\File;
17+
use Magento\Catalog\Model\Product\Option\Type\Select;
18+
use Magento\Catalog\Model\Product\Option\Type\Text;
1419
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\Collection;
1520
use Magento\Catalog\Pricing\Price\BasePrice;
1621
use Magento\Framework\EntityManager\MetadataPool;
@@ -98,6 +103,16 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
98103
*/
99104
protected $validatorPool;
100105

106+
/**
107+
* @var string[]
108+
*/
109+
private $optionGroups;
110+
111+
/**
112+
* @var string[]
113+
*/
114+
private $optionTypesToGroups;
115+
101116
/**
102117
* @var MetadataPool
103118
*/
@@ -121,6 +136,8 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
121136
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
122137
* @param array $data
123138
* @param ProductCustomOptionValuesInterfaceFactory|null $customOptionValuesFactory
139+
* @param array $optionGroups
140+
* @param array $optionTypesToGroups
124141
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
125142
*/
126143
public function __construct(
@@ -135,14 +152,34 @@ public function __construct(
135152
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
136153
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
137154
array $data = [],
138-
ProductCustomOptionValuesInterfaceFactory $customOptionValuesFactory = null
155+
ProductCustomOptionValuesInterfaceFactory $customOptionValuesFactory = null,
156+
array $optionGroups = [],
157+
array $optionTypesToGroups = []
139158
) {
140159
$this->productOptionValue = $productOptionValue;
141160
$this->optionTypeFactory = $optionFactory;
142-
$this->validatorPool = $validatorPool;
143161
$this->string = $string;
162+
$this->validatorPool = $validatorPool;
144163
$this->customOptionValuesFactory = $customOptionValuesFactory ?:
145164
\Magento\Framework\App\ObjectManager::getInstance()->get(ProductCustomOptionValuesInterfaceFactory::class);
165+
$this->optionGroups = $optionGroups ?: [
166+
self::OPTION_GROUP_DATE => Date::class,
167+
self::OPTION_GROUP_FILE => File::class,
168+
self::OPTION_GROUP_SELECT => Select::class,
169+
self::OPTION_GROUP_TEXT => Text::class,
170+
];
171+
$this->optionTypesToGroups = $optionTypesToGroups ?: [
172+
self::OPTION_TYPE_FIELD => self::OPTION_GROUP_TEXT,
173+
self::OPTION_TYPE_AREA => self::OPTION_GROUP_TEXT,
174+
self::OPTION_TYPE_FILE => self::OPTION_GROUP_FILE,
175+
self::OPTION_TYPE_DROP_DOWN => self::OPTION_GROUP_SELECT,
176+
self::OPTION_TYPE_RADIO => self::OPTION_GROUP_SELECT,
177+
self::OPTION_TYPE_CHECKBOX => self::OPTION_GROUP_SELECT,
178+
self::OPTION_TYPE_MULTIPLE => self::OPTION_GROUP_SELECT,
179+
self::OPTION_TYPE_DATE => self::OPTION_GROUP_DATE,
180+
self::OPTION_TYPE_DATE_TIME => self::OPTION_GROUP_DATE,
181+
self::OPTION_TYPE_TIME => self::OPTION_GROUP_DATE,
182+
];
146183

147184
parent::__construct(
148185
$context,
@@ -314,36 +351,22 @@ public function getGroupByType($type = null)
314351
if ($type === null) {
315352
$type = $this->getType();
316353
}
317-
$optionGroupsToTypes = [
318-
self::OPTION_TYPE_FIELD => self::OPTION_GROUP_TEXT,
319-
self::OPTION_TYPE_AREA => self::OPTION_GROUP_TEXT,
320-
self::OPTION_TYPE_FILE => self::OPTION_GROUP_FILE,
321-
self::OPTION_TYPE_DROP_DOWN => self::OPTION_GROUP_SELECT,
322-
self::OPTION_TYPE_RADIO => self::OPTION_GROUP_SELECT,
323-
self::OPTION_TYPE_CHECKBOX => self::OPTION_GROUP_SELECT,
324-
self::OPTION_TYPE_MULTIPLE => self::OPTION_GROUP_SELECT,
325-
self::OPTION_TYPE_DATE => self::OPTION_GROUP_DATE,
326-
self::OPTION_TYPE_DATE_TIME => self::OPTION_GROUP_DATE,
327-
self::OPTION_TYPE_TIME => self::OPTION_GROUP_DATE,
328-
];
329354

330-
return $optionGroupsToTypes[$type] ?? '';
355+
return $this->optionTypesToGroups[$type] ?? '';
331356
}
332357

333358
/**
334359
* Group model factory
335360
*
336361
* @param string $type Option type
337-
* @return \Magento\Catalog\Model\Product\Option\Type\DefaultType
362+
* @return DefaultType
338363
* @throws LocalizedException
339364
*/
340365
public function groupFactory($type)
341366
{
342367
$group = $this->getGroupByType($type);
343-
if (!empty($group)) {
344-
return $this->optionTypeFactory->create(
345-
'Magento\Catalog\Model\Product\Option\Type\\' . $this->string->upperCaseWords($group)
346-
);
368+
if (!empty($group) && isset($this->optionGroups[$group])) {
369+
return $this->optionTypeFactory->create($this->optionGroups[$group]);
347370
}
348371
throw new LocalizedException(__('The option type to get group instance is incorrect.'));
349372
}

app/code/Magento/Catalog/etc/di.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,28 @@
411411
</argument>
412412
</arguments>
413413
</type>
414+
<type name="Magento\Catalog\Model\Product\Option">
415+
<arguments>
416+
<argument name="optionGroups" xsi:type="array">
417+
<item name="date" xsi:type="string">Magento\Catalog\Model\Product\Option\Type\Date</item>
418+
<item name="file" xsi:type="string">Magento\Catalog\Model\Product\Option\Type\File</item>
419+
<item name="select" xsi:type="string">Magento\Catalog\Model\Product\Option\Type\Select</item>
420+
<item name="text" xsi:type="string">Magento\Catalog\Model\Product\Option\Type\Text</item>
421+
</argument>
422+
<argument name="optionTypesToGroups" xsi:type="array">
423+
<item name="field" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_TEXT</item>
424+
<item name="area" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_TEXT</item>
425+
<item name="file" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_FILE</item>
426+
<item name="drop_down" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT</item>
427+
<item name="radio" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT</item>
428+
<item name="checkbox" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT</item>
429+
<item name="multiple" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT</item>
430+
<item name="date" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_DATE</item>
431+
<item name="date_time" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_DATE</item>
432+
<item name="time" xsi:type="const">Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_DATE</item>
433+
</argument>
434+
</arguments>
435+
</type>
414436
<type name="Magento\Catalog\Model\Product\Option\Validator\Pool">
415437
<arguments>
416438
<argument name="validators" xsi:type="array">

app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1010
use Magento\Catalog\Api\Data\ProductInterface;
1111
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
12+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1213
use Magento\Catalog\Api\ProductRepositoryInterface;
1314
use Magento\Catalog\Model\Config;
1415
use Magento\Catalog\Model\Product\Gallery\ReadHandler as GalleryReadHandler;
1516
use Magento\ConfigurableProduct\Model\Product\Type\Collection\SalableProcessor;
1617
use Magento\Framework\App\ObjectManager;
1718
use Magento\Framework\EntityManager\MetadataPool;
19+
use Magento\Framework\Api\SearchCriteriaBuilder;
1820

1921
/**
2022
* Configurable product type implementation
@@ -194,9 +196,18 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
194196
*/
195197
private $salableProcessor;
196198

199+
/**
200+
* @var ProductAttributeRepositoryInterface|null
201+
*/
202+
private $productAttributeRepository;
203+
204+
/**
205+
* @var SearchCriteriaBuilder|null
206+
*/
207+
private $searchCriteriaBuilder;
208+
197209
/**
198210
* @codingStandardsIgnoreStart/End
199-
*
200211
* @param \Magento\Catalog\Model\Product\Option $catalogProductOption
201212
* @param \Magento\Eav\Model\Config $eavConfig
202213
* @param \Magento\Catalog\Model\Product\Type $catalogProductType
@@ -214,9 +225,13 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
214225
* @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable
215226
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
216227
* @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor
228+
* @param \Magento\Framework\Cache\FrontendInterface|null $cache
229+
* @param \Magento\Customer\Model\Session|null $customerSession
217230
* @param \Magento\Framework\Serialize\Serializer\Json $serializer
218231
* @param ProductInterfaceFactory $productFactory
219232
* @param SalableProcessor $salableProcessor
233+
* @param ProductAttributeRepositoryInterface|null $productAttributeRepository
234+
* @param SearchCriteriaBuilder|null $searchCriteriaBuilder
220235
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
221236
*/
222237
public function __construct(
@@ -241,7 +256,9 @@ public function __construct(
241256
\Magento\Customer\Model\Session $customerSession = null,
242257
\Magento\Framework\Serialize\Serializer\Json $serializer = null,
243258
ProductInterfaceFactory $productFactory = null,
244-
SalableProcessor $salableProcessor = null
259+
SalableProcessor $salableProcessor = null,
260+
ProductAttributeRepositoryInterface $productAttributeRepository = null,
261+
SearchCriteriaBuilder $searchCriteriaBuilder = null
245262
) {
246263
$this->typeConfigurableFactory = $typeConfigurableFactory;
247264
$this->_eavAttributeFactory = $eavAttributeFactory;
@@ -256,6 +273,10 @@ public function __construct(
256273
$this->productFactory = $productFactory ?: ObjectManager::getInstance()
257274
->get(ProductInterfaceFactory::class);
258275
$this->salableProcessor = $salableProcessor ?: ObjectManager::getInstance()->get(SalableProcessor::class);
276+
$this->productAttributeRepository = $productAttributeRepository ?:
277+
ObjectManager::getInstance()->get(ProductAttributeRepositoryInterface::class);
278+
$this->searchCriteriaBuilder = $searchCriteriaBuilder ?:
279+
ObjectManager::getInstance()->get(SearchCriteriaBuilder::class);
259280
parent::__construct(
260281
$catalogProductOption,
261282
$eavConfig,
@@ -1231,19 +1252,16 @@ public function isPossibleBuyFromList($product)
12311252

12321253
/**
12331254
* Returns array of sub-products for specified configurable product
1234-
*
1235-
* $requiredAttributeIds - one dimensional array, if provided
12361255
* Result array contains all children for specified configurable product
12371256
*
12381257
* @param \Magento\Catalog\Model\Product $product
1239-
* @param array $requiredAttributeIds
1258+
* @param array $requiredAttributeIds Attributes to include in the select; one-dimensional array
12401259
* @return ProductInterface[]
1241-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
12421260
*/
12431261
public function getUsedProducts($product, $requiredAttributeIds = null)
12441262
{
12451263
if (!$product->hasData($this->_usedProducts)) {
1246-
$collection = $this->getConfiguredUsedProductCollection($product, false);
1264+
$collection = $this->getConfiguredUsedProductCollection($product, false, $requiredAttributeIds);
12471265
$usedProducts = array_values($collection->getItems());
12481266
$product->setData($this->_usedProducts, $usedProducts);
12491267
}
@@ -1390,25 +1408,38 @@ private function getUsedProductsCacheKey($keyParts)
13901408

13911409
/**
13921410
* Prepare collection for retrieving sub-products of specified configurable product
1393-
*
13941411
* Retrieve related products collection with additional configuration
13951412
*
13961413
* @param \Magento\Catalog\Model\Product $product
13971414
* @param bool $skipStockFilter
1415+
* @param array $requiredAttributeIds Attributes to include in the select
13981416
* @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection
1417+
* @throws \Magento\Framework\Exception\LocalizedException
13991418
*/
14001419
private function getConfiguredUsedProductCollection(
14011420
\Magento\Catalog\Model\Product $product,
1402-
$skipStockFilter = true
1421+
$skipStockFilter = true,
1422+
$requiredAttributeIds = null
14031423
) {
14041424
$collection = $this->getUsedProductCollection($product);
14051425

14061426
if ($skipStockFilter) {
14071427
$collection->setFlag('has_stock_status_filter', true);
14081428
}
14091429

1430+
$attributesForSelect = $this->getAttributesForCollection($product);
1431+
if ($requiredAttributeIds) {
1432+
$this->searchCriteriaBuilder->addFilter('attribute_id', $requiredAttributeIds, 'in');
1433+
$requiredAttributes = $this->productAttributeRepository
1434+
->getList($this->searchCriteriaBuilder->create())->getItems();
1435+
$requiredAttributeCodes = [];
1436+
foreach ($requiredAttributes as $requiredAttribute) {
1437+
$requiredAttributeCodes[] = $requiredAttribute->getAttributeCode();
1438+
}
1439+
$attributesForSelect = array_unique(array_merge($attributesForSelect, $requiredAttributeCodes));
1440+
}
14101441
$collection
1411-
->addAttributeToSelect($this->getAttributesForCollection($product))
1442+
->addAttributeToSelect($attributesForSelect)
14121443
->addFilterByRequiredOptions()
14131444
->setStoreId($product->getStoreId());
14141445

dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,33 @@ public function testGetUsedProducts()
254254
}
255255
}
256256

257+
/**
258+
* Tests the $requiredAttributes parameter; uses meta_description as an example of an attribute that is not
259+
* included in default attribute select.
260+
* @magentoAppIsolation enabled
261+
* @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php
262+
*/
263+
public function testGetUsedProductsWithRequiredAttributes()
264+
{
265+
$requiredAttributeIds = [86];
266+
$products = $this->model->getUsedProducts($this->product, $requiredAttributeIds);
267+
foreach ($products as $product) {
268+
self::assertNotNull($product->getData('meta_description'));
269+
}
270+
}
271+
272+
/**
273+
* @magentoAppIsolation enabled
274+
* @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php
275+
*/
276+
public function testGetUsedProductsWithoutRequiredAttributes()
277+
{
278+
$products = $this->model->getUsedProducts($this->product);
279+
foreach ($products as $product) {
280+
self::assertNull($product->getData('meta_description'));
281+
}
282+
}
283+
257284
/**
258285
* Test getUsedProducts returns array with same indexes regardless collections was cache or not.
259286
*

0 commit comments

Comments
 (0)