contacts_events-8.x-1.x-dev/modules/teams/src/EventSubscriber/ReferenceSubscriber.php
modules/teams/src/EventSubscriber/ReferenceSubscriber.php
<?php
namespace Drupal\contacts_events_teams\EventSubscriber;
use Drupal\contacts_events\OrderStateTrait;
use Drupal\contacts_events_teams\Entity\TeamApplication;
use Drupal\contacts_references\ReferenceFieldHelper;
use Drupal\contacts_references\ReferenceSender;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\state_machine\Event\WorkflowTransitionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Event subscriber relating to team ticket and reference states.
*
* @package Drupal\contacts_events_teams\EventSubscriber
*/
class ReferenceSubscriber implements EventSubscriberInterface {
use OrderStateTrait;
/**
* Reference field helper.
*
* @var \Drupal\contacts_references\ReferenceFieldHelper
*/
protected $referenceFieldHelper;
/**
* Reference email sender.
*
* @var \Drupal\contacts_references\ReferenceSender
*/
protected $sender;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $applicationStorage;
/**
* ReferenceSubscriber constructor.
*
* @param \Drupal\contacts_references\ReferenceFieldHelper $reference_field_helper
* Helper for finding reference fields.
* @param \Drupal\contacts_references\ReferenceSender $sender
* Reference email sender.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(ReferenceFieldHelper $reference_field_helper, ReferenceSender $sender, EntityTypeManagerInterface $entity_type_manager) {
$this->referenceFieldHelper = $reference_field_helper;
$this->sender = $sender;
$this->applicationStorage = $entity_type_manager->getStorage('c_events_team_app');
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// When a team applicatiion is submitted, trigger a reference.
$events['contacts_events_teams_applications.submit.post_transition'][] = ['triggerReferenceRequest'];
// Check whether the references are already in a submitted/reviewed state.
$events['contacts_events_teams_applications.submit.post_transition'][] = ['checkReferenceStatesOnSubmission'];
// When all references are submitted, update the application.
$events['contacts_reference.submit.post_transition'][] = ['checkApplicationAfterReferencesSubmitted'];
// When all references have been reviewed (accepted/rejected), update
// the application.
$events['contacts_reference.approve.post_transition'][] = ['checkApplicationAfterReferencesReviewed'];
$events['contacts_reference.reject.post_transition'][] = ['checkApplicationAfterReferencesReviewed'];
return $events;
}
/**
* Triggers a reference request.
*
* @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
* Transition event on the team app.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function triggerReferenceRequest(WorkflowTransitionEvent $event) {
/** @var \Drupal\contacts_events_teams\Entity\TeamApplication $app */
$app = $event->getEntity();
/** @var \Drupal\contacts_references\Entity\Reference[] $references */
$references = $this->referenceFieldHelper->findReferences($app);
foreach ($references as $reference) {
// Check to make sure reference is configured.
// This might be a team transfer and the references may have already been
// submitted.
if ($reference && $this->sender->canSendReference($reference)) {
$this->sender->send($reference);
}
}
}
/**
* Checks if references are already received/reviewed on app submission.
*
* @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
* Transition event on the team app.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function checkReferenceStatesOnSubmission(WorkflowTransitionEvent $event) {
/** @var \Drupal\contacts_events_teams\Entity\TeamApplication $app */
$app = $event->getEntity();
$this->updateApplicationAfterReferencesSubmitted($app);
$this->updateApplicationAfterReferencesReviewed($app);
// The above checks will transition and save the team application. If this
// check is called as part of a team application post transition, it is
// however already inside a save process and saving it again will clear the
// $entity->original property.
// @todo A better way of fixing this would be to add additional transitions
// and guard them at a form level based on the state of the references.
$app->original = $this->applicationStorage->loadUnchanged($app->id());
}
/**
* Updates a team appication after all references are submitted.
*
* @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
* Transition event.
*/
public function checkApplicationAfterReferencesSubmitted(WorkflowTransitionEvent $event) {
/** @var \Drupal\contacts_references\Entity\ReferenceInterface $reference */
$reference = $event->getEntity();
$app = $reference->getTeamApplication();
$this->updateApplicationAfterReferencesSubmitted($app);
}
/**
* Updates a team appication after all references are submitted.
*
* Once all references on the application have been submitted
* then transition the submission into references_received state.
*
* @param \Drupal\contacts_events_teams\Entity\TeamApplication $app
* The team application to update.
*/
public function updateApplicationAfterReferencesSubmitted(TeamApplication $app) {
$references = $this->referenceFieldHelper->findReferences($app);
$has_outstanding = FALSE;
foreach ($references as $reference) {
// If a reference has been deleted, we can throw a fatal error here, so
// we'll check before we do.
if ($reference) {
if (!$reference->getSubmittedTime()) {
$has_outstanding = TRUE;
}
}
}
// No outstanding references left to submit - transition the application to
// the received state.
if (!$has_outstanding) {
/** @var \Drupal\state_machine\Plugin\Field\FieldType\StateItem $state */
$state = $app->get('state')->first();
$this->applyTransitionIfAllowed($state, 'references_received', TRUE);
}
}
/**
* Updates a team application after all references are reviewed.
*
* @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
* Transition event.
*/
public function checkApplicationAfterReferencesReviewed(WorkflowTransitionEvent $event) {
/** @var \Drupal\contacts_references\Entity\ReferenceInterface $reference */
$reference = $event->getEntity();
$app = $reference->getTeamApplication();
$this->updateApplicationAfterReferencesReviewed($app);
}
/**
* Updates a team application after all references are reviewed.
*
* Once all references on the application have been accepted or rejected
* then transition the submission into references_reviewed state.
*
* @param \Drupal\contacts_events_teams\Entity\TeamApplication $app
* The team application to update.
*/
public function updateApplicationAfterReferencesReviewed(TeamApplication $app) {
$references = $this->referenceFieldHelper->findReferences($app);
$has_outstanding = FALSE;
foreach ($references as $reference) {
$has_been_reviewed = $reference->getApprovedTime() || $reference->getRejectedTime();
if (!$has_been_reviewed) {
$has_outstanding = TRUE;
}
}
// No outstanding references left to review. Transition application to the
// reviewed state.
if (!$has_outstanding) {
/** @var \Drupal\state_machine\Plugin\Field\FieldType\StateItem $state */
$state = $app->get('state')->first();
$this->applyTransitionIfAllowed($state, 'references_reviewed', TRUE);
}
}
}
