contacts_events-8.x-1.x-dev/src/Entity/OrderItemHooks.php

src/Entity/OrderItemHooks.php
<?php

namespace Drupal\contacts_events\Entity;

use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\contacts_events\OrderItemStateTrait;
use Drupal\contacts_events\Plugin\Commerce\CheckoutFlow\BookingFlow;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\CurrentRouteMatch;
use Drupal\Core\Session\AccountInterface;

/**
 * Implementations for Order Item hooks.
 */
class OrderItemHooks {

  use OrderItemStateTrait;

  /**
   * The current route match.
   *
   * @var \Drupal\Core\Routing\CurrentRouteMatch
   */
  protected $routeMatch;

  /**
   * Construct the OrderItemHooks service.
   *
   * @param \Drupal\Core\Routing\CurrentRouteMatch $route_match
   *   The current route match.
   */
  public function __construct(CurrentRouteMatch $route_match) {
    $this->routeMatch = $route_match;
  }

  /**
   * Access checks for order items.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $item
   *   The order item.
   * @param string $operation
   *   The operation being checked.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account performing the operation.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  public function access(OrderItemInterface $item, $operation, AccountInterface $account) {
    // Only change access for booking order types.
    if ($item->getOrder()->bundle() == 'contacts_booking') {
      $method = "{$operation}Access";
      if (method_exists($this, $method)) {
        return $this->{$method}($item, $account);
      }
    }

    return AccessResult::neutral();
  }

  /**
   * Update access check for order items.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $item
   *   The order item.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account performing the operation.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  protected function updateAccess(OrderItemInterface $item, AccountInterface $account) {
    // For additional charges, only staff can add/edit them.
    if ($item->bundle() == 'additional_charge') {
      return AccessResult::allowedIfHasPermission($account, 'can manage bookings for contacts_events');
    }

    // Forbid if the item is confirmed. It should only be cancelled.
    $order = $item->getOrder();
    $result = AccessResult::allowedIf($account->isAuthenticated() && $order->getCustomerId() == $account->id())
      ->addCacheableDependency($item)
      ->addCacheableDependency($order)
      ->addCacheableDependency($account);

    if ($item->hasField('state')) {
      $result = $result->andIf(AccessResult::allowedIf($item->get('state')->value == 'pending'));
    }

    return $result;
  }

  /**
   * Delete access check for order items.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $item
   *   The order item.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account performing the operation.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  protected function deleteAccess(OrderItemInterface $item, AccountInterface $account) {
    // For additional charges, only staff can add/edit them.
    if ($item->bundle() == 'additional_charge') {
      return AccessResult::allowedIfHasPermission($account, 'can manage bookings for contacts_events');
    }

    // Globally forbid if the item is confirmed. It should only be cancelled.
    if ($item->hasField('state') && $item->get('state')->value != 'pending') {
      return AccessResult::forbidden()
        ->addCacheableDependency($item);
    }

    // Otherwise use the same rules as update access.
    return $this->updateAccess($item, $account);
  }

  /**
   * Create access check for order items.
   *
   * @param string $entity_bundle
   *   The bundle to be created.
   * @param array $context
   *   The context, if any.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account performing the operation.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  public function createAccess($entity_bundle, array $context, AccountInterface $account) {
    // Inline entity form doesn't give us any context, so if we are on the
    // checkout tickets page, we will assume this is a check for adding a ticket
    // and allow access if the order from the route belongs to the user we're
    // checking access for.
    // @todo See if we can get InlineEntityForm to provide some context.
    // @todo Expand this for non ticket line items.
    if ($entity_bundle == 'contacts_ticket' && $this->routeMatch->getRouteName() == BookingFlow::ROUTE_NAME) {
      /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
      $order = $this->routeMatch->getParameter('commerce_order');
      return AccessResult::allowedIf($account->isAuthenticated() && $order->getCustomerId() == $account->id())
        ->addCacheableDependency($order)
        ->addCacheableDependency($account);
    }
    elseif ($entity_bundle == 'additional_charge') {
      return AccessResult::allowedIfHasPermission($account, 'can manage bookings for contacts_events');
    }

    return AccessResult::neutral();
  }

  /**
   * Cancel access check for order items.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $item
   *   The order item.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account performing the operation.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  public function cancelAccess(OrderItemInterface $item, AccountInterface $account) {
    if (!$item->hasField('state')) {
      return AccessResult::forbidden()->addCacheableDependency($item);
    }

    // Get our state and workflow.
    /** @var \Drupal\state_machine\Plugin\Field\FieldType\StateItemInterface $state */
    $state = $item->get('state')->first();
    $workflow = $state->getWorkflow();

    // Check if the cancel transition is allowed.
    /** @var \Drupal\workflows\Transition[] $transitions */
    $transitions = $workflow->getAllowedTransitions($state->value, $item);
    if (!isset($transitions['cancel'])) {
      return AccessResult::forbidden('Cancel transition unavailable.')
        ->addCacheableDependency($item);
    }

    return AccessResult::allowedIfHasPermission($account, 'can manage bookings for contacts_events')
      ->addCacheableDependency($item);
  }

  /**
   * React to an order item being deleted.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
   *   The order item.
   */
  public function delete(OrderItemInterface $order_item) {
    // Clean up single use purchasable entities.
    $purchased_entity = $order_item->getPurchasedEntity();
    if ($purchased_entity instanceof SingleUsePurchasableEntityInterface) {
      $purchased_entity->delete();
    }
  }

  /**
   * Pre-save for order items.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
   *   The order item.
   * @param \Drupal\commerce_order\Entity\OrderItemInterface|null $original
   *   The original order item, if any.
   */
  public function preSave(OrderItemInterface $order_item, OrderItemInterface $original = NULL): void {
    if (!$order_item->hasField('state')) {
      return;
    }

    // Nothing to do if this is a new item, has no original or is pending.
    if (!$original || $order_item->isNew() || $order_item->get('state')->value == 'pending') {
      return;
    }

    // If there is already a transition happening, we don't want to interfere.
    if ($order_item->get('state')->value != $original->get('state')->value) {
      return;
    }

    // See if the price has changed.
    $total = $order_item->getAdjustedTotalPrice();
    $original_total = $original->getAdjustedTotalPrice();
    if (($total xor $original_total) || (!$total && !$original_total) || !$total->equals($original_total)) {
      // If it has changed, check the state of the order item.
      $this->checkOrderItemStatus($order_item);
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc