vendor/shopware/core/Content/Product/DataAbstractionLayer/CheapestPrice/CheapestPriceContainer.php line 12

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice;
  3. use Shopware\Core\Checkout\Cart\Price\Struct\CartPrice;
  4. use Shopware\Core\Defaults;
  5. use Shopware\Core\Framework\Context;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\PriceCollection;
  8. use Shopware\Core\Framework\Log\Package;
  9. use Shopware\Core\Framework\Struct\Struct;
  10. #[Package('core')]
  11. class CheapestPriceContainer extends Struct
  12. {
  13.     /**
  14.      * @var array<mixed>
  15.      */
  16.     protected array $value;
  17.     /**
  18.      * @var array<mixed>|null
  19.      */
  20.     protected ?array $default null;
  21.     /**
  22.      * @var list<string>|null
  23.      */
  24.     private ?array $ruleIds null;
  25.     /**
  26.      * @param array<mixed> $value
  27.      */
  28.     public function __construct(array $value)
  29.     {
  30.         if (isset($value['default'])) {
  31.             $this->default $value['default'];
  32.             unset($value['default']);
  33.         }
  34.         $this->value $value;
  35.     }
  36.     public function resolve(Context $context): ?CheapestPrice
  37.     {
  38.         $ruleIds $context->getRuleIds();
  39.         $ruleIds[] = 'default';
  40.         $prices = [];
  41.         $defaultWasAdded false;
  42.         foreach ($this->value as $variantId => $group) {
  43.             foreach ($ruleIds as $ruleId) {
  44.                 $price $this->filterByRuleId($group$ruleId$defaultWasAdded);
  45.                 if ($price === null) {
  46.                     continue;
  47.                 }
  48.                 // overwrite the variantId in case the default price was added
  49.                 $price['variant_id'] = $variantId;
  50.                 $prices[] = $price;
  51.                 break;
  52.             }
  53.         }
  54.         if (empty($prices)) {
  55.             return null;
  56.         }
  57.         $cheapest array_shift($prices);
  58.         $reference $this->getPriceValue($cheapest$context);
  59.         $hasRange = (bool) $cheapest['is_ranged'];
  60.         // NEXT-21735 - This is covered randomly
  61.         // @codeCoverageIgnoreStart
  62.         foreach ($prices as $price) {
  63.             $current $this->getPriceValue($price$context);
  64.             if ($current === null) {
  65.                 continue;
  66.             }
  67.             if ($current !== $reference || $price['is_ranged']) {
  68.                 $hasRange true;
  69.             }
  70.             if ($current $reference) {
  71.                 $reference $current;
  72.                 $cheapest $price;
  73.             }
  74.         }
  75.         // @codeCoverageIgnoreEnd
  76.         $object = new CheapestPrice();
  77.         $object->setRuleId($cheapest['rule_id']);
  78.         $object->setVariantId($cheapest['variant_id']);
  79.         $object->setParentId($cheapest['parent_id']);
  80.         $object->setHasRange($hasRange);
  81.         $object->setPurchase($cheapest['purchase_unit'] ? (float) $cheapest['purchase_unit'] : null);
  82.         $object->setReference($cheapest['reference_unit'] ? (float) $cheapest['reference_unit'] : null);
  83.         $object->setUnitId($cheapest['unit_id'] ?? null);
  84.         $prices = [];
  85.         $blueprint = new Price(''11true);
  86.         foreach ($cheapest['price'] as $row) {
  87.             $price = clone $blueprint;
  88.             $price->setCurrencyId($row['currencyId']);
  89.             $price->setGross((float) $row['gross']);
  90.             $price->setNet((float) $row['net']);
  91.             $price->setLinked((bool) $row['linked']);
  92.             if (isset($row['listPrice'])) {
  93.                 $list = clone $blueprint;
  94.                 $list->setCurrencyId($row['currencyId']);
  95.                 $list->setGross((float) $row['listPrice']['gross']);
  96.                 $list->setNet((float) $row['listPrice']['net']);
  97.                 $list->setLinked((bool) $row['listPrice']['linked']);
  98.                 $price->setListPrice($list);
  99.             }
  100.             if (isset($row['regulationPrice'])) {
  101.                 $regulation = clone $blueprint;
  102.                 $regulation->setCurrencyId($row['currencyId']);
  103.                 $regulation->setGross((float) $row['regulationPrice']['gross']);
  104.                 $regulation->setNet((float) $row['regulationPrice']['net']);
  105.                 $regulation->setLinked((bool) $row['regulationPrice']['linked']);
  106.                 $price->setRegulationPrice($regulation);
  107.             }
  108.             if (isset($row['percentage'])) {
  109.                 $price->setPercentage([
  110.                     'gross' => $row['percentage']['gross'],
  111.                     'net' => $row['percentage']['net'],
  112.                 ]);
  113.             }
  114.             $prices[] = $price;
  115.         }
  116.         $object->setPrice(new PriceCollection($prices));
  117.         return $object;
  118.     }
  119.     public function getApiAlias(): string
  120.     {
  121.         return 'cheapest_price_container';
  122.     }
  123.     /**
  124.      * @return array<mixed>
  125.      */
  126.     public function getValue(): array
  127.     {
  128.         return $this->value;
  129.     }
  130.     /**
  131.      * @return array<mixed>
  132.      */
  133.     public function getPricesForVariant(string $variantId): array
  134.     {
  135.         return $this->value[$variantId] ?? [];
  136.     }
  137.     /**
  138.      * @return array<string>
  139.      */
  140.     public function getVariantIds(): array
  141.     {
  142.         return \array_keys($this->value);
  143.     }
  144.     /**
  145.      * @return array<mixed>
  146.      */
  147.     public function getDefault(): ?array
  148.     {
  149.         return $this->default;
  150.     }
  151.     /**
  152.      * @return list<string>
  153.      */
  154.     public function getRuleIds(): array
  155.     {
  156.         if ($this->ruleIds === null) {
  157.             $ruleIds = [];
  158.             foreach ($this->value as $group) {
  159.                 foreach ($group as $price) {
  160.                     /** @var string|null $ruleId */
  161.                     $ruleId $price['rule_id'] ?? null;
  162.                     if ($ruleId === null) {
  163.                         continue;
  164.                     }
  165.                     $ruleIds[$price['rule_id']] = true;
  166.                 }
  167.             }
  168.             /** @var list<string> $ruleIds */
  169.             $ruleIds array_keys($ruleIds);
  170.             $this->ruleIds $ruleIds;
  171.         }
  172.         return $this->ruleIds;
  173.     }
  174.     /**
  175.      * @param array<mixed> $prices
  176.      *
  177.      * @return array<mixed>|null
  178.      */
  179.     private function filterByRuleId(array $pricesstring $ruleIdbool &$defaultWasAdded): ?array
  180.     {
  181.         if (\array_key_exists($ruleId$prices)) {
  182.             // Null Price is the marker that the default price is inherited
  183.             if ($prices[$ruleId] === null && !$defaultWasAdded) {
  184.                 // Make sure to add the default price only once, to not bloat up the intermediate prices array
  185.                 $defaultWasAdded true;
  186.                 return $this->default;
  187.             }
  188.             return $prices[$ruleId];
  189.         }
  190.         return null;
  191.     }
  192.     /**
  193.      * @param array<mixed> $price
  194.      */
  195.     private function getPriceValue(array $priceContext $context): ?float
  196.     {
  197.         $currency $this->getCurrencyPrice($price['price'], $context->getCurrencyId());
  198.         if (!$currency) {
  199.             return null;
  200.         }
  201.         $value $context->getTaxState() === CartPrice::TAX_STATE_GROSS $currency['gross'] : $currency['net'];
  202.         if ($currency['currencyId'] !== $context->getCurrencyId()) {
  203.             $value *= $context->getCurrencyFactor();
  204.         }
  205.         return $value;
  206.     }
  207.     /**
  208.      * @param array<mixed> $collection
  209.      *
  210.      * @return array<mixed>|null
  211.      */
  212.     private function getCurrencyPrice(array $collectionstring $currencyIdbool $fallback true): ?array
  213.     {
  214.         foreach ($collection as $price) {
  215.             if ($price['currencyId'] === $currencyId) {
  216.                 return $price;
  217.             }
  218.         }
  219.         if (!$fallback) {
  220.             return null;
  221.         }
  222.         return $this->getCurrencyPrice($collectionDefaults::CURRENCYfalse);
  223.     }
  224. }