You are here

class CartUnifier in Commerce Combine Carts 8

Hierarchy

Expanded class hierarchy of CartUnifier

1 file declares its use of CartUnifier
CartEventSubscriber.php in src/EventSubscriber/CartEventSubscriber.php
1 string reference to 'CartUnifier'
commerce_combine_carts.services.yml in ./commerce_combine_carts.services.yml
commerce_combine_carts.services.yml
1 service uses CartUnifier
commerce_combine_carts.cart_unifier in ./commerce_combine_carts.services.yml
Drupal\commerce_combine_carts\CartUnifier

File

src/CartUnifier.php, line 14

Namespace

Drupal\commerce_combine_carts
View source
class CartUnifier {

  /** @var \Drupal\commerce_cart\CartProviderInterface */
  protected $cartProvider;

  /** @var \Drupal\commerce_cart\CartManagerInterface */
  protected $cartManager;

  /** @var \Drupal\Core\Routing\RouteMatchInterface $routeMatch */
  protected $routeMatch;

  /**
   * CartUnifier constructor.
   *
   * @param \Drupal\commerce_cart\CartProviderInterface $cart_provider
   *   The cart provider.
   * @param \Drupal\commerce_cart\CartManagerInterface $cart_manager
   *   The cart manager.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match.
   */
  public function __construct(CartProviderInterface $cart_provider, CartManagerInterface $cart_manager, RouteMatchInterface $route_match) {
    $this->cartProvider = $cart_provider;
    $this->cartManager = $cart_manager;
    $this->routeMatch = $route_match;
  }

  /**
   * Returns main carts, one per order type.
   *
   * @param \Drupal\user\UserInterface $user
   *   The user.
   *
   * @return \Drupal\commerce_order\Entity\OrderInterface[]|NULL
   *   The main carts for the user, or NULL if there is no cart.
   */
  public function getMainCarts(UserInterface $user) {

    // Clear cart cache so that newly assigned carts are available.
    $this->cartProvider
      ->clearCaches();
    $carts = $this->cartProvider
      ->getCarts($user);
    if (empty($carts)) {
      return NULL;
    }

    // Loop over carts. If there are several of the same type, we overwrite it
    // with the latest one.
    $carts_per_type = [];
    foreach ($carts as $cart) {
      $carts_per_type[$cart
        ->bundle()] = $cart;
    }
    return $carts_per_type;
  }

  /**
   * Assign a cart to a user, possibly moving items to the user's main cart.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $cart
   *   The cart to assign.
   * @param \Drupal\user\UserInterface $user
   *   The user.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function assignCart(OrderInterface $cart, UserInterface $user) {
    $main_carts = $this
      ->getMainCarts($user);
    if ($main_carts) {
      foreach ($main_carts as $main_cart) {
        if ($cart
          ->bundle() != $main_cart
          ->bundle()) {
          continue;
        }
        if ($this
          ->isCartRequestedForCheckout($cart)) {
          $this
            ->combineCarts($cart, $main_cart, FALSE);
        }
        else {
          $this
            ->combineCarts($main_cart, $cart, FALSE);
        }
      }
    }
  }

  /**
   * Combines all of a user's carts into their main cart.
   *
   * @param \Drupal\user\UserInterface $user
   *   The user.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function combineUserCarts(UserInterface $user) {
    $main_carts = $this
      ->getMainCarts($user);
    if ($main_carts) {
      foreach ($main_carts as $main_cart) {
        foreach ($this->cartProvider
          ->getCarts($user) as $cart) {
          if ($cart
            ->bundle() != $main_cart
            ->bundle()) {
            continue;
          }
          $this
            ->combineCarts($main_cart, $cart, TRUE);
        }
      }
    }
  }

  /**
   * Combines another cart into the main cart and optionally deletes the other
   * cart.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $main_cart
   *   The main cart.
   * @param \Drupal\commerce_order\Entity\OrderInterface $other_cart
   *   The other cart.
   * @param bool $delete
   *   TRUE to delete the other cart when finished, FALSE to save it as empty.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function combineCarts(OrderInterface $main_cart, OrderInterface $other_cart, $delete = FALSE) {
    if ($main_cart
      ->id() === $other_cart
      ->id()) {
      return;
    }
    if ($this
      ->isCartRequestedForCheckout($other_cart)) {
      return $this
        ->combineCarts($other_cart, $main_cart, $delete);
    }
    foreach ($other_cart
      ->getItems() as $item) {
      $other_cart
        ->removeItem($item);
      $item
        ->get('order_id')->entity = $main_cart;
      $combine = $this
        ->shouldCombineItem($item);
      $this->cartManager
        ->addOrderItem($main_cart, $item, $combine);
    }
    $main_cart
      ->save();
    if ($delete) {
      $other_cart
        ->delete();
    }
    else {
      $other_cart
        ->save();
    }
  }

  /**
   * Determine if a line item should be combined with like items.
   *
   * @param OrderItemInterface $item
   *   The order item.
   *
   * @return bool
   *   TRUE if items should be combined, FALSE otherwise.
   */
  private function shouldCombineItem(OrderItemInterface $item) {

    /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $purchased_entity */
    $purchased_entity = $item
      ->getPurchasedEntity();

    // Do not combine products which are no longer available in system.
    if (!$purchased_entity instanceof ProductVariationInterface) {
      return FALSE;
    }
    $product = $purchased_entity
      ->getProduct();
    $entity_display = EntityViewDisplay::load($product
      ->getEntityTypeId() . '.' . $product
      ->bundle() . '.default');
    $combine = TRUE;
    if ($component = $entity_display
      ->getComponent('variations')) {
      $combine = !empty($component['settings']['combine']);
    }
    return $combine;
  }

  /**
   * Returns the cart requested for checkout.
   *
   * @return \Drupal\commerce_order\Entity\OrderInterface|null
   */
  protected function getCartRequestedForCheckout() {
    if ($this->routeMatch
      ->getRouteName() === 'commerce_checkout.form') {
      $requested_order = $this->routeMatch
        ->getParameter('commerce_order');
      if ($requested_order) {
        return $requested_order;
      }
    }
    return NULL;
  }

  /**
   * Returns TRUE if given cart is requested for checkout.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $cart
   *
   * @return bool
   */
  protected function isCartRequestedForCheckout(OrderInterface $cart) {
    $requested_cart = $this
      ->getCartRequestedForCheckout();
    return $requested_cart && $requested_cart
      ->id() === $cart
      ->id();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CartUnifier::$cartManager protected property @var \Drupal\commerce_cart\CartManagerInterface
CartUnifier::$cartProvider protected property @var \Drupal\commerce_cart\CartProviderInterface
CartUnifier::$routeMatch protected property @var \Drupal\Core\Routing\RouteMatchInterface $routeMatch
CartUnifier::assignCart public function Assign a cart to a user, possibly moving items to the user's main cart.
CartUnifier::combineCarts public function Combines another cart into the main cart and optionally deletes the other cart.
CartUnifier::combineUserCarts public function Combines all of a user's carts into their main cart.
CartUnifier::getCartRequestedForCheckout protected function Returns the cart requested for checkout.
CartUnifier::getMainCarts public function Returns main carts, one per order type.
CartUnifier::isCartRequestedForCheckout protected function Returns TRUE if given cart is requested for checkout.
CartUnifier::shouldCombineItem private function Determine if a line item should be combined with like items.
CartUnifier::__construct public function CartUnifier constructor.