|
1 | 1 | <?php
|
2 | 2 | /**
|
3 |
| - * Copyright © Magento, Inc. All rights reserved. |
4 |
| - * See COPYING.txt for license details. |
| 3 | + * Copyright 2015 Adobe |
| 4 | + * All Rights Reserved. |
5 | 5 | */
|
6 | 6 |
|
7 | 7 | namespace Magento\ConfigurableProduct\Pricing\Price;
|
@@ -60,6 +60,11 @@ class ConfigurableRegularPrice extends AbstractPrice implements
|
60 | 60 | */
|
61 | 61 | private $configurableMaxPriceCalculator;
|
62 | 62 |
|
| 63 | + /** |
| 64 | + * @var array<int, bool> |
| 65 | + */ |
| 66 | + private $equalFinalPriceCache = []; |
| 67 | + |
63 | 68 | /**
|
64 | 69 | * @param \Magento\Framework\Pricing\SaleableInterface $saleableItem
|
65 | 70 | * @param float $quantity
|
@@ -193,29 +198,71 @@ private function getConfigurableOptionsProvider()
|
193 | 198 | public function _resetState(): void
|
194 | 199 | {
|
195 | 200 | $this->values = [];
|
| 201 | + $this->equalFinalPriceCache = []; |
196 | 202 | }
|
197 | 203 |
|
198 | 204 | /**
|
199 | 205 | * Check whether Configurable Product have more than one children products
|
200 | 206 | *
|
201 | 207 | * @param SaleableInterface $product
|
202 | 208 | * @return bool
|
| 209 | + * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
| 210 | + * @SuppressWarnings(PHPMD.NPathComplexity) |
203 | 211 | */
|
204 | 212 | public function isChildProductsOfEqualPrices(SaleableInterface $product): bool
|
205 | 213 | {
|
206 |
| - $minPrice = $this->getMinRegularAmount()->getValue(); |
207 |
| - $final_price = $product->getFinalPrice(); |
208 |
| - $productId = $product->getId(); |
209 |
| - if ($final_price < $minPrice) { |
210 |
| - return false; |
| 214 | + $storeId = (int) ($product->getStoreId() ?: 0); |
| 215 | + $cacheKey = (int) $product->getId() . ':' . $storeId; |
| 216 | + if (isset($this->equalFinalPriceCache[$cacheKey])) { |
| 217 | + return $this->equalFinalPriceCache[$cacheKey]; |
| 218 | + } |
| 219 | + |
| 220 | + $memoKey = '_children_final_prices_equal_store_' . $storeId; |
| 221 | + $memoized = $product->getData($memoKey); |
| 222 | + if ($memoized !== null) { |
| 223 | + return (bool) $memoized; |
| 224 | + } |
| 225 | + |
| 226 | + // Listing fast-path: if index fields are present, rely on them and avoid any child loading |
| 227 | + $minIndexed = $product->getData('minimal_price'); |
| 228 | + $maxIndexed = $product->getData('max_price'); |
| 229 | + if (is_numeric($minIndexed) && is_numeric($maxIndexed)) { |
| 230 | + $result = ((float)$minIndexed === (float)$maxIndexed); |
| 231 | + $this->equalFinalPriceCache[$cacheKey] = $result; |
| 232 | + $product->setData($memoKey, $result); |
| 233 | + return $result; |
211 | 234 | }
|
212 |
| - $attributes = $product->getTypeInstance()->getConfigurableAttributes($product); |
213 |
| - $items = $attributes->getItems(); |
214 |
| - $options = reset($items); |
215 |
| - $maxPrice = $this->configurableMaxPriceCalculator->getMaxPriceForConfigurableProduct($productId); |
216 |
| - if ($maxPrice == 0) { |
217 |
| - $maxPrice = $this->getMaxRegularAmount()->getValue(); |
| 235 | + |
| 236 | + $children = $product->getTypeInstance()->getUsedProducts($product); |
| 237 | + $firstFinal = null; |
| 238 | + $saleableChildrenCount = 0; |
| 239 | + $allEqual = true; |
| 240 | + foreach ($children as $child) { |
| 241 | + if (!$child->isSalable()) { |
| 242 | + continue; |
| 243 | + } |
| 244 | + $saleableChildrenCount++; |
| 245 | + $value = $child->getPriceInfo()->getPrice('final_price')->getAmount()->getValue(); |
| 246 | + if ($firstFinal === null) { |
| 247 | + $firstFinal = $value; |
| 248 | + continue; |
| 249 | + } |
| 250 | + if ($value != $firstFinal) { |
| 251 | + $allEqual = false; |
| 252 | + break; |
| 253 | + } |
218 | 254 | }
|
219 |
| - return (count($options->getOptions()) > 1) && $minPrice == $maxPrice; |
| 255 | + |
| 256 | + if ($saleableChildrenCount <= 1 || $firstFinal === null || !$allEqual) { |
| 257 | + $product->setData($memoKey, false); |
| 258 | + $this->equalFinalPriceCache[$cacheKey] = false; |
| 259 | + return false; |
| 260 | + } |
| 261 | + |
| 262 | + // Guard against parent-level extra discounts (compute only when children are equal) |
| 263 | + $result = !($product->getFinalPrice() < $firstFinal); |
| 264 | + $this->equalFinalPriceCache[$cacheKey] = $result; |
| 265 | + $product->setData($memoKey, $result); |
| 266 | + return $result; |
220 | 267 | }
|
221 | 268 | }
|
0 commit comments