contacts_events-8.x-1.x-dev/modules/teams/src/Controller/TeamApplicationController.php

modules/teams/src/Controller/TeamApplicationController.php
<?php

namespace Drupal\contacts_events_teams\Controller;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\contacts_events\Entity\TicketInterface;
use Drupal\contacts_events_teams\Entity\TeamApplication;
use Drupal\contacts_events_teams\Plugin\TeamApplicationStep\TeamApplicationStepManager;
use Drupal\contacts_events_teams\TeamQueries;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
use Drupal\Core\Plugin\Context\EntityContext;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\user\Entity\User;
use Drupal\user\UserInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Controller for managing team application process.
 *
 * @package Drupal\contacts_events_teams\Controller
 */
class TeamApplicationController extends ControllerBase {

  /**
   * Team app step manager.
   *
   * @var \Drupal\contacts_events_teams\Plugin\TeamApplicationStep\TeamApplicationStepManager
   */
  protected $stepManager;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * The team queries service.
   *
   * @var \Drupal\contacts_events_teams\TeamQueries
   */
  protected $queries;

  /**
   * The time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * The block manager service.
   *
   * @var \Drupal\Core\Block\BlockManagerInterface
   */
  protected $blockManager;

  /**
   * Plugin context handler.
   *
   * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
   */
  protected $contextHandler;

  /**
   * Reference field helper.
   *
   * @var \Drupal\contacts_references\ReferenceFieldHelper
   */
  protected $referenceFieldHelper;

  /**
   * TeamApplicationController constructor.
   *
   * @param \Drupal\contacts_events_teams\Plugin\TeamApplicationStep\TeamApplicationStepManager $step_manager
   *   Application step plugin manager.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   * @param \Drupal\contacts_events_teams\TeamQueries $queries
   *   The team queries service.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time service.
   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
   *   The block manager service.
   * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
   *   The context handler service.
   */
  public function __construct(TeamApplicationStepManager $step_manager, DateFormatterInterface $date_formatter, TeamQueries $queries, TimeInterface $time, BlockManagerInterface $block_manager, ContextHandlerInterface $context_handler) {
    $this->stepManager = $step_manager;
    $this->dateFormatter = $date_formatter;
    $this->queries = $queries;
    $this->time = $time;
    $this->blockManager = $block_manager;
    $this->contextHandler = $context_handler;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('plugin.manager.team_application_step'),
      $container->get('date.formatter'),
      $container->get('contacts_events_teams.queries'),
      $container->get('datetime.time'),
      $container->get('plugin.manager.block'),
      $container->get('context.handler')
    );
  }

  /**
   * Determines whether the team application can be accessed (apply).
   *
   * @param \Drupal\contacts_events\Entity\TicketInterface $contacts_ticket
   *   The ticket we want to apply for.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user account.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   Access result.
   */
  public function accessApplication(TicketInterface $contacts_ticket, AccountInterface $account) {
    // Forbid access for any status other than currently in progress.
    if ($contacts_ticket->getStatus() != 'team_app_in_progress') {
      return AccessResult::forbidden('Team application is not in progress.')
        ->addCacheableDependency($contacts_ticket);
    }

    // Allow if the ticket owner matches the current user.
    $result = AccessResult::allowedIf($contacts_ticket->getTicketHolderId() === (int) $account->id())
      ->addCacheableDependency($contacts_ticket)
      ->addCacheContexts(['user']);

    // Also allow if user has the right permission.
    return $result->orIf(AccessResult::allowedIfHasPermission($account, 'manage all contacts events team applications'));
  }

  /**
   * The team application process.
   *
   * @param \Drupal\contacts_events\Entity\TicketInterface $contacts_ticket
   *   The ticket we want to apply for.
   * @param string|null $step
   *   The step of the application form to show..
   *
   * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
   *   Render array or redirect response.
   */
  public function apply(TicketInterface $contacts_ticket, ?string $step) {
    // If this is not a team ticket, redirect with a message.
    if (!$contacts_ticket->get('is_team_ticket')->value) {
      $this->messenger()->addWarning($this->t('Your booking manager has not indicated that you wish to apply for a team place. Please ask them to update the details on your booking to continue.'));
      return $this->redirect('contacts_events_teams.my_teams', [
        'user' => $contacts_ticket->getTicketHolderId(),
      ]);
    }

    $app = $this->queries->getTeamApplicationForTicket($contacts_ticket);

    // Redirect back to the user dashboard if the application is already
    // submitted.
    if ($app && $app->isSubmitted()) {
      // If the application is already submitted, just redirect back to the
      // booking summary.
      $this->messenger()->addMessage("Your application has already been submitted. You can track the status of your application from your 'My Account' page.");
      // @todo Assume this should redirect somewhere different if applicant
      // is not booking manager?
      return $this->redirect('contacts_events_teams.my_teams', [
        'user' => $contacts_ticket->getTicketHolderId(),
      ]);
    }

    $progress = $this->stepManager->getProgressIndicator($contacts_ticket, $step);
    // Show our step form.
    $step = $this->stepManager->getStepForm($contacts_ticket, $step);
    if ($step == NULL) {
      throw new NotFoundHttpException();
    }

    return [$progress, $step];
  }

  /**
   * Lists team applications for a user.
   *
   * @param \Drupal\user\Entity\User $user
   *   The user.
   *
   * @return array
   *   Render array.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function myActiveTeams(User $user) {
    /** @var \Drupal\contacts_events\Entity\TicketInterface[] $tickets */
    $tickets = $this->loadTeamTickets($user);

    $build['table'] = [
      '#type' => 'table',
      '#header' => [
        'event' => $this->t('Event'),
        'date' => $this->t('Date'),
        'team' => $this->t('Team'),
        'status' => $this->t('Status'),
      ],
      '#rows' => [],
      '#empty' => $this->t("You don't have any active team applications. To apply for team, please book onto an event and select to be on team when adding your ticket."),
    ];

    $has_actions = FALSE;
    $check_references = FALSE;
    $has_references = FALSE;

    if ($this->moduleHandler()->moduleExists('contacts_references')) {
      $check_references = TRUE;
      $this->referenceFieldHelper = \Drupal::service('contacts_references.reference_field_helper');
    }

    foreach ($tickets as $ticket) {
      if ($ticket->getStatus() == 'pending') {
        continue;
      }

      /** @var \Drupal\contacts_events\Entity\EventInterface $event */
      $event = $ticket->get('event')->entity;
      $app = $this->queries->getTeamApplicationForTicket($ticket);

      $row = [
        'event' => $event->label(),
        'date' => $this->dateFormatter->format($event->get('date')->start_date->getTimestamp(), 'short'),
        'team' => $ticket->team->entity->label(),
        'status' => $this->getStatus($app),
      ];

      if ($check_references) {
        $reference_status = $this->getReferenceStatus($app);

        if ($reference_status) {
          $has_references = TRUE;
          $row['references'] = $reference_status;
        }
      }

      if (!$app || $app->get('state')->value === 'draft') {
        $has_actions = TRUE;
        $text = $app ? $this->t('Continue application') : $this->t('Start application');
        $row['action'] = Link::createFromRoute($text,
          'contacts_events_teams.application_flow',
          ['contacts_ticket' => $ticket->id()]);
      }

      $build['table']['#rows'][$ticket->id()] = $row;
    }

    if ($has_references) {
      $build['table']['#header']['references'] = 'References';
    }

    if ($has_actions) {
      $build['table']['#header']['action'] = '';
    }

    // Disable caching because user could be staff viewing different user pages.
    $build['#cache'] = ['max-age' => 0];

    return $build;
  }

  /**
   * Lists team applications for a user for events that have passed.
   *
   * @param \Drupal\user\Entity\User $user
   *   The user.
   *
   * @return array
   *   Render array.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function myPastTeams(User $user) {
    /** @var \Drupal\contacts_events\Entity\TicketInterface[] $tickets */
    $tickets = $this->loadTeamTickets($user, TRUE);

    $build['table'] = [
      '#type' => 'table',
      '#header' => [
        'event' => $this->t('Event'),
        'date' => $this->t('Date'),
        'team' => $this->t('Team'),
        'status' => $this->t('Status'),
      ],
      '#rows' => [],
      '#empty' => $this->t("You don't have any past team applications."),
    ];

    foreach ($tickets as $ticket) {
      if ($ticket->getStatus() == 'pending') {
        continue;
      }

      /** @var \Drupal\contacts_events\Entity\EventInterface $event */
      $event = $ticket->get('event')->entity;
      $app = $this->queries->getTeamApplicationForTicket($ticket);

      $row = [
        'event' => $event->label(),
        'date' => $this->dateFormatter->format($event->get('date')->start_date->getTimestamp(), 'short'),
        'team' => $ticket->team->entity->label(),
        'status' => $this->getStatus($app),
      ];

      $build['table']['#rows'][$ticket->id()] = $row;
    }

    // Disable caching because user could be staff viewing different user pages.
    $build['#cache'] = ['max-age' => 0];

    return $build;
  }

  /**
   * Load any team tickets (past or future) for the current user.
   */
  private function loadTeamTickets($user, $past_events = FALSE) {
    $storage = $this->entityTypeManager()
      ->getStorage('contacts_ticket');

    $query = $storage->getQuery();
    $query->accessCheck(TRUE);
    $query->condition('contact', $user->id());
    $query->condition('is_team_ticket', TRUE);

    if ($past_events) {
      $query->condition('event.entity.date.end_value', date(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $this->time->getRequestTime()), '<=');
    }
    else {
      $query->condition('event.entity.date.end_value', date(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $this->time->getRequestTime()), '>');
    }
    $query->sort('event.entity.date.value', 'DESC');
    return $storage->loadMultiple($query->execute());
  }

  /**
   * Displays team applications for past and upcoming events.
   *
   * @param \Drupal\user\UserInterface $user
   *   The user being viewed.
   *
   * @return array
   *   Render array.
   */
  public function myTeams(UserInterface $user): array {
    $build = [];

    // Convert the AccountInterface back into an underlying user entity.
    $current_user = $this->entityTypeManager()->getStorage('user')
      ->load($this->currentUser()->id());

    $contexts = [
      'current_user' => EntityContext::fromEntity($current_user),
      'user' => EntityContext::fromEntity($user),
    ];

    $build['upcoming_title'] = [
      '#markup' => $this->t('<h2>Active team applications</h2>'),
    ];
    $build['upcoming'] = $this->myActiveTeams($user);

    $build['past_title'] = [
      '#markup' => $this->t('<h2>Past team applications</h2>'),
    ];
    $build['past'] = $this->myPastTeams($user);

    return $build;
  }

  /**
   * Builds the block output.
   *
   * @param string $block_id
   *   Block ID to build.
   * @param array $contexts
   *   Contexts for the block.
   *
   * @return array
   *   Render array.
   */
  private function buildBlock($block_id, array $contexts) {
    $block = $this->blockManager->createInstance($block_id);
    if ($block instanceof ContextAwarePluginInterface) {
      $this->contextHandler->applyContextMapping($block, $contexts);
    }
    return $block->build();
  }

  /**
   * Gets the public status of a team application.
   *
   * This doesn't return the literal status values, as we don't necessarily
   * want to show users that they've been rejected for a team straight away.
   *
   * @todo Don't hard-code these?
   *
   * @param \Drupal\contacts_events_teams\Entity\TeamApplication|null $app
   *   The team application.
   *
   * @return string
   *   The public status label.
   */
  private function getStatus(?TeamApplication $app) : string {
    if (!$app) {
      return $this->t('Not started');
    }

    switch ($app->get('state')->value) {
      case 'draft':
        return $this->t('Not Submitted');

      case 'submitted':
      case 'references_received':
      case 'references_reviewed':
      case 'accepted':
      case 'rejected':
        $message = $this->t('Submitted');
        // Checkout for dbs integration.
        if ($this->moduleHandler()->moduleExists('contacts_dbs')) {
          if ($app->getTeam() && $app->getTeam()->hasField('dbs_workforce') && $workforce = $app->getTeam()->get('dbs_workforce')->value) {
            $message = $this->getDbsStatus($app, $workforce);
          }
        }
        return $message;

      case 'approved':
        return $this->t('Accepted');
    }
  }

  /**
   * Check DBS record for specific status information.
   *
   * @param \Drupal\contacts_events_teams\Entity\TeamApplication $app
   *   The team application.
   * @param string $workforce
   *   The workforce to check against.
   *
   * @return string
   *   The public status label for DBS.
   *
   * @see \Drupal\contacts_events_teams\Plugin\views\field\DbsStatus::getDbsStatus
   */
  private function getDbsStatus(TeamApplication $app, $workforce) : string {
    /** @var \Drupal\contacts_dbs\DBSManager $dbs_manager */
    $dbs_manager = \Drupal::service('contacts_dbs.dbs_manager');
    $dbs_record = $dbs_manager->getDbs($app->getOwnerId(), $workforce);
    $dbs_status = $dbs_record ? $dbs_record->get('status')->value : NULL;

    switch ($dbs_status) {
      case 'letter_required':
      case 'letter_sent':
      case 'dbs_expired':
        return $this->t('Submitted (DBS required)');

      case 'disclosure_requested':
      case 'update_service_check_required':
      case 'disclosure_review':
        return $this->t('Submitted (DBS in progress)');

      case 'dbs_clear':
      case 'update_service_checked':
      case 'dbs_exception':
      case 'disclosure_accepted':
      case 'living_abroad':
        return $this->t('Submitted (DBS clear)');

      case 'dbs_not_clear':
        return $this->t('Contact the Office');

      case NULL:
        return $this->t('DBS Error');

      default:
        return $this->t('Submitted');
    }
  }

  /**
   * Gets the state of submitted references.
   *
   * @param \Drupal\contacts_events_teams\Entity\TeamApplication|null $app
   *   The team application.
   *
   * @return string
   *   The public reference status label.
   */
  private function getReferenceStatus(?TeamApplication $app) : string {
    if (!$app) {
      return '';
    }

    switch ($app->get('state')->value) {
      case 'submitted':
        $submitted_count = 0;
        $total_count = 0;

        foreach ($this->referenceFieldHelper->findReferences($app) as $reference) {
          $total_count++;
          if (!in_array($reference->get('state')->value, [
            'pending',
            'requested',
          ])) {
            $submitted_count++;
          }
        }

        if ($submitted_count == 0) {
          return $this->t('Waiting for references');
        }
        if ($submitted_count == 1) {
          return $this->t('One reference received');
        }
        if ($submitted_count < $total_count) {
          return $this->t('@count references received', ['@count' => $submitted_count]);
        }
        return $this->t('References received');

      case 'references_received':
        return $this->t('References received');

      default:
        return '';
    }
  }

}

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

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