contacts_events-8.x-1.x-dev/src/Controller/EventController.php

src/Controller/EventController.php
<?php

namespace Drupal\contacts_events\Controller;

use Drupal\commerce_checkout\CheckoutOrderManagerInterface;
use Drupal\commerce_checkout\Resolver\ChainCheckoutFlowResolverInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\contacts_events\Entity\EventInterface;
use Drupal\contacts_events\UserBookingsHelper;
use Drupal\contacts_events\Plugin\Commerce\CheckoutFlow\BookingFlowInterface;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Link;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Messenger\Messenger;
use Drupal\Core\Routing\RedirectDestination;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AccountProxy;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * The event booking controller.
 */
class EventController extends ControllerBase {

  /**
   * Booking settings config object.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $bookingSettings;

  /**
   * The messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The events logger channel.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $loggerChannel;

  /**
   * The lock backend.
   *
   * @var \Drupal\Core\Lock\LockBackendInterface
   */
  protected $lock;

  /**
   * The user bookings helper.
   *
   * @var \Drupal\contacts_events\UserBookingsHelper
   */
  protected $bookingsHelper;

  /**
   * The checkout order manager.
   *
   * @var \Drupal\commerce_checkout\CheckoutOrderManagerInterface
   */
  protected $checkoutOrderManager;

  /**
   * The chain checkout flow resolver.
   *
   * @var \Drupal\commerce_checkout\Resolver\ChainCheckoutFlowResolverInterface
   */
  protected $chainCheckoutFlowResolver;

  /**
   * Constructs a new EventController object.
   */
  public function __construct(EntityTypeManager $entity_type_manager, AccountProxy $current_user, RedirectDestination $redirect_destination, ConfigFactory $config_factory, Messenger $messenger, LoggerChannelInterface $logger_channel, ModuleHandlerInterface $module_handler, LockBackendInterface $lock, UserBookingsHelper $user_bookings_helper, CheckoutOrderManagerInterface $checkout_order_manager, ChainCheckoutFlowResolverInterface $checkout_flow_resolver) {
    $this->entityTypeManager = $entity_type_manager;
    $this->currentUser = $current_user;
    $this->redirectDestination = $redirect_destination;
    $this->configFactory = $config_factory;
    $this->bookingSettings = $this->config('contacts_events.booking_settings');
    $this->messenger = $messenger;
    $this->loggerChannel = $logger_channel;
    $this->moduleHandler = $module_handler;
    $this->lock = $lock;
    $this->bookingsHelper = $user_bookings_helper;
    $this->checkoutOrderManager = $checkout_order_manager;
    $this->chainCheckoutFlowResolver = $checkout_flow_resolver;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('current_user'),
      $container->get('redirect.destination'),
      $container->get('config.factory'),
      $container->get('messenger'),
      $container->get('logger.channel.contacts_events'),
      $container->get('module_handler'),
      $container->get('lock'),
      $container->get('contacts_events.user_bookings'),
      $container->get('commerce_checkout.checkout_order_manager'),
      $container->get('commerce_checkout.chain_checkout_flow_resolver')
    );
  }

  /**
   * Book onto an event.
   *
   * @param \Drupal\contacts_events\Entity\EventInterface $contacts_event
   *   The event to book for.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   The redirection to the checkour process.
   */
  public function book(EventInterface $contacts_event) {
    // Give an anonymous user a chance to log in.
    if ($this->currentUser->isAnonymous()) {
      $url = Url::fromRoute('user.login', [], ['query' => ['destination' => $this->redirectDestination->get()]]);
      return new RedirectResponse($url->toString());
    }

    $access_result = $contacts_event->access('book', $this->currentUser, TRUE);

    // Always deny if explicitly forbidden.
    if ($access_result->isForbidden()) {
      return $this->deniedRedirect($contacts_event, $this->t('Sorry, we were unable to start a booking for %event.', [
        '%event' => $contacts_event->label(),
      ]));
    }

    // Wait for a lock for the next steps to ensure we don't create two bookings
    // for the same event and user.
    $lock_id = 'contacts_events_book_now:' . $this->currentUser->id();
    if (!$this->lock->acquire($lock_id)) {
      $this->lock->wait($lock_id, 10);
      if (!$this->lock->acquire($lock_id)) {
        return $this->deniedRedirect($contacts_event, $this->t('Sorry, there was a temporary problem starting a booking for %event. Please try again.', [
          '%event' => $contacts_event->label(),
        ]));
      }
    }

    // Otherwise, look for an existing order to redirect to.
    $booking = $this->bookingsHelper->findBookingForManager($contacts_event, $this->currentUser);
    if ($booking) {
      /** @var \Drupal\contacts_events\Plugin\Commerce\CheckoutFlow\BookingFlowInterface $flow */
      $flow = $this->getCheckoutFlow($booking);
      return new RedirectResponse($flow->getContinueUrl()->toString());
    }

    if ($this->bookingsHelper->findBookingForTicketHolder($contacts_event, $this->currentUser)) {
      $ticket_holder_text = $this->t('You already have a ticket for %event. You can view all your bookings on your %user_dashboard.', [
        '%event' => $contacts_event->label(),
        '%user_dashboard' => Link::createFromRoute('User Dashboard', 'contacts_events.user_events', ['user' => $this->currentUser->id()])->toString(),
      ]);
      return $this->deniedRedirect($contacts_event, $ticket_holder_text);
    }

    // If we are allowed to book.
    if (!$this->currentUser->hasPermission('can book for contacts_events')) {
      // Release the lock as we are not going to create a booking and redirect
      // to the event page.
      $this->lock->release($lock_id);
      return $this->deniedRedirect($contacts_event);
    }

    // Ensure the system is configured.
    if (!$this->checkConfiguration()) {
      // Release the lock as we are not going to create a booking.
      $this->lock->release($lock_id);

      // If we have permission to update settings, give a directive message.
      $message = NULL;
      if ($this->currentUser->hasPermission('configure contacts events')) {
        $link = Link::createFromRoute($this->t('booking settings'), 'contacts_events.contacts_events_booking_settings_form');
        $message = $this->t('You must configure the @link before booking onto an event.', [
          '@link' => $link->toString(),
        ]);
      }
      return $this->deniedRedirect($contacts_event, $message);
    }

    // Finally allow other modules to deny with a reason.
    $args = [$contacts_event, $this->currentUser];
    foreach ($this->moduleHandler->getImplementations('contacts_events_deny_booking') as $module) {
      $denial_reason = $this->moduleHandler->invoke($module, 'contacts_events_deny_booking', $args);
      if ($denial_reason) {
        // Release the lock as we are not going to create a booking.
        $this->lock->release($lock_id);

        return $this->deniedRedirect($contacts_event, $denial_reason);
      }
    }

    // Build a new booking, redirecting direct into the booking process.
    $booking = $this->createBooking($contacts_event, $this->currentUser);

    // Release the lock now we have created a booking.
    $this->lock->release($lock_id);

    $flow = $this->getCheckoutFlow($booking);
    return new RedirectResponse($flow->getContinueUrl()->toString());
  }

  /**
   * Create a booking for an event and user.
   *
   * @param \Drupal\contacts_events\Entity\EventInterface $event
   *   The event entity.
   * @param \Drupal\Core\Session\AccountInterface|null $account
   *   The user. If not provided, we use the current user.
   *
   * @return \Drupal\commerce_order\Entity\OrderInterface
   *   The created and saved booking, ready to continue.
   */
  protected function createBooking(EventInterface $event, AccountInterface $account = NULL) {
    // If we didn't get an account, use the current user.
    if (!$account) {
      $account = $this->currentUser;
    }

    // Intial values for the booking.
    $values = [
      'type' => 'contacts_booking',
      'store_id' => $this->bookingSettings->get('store_id'),
      'event' => $event->id(),
      'uid' => $account->id(),
      'checkout_step' => 'tickets',
    ];

    // Create, save and return the booking.
    /** @var \Drupal\commerce_order\Entity\OrderInterface $booking */
    $booking = $this->entityTypeManager
      ->getStorage('commerce_order')
      ->create($values);

    // Look for a customer profile we can use for billing records.
    if ($profiles = $booking->collectProfiles()) {
      if (isset($profiles['billing'])) {
        $booking->setBillingProfile($profiles['billing']);
      }
    }

    /** @var \Drupal\contacts_events\Plugin\Commerce\CheckoutFlow\BookingFlowInterface $flow */
    $flow_entity = $this->chainCheckoutFlowResolver->resolve($booking);
    $flow = $flow_entity->getPlugin();
    $flow->setOrder($booking);
    $booking->set('checkout_flow', $flow_entity);
    $booking->set('checkout_step', $flow->getInitialStep());
    $booking->save();
    return $booking;
  }

  /**
   * Get the checkout flow for a booking.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $booking
   *   The booking to get the checkout flow for.
   *
   * @return \Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowInterface
   *   The checkout flow with the relevant booking set.
   */
  protected function getCheckoutFlow(OrderInterface $booking) {
    $flow = $this->checkoutOrderManager->getCheckoutFlow($booking)->getPlugin();
    if ($flow instanceof BookingFlowInterface) {
      $flow->setOrder($booking);
    }
    return $flow;
  }

  /**
   * Check the configuration for bookings.
   *
   * @return bool
   *   Whether the configuration is valid.
   */
  protected function checkConfiguration() {
    // Ensure the system is configured.
    if (!$store_id = $this->bookingSettings->get('store_id')) {
      // Log a critical error if the store is not configured.
      $this->loggerChannel->critical('The system is not correctly configured for bookings.');
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Redirect to the event page with a denied message.
   *
   * @param \Drupal\contacts_events\Entity\EventInterface $event
   *   The event entity.
   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|string|null|false $message
   *   The message to show. NULL will use the default and FALSE will not use
   *   one.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   The redirect response.
   */
  protected function deniedRedirect(EventInterface $event, $message = NULL) {
    // Set the default message.
    if (!isset($message)) {
      $message = $this->t('Sorry, we were unable to start a booking for %event', [
        '%event' => $event->label(),
      ]);
    }

    // Show the message if there is one.
    if ($message) {
      $this->messenger->addError($message);
    }

    // Redirect to the event page.
    return new RedirectResponse($event->toUrl()->toString());
  }

}

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

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