Skip to content

Commit 6a86bc8

Browse files
committed
MAGETWO-55729: [Customer] Optimize performance for bundled products with lots of product options
- MAGETWO-60732: SQL exception in staging preview mode
1 parent 8f1a1bd commit 6a86bc8

File tree

5 files changed

+292
-176
lines changed

5 files changed

+292
-176
lines changed

app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php

Lines changed: 37 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,33 @@ class Calculator implements BundleCalculatorInterface
5555
*/
5656
private $optionAmount = [];
5757

58+
/**
59+
* @var SelectionPriceListProviderInterface
60+
*/
61+
private $selectionPriceListProvider;
62+
5863
/**
5964
* @param CalculatorBase $calculator
6065
* @param AmountFactory $amountFactory
6166
* @param BundleSelectionFactory $bundleSelectionFactory
6267
* @param TaxHelper $taxHelper
6368
* @param PriceCurrencyInterface $priceCurrency
69+
* @param SelectionPriceListProviderInterface|null $selectionPriceListProvider
6470
*/
6571
public function __construct(
6672
CalculatorBase $calculator,
6773
AmountFactory $amountFactory,
6874
BundleSelectionFactory $bundleSelectionFactory,
6975
TaxHelper $taxHelper,
70-
PriceCurrencyInterface $priceCurrency
76+
PriceCurrencyInterface $priceCurrency,
77+
SelectionPriceListProviderInterface $selectionPriceListProvider = null
7178
) {
7279
$this->calculator = $calculator;
7380
$this->amountFactory = $amountFactory;
7481
$this->selectionFactory = $bundleSelectionFactory;
7582
$this->taxHelper = $taxHelper;
7683
$this->priceCurrency = $priceCurrency;
84+
$this->selectionPriceListProvider = $selectionPriceListProvider;
7785
}
7886

7987
/**
@@ -183,90 +191,24 @@ public function getAmountWithoutOption($amount, Product $saleableItem)
183191
* @param bool $searchMin
184192
* @param bool $useRegularPrice
185193
* @return array
186-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
187-
* @SuppressWarnings(PHPMD.NPathComplexity)
188194
*/
189195
protected function getSelectionAmounts(Product $bundleProduct, $searchMin, $useRegularPrice = false)
190196
{
191-
// Flag shows - is it necessary to find minimal option amount in case if all options are not required
192-
$shouldFindMinOption = false;
193-
if ($searchMin
194-
&& $bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC
195-
&& !$this->hasRequiredOption($bundleProduct)
196-
) {
197-
$shouldFindMinOption = true;
198-
}
199-
$canSkipRequiredOptions = $searchMin && !$shouldFindMinOption;
200-
201-
/** @var \Magento\Bundle\Model\Product\Type $typeInstance */
202-
$typeInstance = $bundleProduct->getTypeInstance();
203-
$priceList = [];
204-
205-
foreach ($this->getBundleOptions($bundleProduct) as $option) {
206-
/** @var \Magento\Bundle\Model\Option $option */
207-
if ($this->canSkipOption($option, $canSkipRequiredOptions)) {
208-
continue;
209-
}
210-
211-
$selectionsCollection = $typeInstance->getSelectionsCollection(
212-
[(int)$option->getOptionId()],
213-
$bundleProduct
214-
);
215-
$selectionsCollection->removeAttributeToSelect();
216-
$selectionsCollection->addQuantityFilter();
217-
218-
if (!$searchMin && $option->isMultiSelection()) {
219-
$selectionsCollection->addPriceData();
220-
221-
foreach ($selectionsCollection as $selection) {
222-
$priceList[] = $this->selectionFactory->create(
223-
$bundleProduct,
224-
$selection,
225-
$selection->getSelectionQty(),
226-
[
227-
'useRegularPrice' => $useRegularPrice,
228-
]
229-
);
230-
}
231-
} else {
232-
$selectionsCollection->addPriceFilter($bundleProduct, $searchMin, $useRegularPrice);
233-
$selectionsCollection->setPage(0, 1);
234-
if (!$useRegularPrice) {
235-
$selectionsCollection->addAttributeToSelect('special_price');
236-
$selectionsCollection->addAttributeToSelect('special_price_from');
237-
$selectionsCollection->addAttributeToSelect('special_price_to');
238-
$selectionsCollection->addAttributeToSelect('tax_class_id');
239-
}
240-
241-
$selection = $selectionsCollection->getFirstItem();
242-
243-
if (!$selection->isEmpty()) {
244-
$priceList[] = $this->selectionFactory->create(
245-
$bundleProduct,
246-
$selection,
247-
$selection->getSelectionQty(),
248-
[
249-
'useRegularPrice' => $useRegularPrice,
250-
]
251-
);
252-
}
253-
}
254-
}
197+
return $this->getSelectionPriceListProvider()->getPriceList($bundleProduct, $searchMin, $useRegularPrice);
198+
}
255199

256-
if ($shouldFindMinOption) {
257-
$minPrice = null;
258-
$priceSelection = null;
259-
foreach ($priceList as $price) {
260-
$minPriceTmp = $price->getAmount()->getValue() * $price->getQuantity();
261-
if (!$minPrice || $minPriceTmp < $minPrice) {
262-
$minPrice = $minPriceTmp;
263-
$priceSelection = $price;
264-
}
265-
}
266-
$priceList = $priceSelection ? [$priceSelection] : [];
200+
/**
201+
* @return SelectionPriceListProviderInterface
202+
* @deprecated
203+
*/
204+
private function getSelectionPriceListProvider()
205+
{
206+
if (null === $this->selectionPriceListProvider) {
207+
$this->selectionPriceListProvider = \Magento\Framework\App\ObjectManager::getInstance()
208+
->get(SelectionPriceListProviderInterface::class);
267209
}
268210

269-
return $priceList;
211+
return $this->selectionPriceListProvider;
270212
}
271213

272214
/**
@@ -275,35 +217,45 @@ protected function getSelectionAmounts(Product $bundleProduct, $searchMin, $useR
275217
* @param \Magento\Bundle\Model\Option $option
276218
* @param bool $canSkipRequiredOption
277219
* @return bool
220+
* @deprecated
278221
*/
279222
protected function canSkipOption($option, $canSkipRequiredOption)
280223
{
281-
return $canSkipRequiredOption && !$option->getRequired();
224+
return !$option->getSelections() || ($canSkipRequiredOption && !$option->getRequired());
282225
}
283226

284227
/**
285228
* Check the bundle product for availability of required options
286229
*
287230
* @param Product $bundleProduct
288231
* @return bool
232+
* @deprecated
289233
*/
290234
protected function hasRequiredOption($bundleProduct)
291235
{
292-
$collection = clone $this->getBundleOptions($bundleProduct);
293-
$collection->clear();
294-
295-
return $collection->addFilter(\Magento\Bundle\Model\Option::KEY_REQUIRED, 1)->getSize() > 0;
236+
$options = array_filter(
237+
$this->getBundleOptions($bundleProduct),
238+
function ($item) {
239+
return $item->getRequired();
240+
}
241+
);
242+
return !empty($options);
296243
}
297244

298245
/**
299246
* Get bundle options
300247
*
301248
* @param Product $saleableItem
302249
* @return \Magento\Bundle\Model\ResourceModel\Option\Collection
250+
* @deprecated
303251
*/
304252
protected function getBundleOptions(Product $saleableItem)
305253
{
306-
return $saleableItem->getTypeInstance()->getOptionsCollection($saleableItem);
254+
/** @var \Magento\Bundle\Pricing\Price\BundleOptionPrice $bundlePrice */
255+
$bundlePrice = $saleableItem->getPriceInfo()->getPrice(
256+
\Magento\Bundle\Pricing\Price\BundleOptionPrice::PRICE_CODE
257+
);
258+
return $bundlePrice->getOptions();
307259
}
308260

309261
/**

0 commit comments

Comments
 (0)