vendor/pimcore/pimcore/bundles/EcommerceFrameworkBundle/PricingManager/PricingManager.php line 234

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager;
  15. use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartInterface;
  16. use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartPriceModificator\Discount;
  17. use Pimcore\Bundle\EcommerceFrameworkBundle\EventListener\SessionBagListener;
  18. use Pimcore\Bundle\EcommerceFrameworkBundle\Exception\InvalidConfigException;
  19. use Pimcore\Bundle\EcommerceFrameworkBundle\Model\CheckoutableInterface;
  20. use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfoInterface as PriceSystemPriceInfoInterface;
  21. use Pimcore\Targeting\VisitorInfoStorageInterface;
  22. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  23. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  24. use Symfony\Component\OptionsResolver\OptionsResolver;
  25. class PricingManager implements PricingManagerInterface
  26. {
  27.     /**
  28.      * @var bool
  29.      */
  30.     protected $enabled true;
  31.     /**
  32.      * Condition name => class mapping
  33.      *
  34.      * @var array
  35.      */
  36.     protected $conditionMapping = [];
  37.     /**
  38.      * Action name => class mapping
  39.      *
  40.      * @var array
  41.      */
  42.     protected $actionMapping = [];
  43.     /**
  44.      *
  45.      * @deprecated will be removed in Pimcore 11
  46.      *
  47.      * @var SessionInterface
  48.      */
  49.     protected $session;
  50.     /**
  51.      * @var array
  52.      */
  53.     protected $options;
  54.     /**
  55.      * @var VisitorInfoStorageInterface|null
  56.      */
  57.     protected ?VisitorInfoStorageInterface $visitorInfoStorage null;
  58.     /**
  59.      * @var RuleInterface[]|null
  60.      */
  61.     protected $rules;
  62.     public function __construct(
  63.         array $conditionMapping,
  64.         array $actionMapping,
  65.         SessionInterface $session,
  66.         array $options = [],
  67.         VisitorInfoStorageInterface $visitorInfoStorage null
  68.     ) {
  69.         $this->conditionMapping $conditionMapping;
  70.         $this->actionMapping $actionMapping;
  71.         $this->session $session;
  72.         $resolver = new OptionsResolver();
  73.         $this->configureOptions($resolver);
  74.         $this->visitorInfoStorage $visitorInfoStorage;
  75.         $this->options $resolver->resolve($options);
  76.     }
  77.     protected function configureOptions(OptionsResolver $resolver)
  78.     {
  79.         $classProperties = ['rule_class''price_info_class''environment_class'];
  80.         $resolver->setRequired($classProperties);
  81.         $resolver->setDefaults([
  82.             'rule_class' => Rule::class,
  83.             'price_info_class' => PriceInfo::class,
  84.             'environment_class' => Environment::class,
  85.         ]);
  86.         foreach ($classProperties as $classProperty) {
  87.             $resolver->setAllowedTypes($classProperty'string');
  88.         }
  89.     }
  90.     public function setEnabled(bool $enabled)
  91.     {
  92.         $this->enabled $enabled;
  93.     }
  94.     public function isEnabled(): bool
  95.     {
  96.         return $this->enabled;
  97.     }
  98.     /**
  99.      * @param PriceSystemPriceInfoInterface $priceInfo
  100.      *
  101.      * @return PriceSystemPriceInfoInterface
  102.      */
  103.     public function applyProductRules(PriceSystemPriceInfoInterface $priceInfo)
  104.     {
  105.         if (!$this->enabled) {
  106.             return $priceInfo;
  107.         }
  108.         // create new price info with pricing rules
  109.         $priceInfoWithRules $this->getPriceInfo($priceInfo);
  110.         // add all valid rules to the price info
  111.         foreach ($this->getValidRules() as $rule) {
  112.             $priceInfoWithRules->addRule($rule);
  113.         }
  114.         return $priceInfoWithRules;
  115.     }
  116.     /**
  117.      * @param CartInterface $cart
  118.      *
  119.      * @return RuleInterface[]
  120.      */
  121.     public function applyCartRules(CartInterface $cart): array
  122.     {
  123.         $appliedRules = [];
  124.         if (!$this->enabled) {
  125.             return $appliedRules;
  126.         }
  127.         // configure environment
  128.         $env $this->getEnvironment();
  129.         $env->setCart($cart);
  130.         $env->setExecutionMode(EnvironmentInterface::EXECUTION_MODE_CART);
  131.         $env->setProduct(null);
  132.         if ($this->visitorInfoStorage && $this->visitorInfoStorage->hasVisitorInfo()) {
  133.             $env->setVisitorInfo($this->visitorInfoStorage->getVisitorInfo());
  134.         }
  135.         $categories = [];
  136.         foreach ($cart->getItems() as $item) {
  137.             $product $item->getProduct();
  138.             if ($product instanceof CheckoutableInterface && method_exists($product'getCategories')) {
  139.                 $productCategories $product->getCategories();
  140.                 if (is_array($productCategories)) {
  141.                     foreach ($productCategories as $c) {
  142.                         $categories[$c->getId()] = $c;
  143.                     }
  144.                 }
  145.             }
  146.         }
  147.         $env->setCategories(array_values($categories));
  148.         // clean up discount pricing modificators in cart price calculator
  149.         $priceCalculator $cart->getPriceCalculator();
  150.         $priceModificators $priceCalculator->getModificators();
  151.         foreach ($priceModificators as $priceModificator) {
  152.             if ($priceModificator instanceof Discount) {
  153.                 $priceCalculator->removeModificator($priceModificator);
  154.             }
  155.         }
  156.         // execute all valid rules
  157.         foreach ($this->getValidRules() as $rule) {
  158.             $env->setRule($rule);
  159.             // test rule
  160.             if ($rule->check($env) === false) {
  161.                 continue;
  162.             }
  163.             // execute rule
  164.             $rule->executeOnCart($env);
  165.             $appliedRules[] = $rule;
  166.             // is this a stop rule?
  167.             if ($rule->getBehavior() === 'stopExecute') {
  168.                 break;
  169.             }
  170.         }
  171.         return $appliedRules;
  172.     }
  173.     /**
  174.      * @return RuleInterface[]
  175.      */
  176.     public function getValidRules()
  177.     {
  178.         if (is_null($this->rules)) {
  179.             $rules $this->getRuleListing();
  180.             $rules->setCondition('active = 1');
  181.             $rules->setOrderKey('prio');
  182.             $rules->setOrder('ASC');
  183.             $rules->getDao()->setRuleClass($this->options['rule_class']);
  184.             $this->rules $rules->getRules();
  185.         }
  186.         return $this->rules;
  187.     }
  188.     /**
  189.      * @return EnvironmentInterface
  190.      */
  191.     public function getEnvironment()
  192.     {
  193.         /** @var AttributeBagInterface $sessionBag */
  194.         $sessionBag $this->session->getBag(SessionBagListener::ATTRIBUTE_BAG_PRICING_ENVIRONMENT);
  195.         $class $this->options['environment_class'];
  196.         /** @var EnvironmentInterface $environment */
  197.         $environment = new $class();
  198.         $environment->setSession($sessionBag);
  199.         return $environment;
  200.     }
  201.     /**
  202.      * @return Rule\Listing
  203.      */
  204.     public function getRuleListing()
  205.     {
  206.         $class $this->options['rule_class'] . '\\Listing';
  207.         return new $class;
  208.     }
  209.     /**
  210.      * @return array
  211.      */
  212.     public function getConditionMapping(): array
  213.     {
  214.         return $this->conditionMapping;
  215.     }
  216.     /**
  217.      * @return array
  218.      */
  219.     public function getActionMapping(): array
  220.     {
  221.         return $this->actionMapping;
  222.     }
  223.     /**
  224.      * Factory
  225.      *
  226.      * @param string $type
  227.      *
  228.      * @return ConditionInterface
  229.      *
  230.      * @throws InvalidConfigException
  231.      */
  232.     public function getCondition($type)
  233.     {
  234.         if (!isset($this->conditionMapping[$type])) {
  235.             throw new InvalidConfigException(sprintf('ConditionInterface for type "%s" is not registered'$type));
  236.         }
  237.         $class $this->conditionMapping[$type];
  238.         return new $class();
  239.     }
  240.     /**
  241.      * Factory
  242.      *
  243.      * @param string $type
  244.      *
  245.      * @return ActionInterface
  246.      *
  247.      * @throws InvalidConfigException
  248.      */
  249.     public function getAction($type)
  250.     {
  251.         if (!isset($this->actionMapping[$type])) {
  252.             throw new InvalidConfigException(sprintf('ActionInterface for type "%s" is not registered'$type));
  253.         }
  254.         $class $this->actionMapping[$type];
  255.         return new $class();
  256.     }
  257.     /**
  258.      * @param PriceSystemPriceInfoInterface $priceInfo
  259.      *
  260.      * @return PriceInfoInterface
  261.      *
  262.      * @throws InvalidConfigException
  263.      */
  264.     public function getPriceInfo(PriceSystemPriceInfoInterface $priceInfo)
  265.     {
  266.         // TODO make getPriceInfo private as this call is only used internally where the enabled check is alread applied?
  267.         if (!$this->enabled) {
  268.             throw new \RuntimeException('Can\'t build a pricing manager price info as the pricing manager is disabled');
  269.         }
  270.         $class $this->options['price_info_class'];
  271.         // create environment
  272.         $environment $this->getEnvironment();
  273.         $environment->setProduct($priceInfo->getProduct());
  274.         if ($priceInfo->getProduct() && method_exists($priceInfo->getProduct(), 'getCategories')) {
  275.             $environment->setCategories((array)$priceInfo->getProduct()->getCategories());
  276.         }
  277.         if ($this->visitorInfoStorage && $this->visitorInfoStorage->hasVisitorInfo()) {
  278.             $environment->setVisitorInfo($this->visitorInfoStorage->getVisitorInfo());
  279.         }
  280.         $priceInfoWithRules = new $class($priceInfo$environment);
  281.         $environment->setPriceInfo($priceInfoWithRules);
  282.         return $priceInfoWithRules;
  283.     }
  284. }