You are here

class PriceCalculator in Commerce Core 8.2

Hierarchy

Expanded class hierarchy of PriceCalculator

1 string reference to 'PriceCalculator'
commerce_order.services.yml in modules/order/commerce_order.services.yml
modules/order/commerce_order.services.yml
1 service uses PriceCalculator
commerce_order.price_calculator in modules/order/commerce_order.services.yml
Drupal\commerce_order\PriceCalculator

File

modules/order/src/PriceCalculator.php, line 12

Namespace

Drupal\commerce_order
View source
class PriceCalculator implements PriceCalculatorInterface {

  /**
   * The adjustment transformer.
   *
   * @var \Drupal\commerce_order\AdjustmentTransformerInterface
   */
  protected $adjustmentTransformer;

  /**
   * The chain order type resolver.
   *
   * @var \Drupal\commerce_order\Resolver\ChainOrderTypeResolverInterface
   */
  protected $chainOrderTypeResolver;

  /**
   * The chain price resolver.
   *
   * @var \Drupal\commerce_price\Resolver\ChainPriceResolverInterface
   */
  protected $chainPriceResolver;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The order processors.
   *
   * @var \Drupal\commerce_order\OrderProcessorInterface[]
   */
  protected $processors = [];

  /**
   * The unsaved orders used for calculations.
   *
   * @var \Drupal\commerce_order\Entity\OrderInterface[]
   */
  protected $orders = [];

  /**
   * Constructs a new PriceCalculator object.
   *
   * @param \Drupal\commerce_order\AdjustmentTransformerInterface $adjustment_transformer
   *   The adjustment transformer.
   * @param \Drupal\commerce_order\Resolver\ChainOrderTypeResolverInterface $chain_order_type_resolver
   *   The chain order type resolver.
   * @param \Drupal\commerce_price\Resolver\ChainPriceResolverInterface $chain_price_resolver
   *   The chain price resolver.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   */
  public function __construct(AdjustmentTransformerInterface $adjustment_transformer, ChainOrderTypeResolverInterface $chain_order_type_resolver, ChainPriceResolverInterface $chain_price_resolver, EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack) {
    $this->adjustmentTransformer = $adjustment_transformer;
    $this->chainOrderTypeResolver = $chain_order_type_resolver;
    $this->chainPriceResolver = $chain_price_resolver;
    $this->entityTypeManager = $entity_type_manager;
    $this->requestStack = $request_stack;
  }

  /**
   * {@inheritdoc}
   */
  public function addProcessor(OrderProcessorInterface $processor, $adjustment_type) {
    $this->processors[$adjustment_type][] = $processor;
  }

  /**
   * {@inheritdoc}
   */
  public function getProcessors($adjustment_type) {
    if (!isset($this->processors[$adjustment_type])) {
      return [];
    }
    return $this->processors[$adjustment_type];
  }

  /**
   * {@inheritdoc}
   */
  public function calculate(PurchasableEntityInterface $purchasable_entity, $quantity, Context $context, array $adjustment_types = []) {
    $resolved_price = $this->chainPriceResolver
      ->resolve($purchasable_entity, $quantity, $context);
    $processors = [];
    foreach ($adjustment_types as $adjustment_type) {
      $processors = array_merge($processors, $this
        ->getProcessors($adjustment_type));
    }
    if (empty($adjustment_types) || empty($processors)) {
      return new PriceCalculatorResult($resolved_price, $resolved_price);
    }

    /** @var \Drupal\commerce_order\OrderItemStorageInterface $order_item_storage */
    $order_item_storage = $this->entityTypeManager
      ->getStorage('commerce_order_item');
    $order_item = $order_item_storage
      ->createFromPurchasableEntity($purchasable_entity);
    $order_item
      ->setUnitPrice($resolved_price);
    $order_item
      ->setQuantity($quantity);
    $order_type_id = $this->chainOrderTypeResolver
      ->resolve($order_item);
    $order = $this
      ->prepareOrder($order_type_id, $context);
    $order_item->order_id = $order;
    $order
      ->setItems([
      $order_item,
    ]);

    // Allow each selected processor to add its adjustments.
    foreach ($processors as $processor) {
      $processor
        ->process($order);
    }
    $calculated_price = $order_item
      ->getAdjustedTotalPrice();
    $adjustments = $order_item
      ->getAdjustments();
    $adjustments = $this->adjustmentTransformer
      ->processAdjustments($adjustments);
    return new PriceCalculatorResult($calculated_price, $resolved_price, $adjustments);
  }

  /**
   * Prepares an unsaved order for the given type/context.
   *
   * @param string $order_type_id
   *   The order type ID.
   * @param \Drupal\commerce\Context $context
   *   The context.
   *
   * @return \Drupal\commerce_order\Entity\OrderInterface
   *   The order.
   */
  protected function prepareOrder($order_type_id, Context $context) {
    if (!isset($this->orders[$order_type_id])) {
      $order_storage = $this->entityTypeManager
        ->getStorage('commerce_order');
      $this->orders[$order_type_id] = $order_storage
        ->create([
        'type' => $order_type_id,
        'ip_address' => $this->requestStack
          ->getCurrentRequest()
          ->getClientIp(),
        // Provide a flag that can be used in the order create hook/event
        // to identify orders used for price calculation purposes.
        'data' => [
          'provider' => 'order_price_calculator',
        ],
      ]);
    }
    $order = $this->orders[$order_type_id];

    // Make sure that the order data matches the data passed in the context.
    $order
      ->setStoreId($context
      ->getStore()
      ->id());
    $order
      ->setCustomerId($context
      ->getCustomer()
      ->id());
    $order
      ->setEmail($context
      ->getCustomer()
      ->getEmail());

    // Start from a clear set of adjustments each time.
    $order
      ->clearAdjustments();
    return $order;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
PriceCalculator::$adjustmentTransformer protected property The adjustment transformer.
PriceCalculator::$chainOrderTypeResolver protected property The chain order type resolver.
PriceCalculator::$chainPriceResolver protected property The chain price resolver.
PriceCalculator::$entityTypeManager protected property The entity type manager.
PriceCalculator::$orders protected property The unsaved orders used for calculations.
PriceCalculator::$processors protected property The order processors.
PriceCalculator::$requestStack protected property The request stack.
PriceCalculator::addProcessor public function Adds an order processor for the given adjustment type. Overrides PriceCalculatorInterface::addProcessor
PriceCalculator::calculate public function Calculates a purchasable entity's price. Overrides PriceCalculatorInterface::calculate
PriceCalculator::getProcessors public function Gets all order processors for the given adjustment type. Overrides PriceCalculatorInterface::getProcessors
PriceCalculator::prepareOrder protected function Prepares an unsaved order for the given type/context.
PriceCalculator::__construct public function Constructs a new PriceCalculator object.