recurring_events-2.0.x-dev/modules/recurring_events_registration/recurring_events_registration.module

modules/recurring_events_registration/recurring_events_registration.module
<?php

/**
 * @file
 * Contains recurring_events_registration.module.
 */

declare(strict_types=1);

use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\recurring_events\Entity\EventInstance;
use Drupal\recurring_events\Entity\EventSeries;
use Drupal\recurring_events_registration\Entity\Registrant;
use Drupal\recurring_events_registration\Entity\RegistrantInterface;
use Drupal\recurring_events_registration\Form\RegistrantForm;
use Drupal\recurring_events_registration\Plugin\ComputedField\AvailabilityCount;
use Drupal\recurring_events_registration\Plugin\ComputedField\RegistrationCount;
use Drupal\recurring_events_registration\Plugin\ComputedField\WaitlistCount;

/**
 * Implements hook_help().
 */
function recurring_events_registration_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the recurring_events_views module.
    case 'help.page.recurring_events_registration':
      $text = file_get_contents(__DIR__ . '/README.md');
      if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
        return '<pre>' . Html::escape($text) . '</pre>';
      }
      else {
        // Use the Markdown filter to render the README.
        $filter_manager = \Drupal::service('plugin.manager.filter');
        $settings = \Drupal::configFactory()->get('markdown.settings')->getRawData();
        $config = ['settings' => $settings];
        $filter = $filter_manager->createInstance('markdown', $config);
        return $filter->process($text, 'en');
      }
      break;
  }
}

/**
 * Implements hook_entity_base_field_info_alter().
 */
function recurring_events_registration_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'eventseries') {
    $fields['event_registration'] = BaseFieldDefinition::create('event_registration')
      ->setName('event_registration')
      ->setLabel(t('Event Registration'))
      ->setDescription('The event registration configuration.')
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(FALSE)
      ->setCardinality(1)
      ->setRequired(FALSE)
      ->setTargetEntityTypeId($entity_type->id())
      ->setDisplayOptions('form', [
        'type' => 'event_registration',
        'weight' => 10,
      ]);
  }

  if ($entity_type->id() === 'eventinstance') {
    $fields['availability_count'] = BaseFieldDefinition::create('integer')
      ->setName('availability_count')
      ->setLabel(t('Availability Count'))
      ->setDescription('The availability for this event.')
      ->setReadOnly(TRUE)
      ->setComputed(TRUE)
      ->setClass(AvailabilityCount::class)
      ->setTargetEntityTypeId($entity_type->id());

    $fields['registration_count'] = BaseFieldDefinition::create('integer')
      ->setName('registration_count')
      ->setLabel(t('Registration Count'))
      ->setDescription('The number of registrants for this event.')
      ->setReadOnly(TRUE)
      ->setComputed(TRUE)
      ->setClass(RegistrationCount::class)
      ->setTargetEntityTypeId($entity_type->id());

    $fields['waitlist_count'] = BaseFieldDefinition::create('integer')
      ->setName('waitlist_count')
      ->setLabel(t('Waitlist Count'))
      ->setDescription('The number of waitlisted registrants for this event.')
      ->setReadOnly(TRUE)
      ->setComputed(TRUE)
      ->setClass(WaitlistCount::class)
      ->setTargetEntityTypeId($entity_type->id());
  }
}

/**
 * Implements hook_theme().
 */
function recurring_events_registration_theme() {
  $theme = [];

  $theme['registrant'] = [
    'render element' => 'elements',
    'template' => 'registrant',
  ];

  $theme['eventinstance_register_button'] = [
    'render element' => 'elements',
    'template' => 'eventinstance-register-button',
    'variables' => [
      'entity' => NULL,
      'attributes' => NULL,
    ],
  ];

  return $theme;
}

/**
 * Implements template_preprocess_entity().
 */
function template_preprocess_registrant(array &$variables) {
  // Set the registrant object to be accessible in the template.
  $variables['registrant'] = $variables['elements']['#registrant'];

  // Set a class on the registrant to differentiate between view modes.
  $variables['view_mode'] = $variables['elements']['#view_mode'];
  $variables['attributes']['class'][] = 'registrant-' . $variables['view_mode'];

  // Allow field groups to be rendered too.
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }
}

/**
 * Implements hook_mail().
 */
function recurring_events_registration_mail($key, &$message, $params) {
  // Only if a value for 'subject', 'body' or 'from' has not been received in
  // the `$params`, then use the notification service which is able to get
  // those values from the `$key` and the `$registrant`.
  // Some pieces of code can call the `mail()` function with already processed
  // values for 'subject', 'body' and 'from', meaning that it is not necessary
  // that those values are calculated here by the notification service.
  // @see \Drupal\recurring_events_registration\Plugin\QueueWorker\EmailNotificationsQueueWorker
  if ((empty($params['subject']) || empty($params['body']) || empty($params['from']))
    && !empty($params['registrant'])
    && $params['registrant'] instanceof Registrant) {
    /** @var \Drupal\recurring_events_registration\NotificationService $service */
    $service = \Drupal::service('recurring_events_registration.notification_service');
    $service->setKey($key)->setEntity($params['registrant']);
  }

  // If other pieces of code that have called the `mail()` function have
  // already defined those params, give them precedence. Else, let the
  // notification service to calculate those values.
  // Set the `$message['from']`.
  if (!empty($params['from'])) {
    $message['from'] = $params['from'];
  }
  elseif (isset($service)) {
    $message['from'] = $service->getFrom();
  }

  // Set the `$message['subject']`.
  if (!empty($params['subject'])) {
    $message['subject'] = $params['subject'];
  }
  elseif (isset($service)) {
    $message['subject'] = $service->getSubject();
  }

  // Set the `$message['body']`.
  if (!empty($params['body'])) {
    $message['body'][] = $params['body'];
  }
  elseif (isset($service)) {
    $message['body'][] = $service->getMessage();
  }
}

/**
 * Implements hook_recurring_events_registration_notification_types_alter().
 */
function recurring_events_registration_recurring_events_registration_notification_types_alter(array &$notification_types) {
  $notification_types += [
    'registration_notification' => [
      'name' => t('Registration Notification'),
      'description' => t('Send an email to a registrant to confirm they were registered for an event?'),
    ],
    'waitlist_notification' => [
      'name' => t('Waitlist Notification'),
      'description' => t('Send an email to a registrant to confirm they were added to the waitlist?'),
    ],
    'promotion_notification' => [
      'name' => t('Promotion Notification'),
      'description' => t('Send an email to a registrant to confirm they were promoted from the waitlist?'),
    ],
    'instance_deletion_notification' => [
      'name' => t('Instance Deletion Notification'),
      'description' => t('Send an email to a registrant to confirm an instance deletion?'),
    ],
    'series_deletion_notification' => [
      'name' => t('Series Deletion Notification'),
      'description' => t('Send an email to a registrant to confirm a series deletion?'),
    ],
    'instance_modification_notification' => [
      'name' => t('Instance Modification Notification'),
      'description' => t('Send an email to a registrant to confirm an instance modification?'),
    ],
    'series_modification_notification' => [
      'name' => t('Series Modification Notification'),
      'description' => t('Send an email to a registrant to confirm a series modification?'),
    ],
  ];
}

/**
 * Implements hook_recurring_events_save_pre_instances_deletion().
 */
function recurring_events_registration_recurring_events_save_pre_instances_deletion(EventSeries $event_series) {
  $registration_creation_service = \Drupal::service('recurring_events_registration.creation_service');
  $registration_creation_service->setEventSeries($event_series);

  // Get all the registrants who have registered for any event in this series.
  $registrants = $registration_creation_service->retrieveAllSeriesRegisteredParties(TRUE);
  if (empty($registrants)) {
    return;
  }

  $key = 'series_modification_notification';

  $config = \Drupal::config('recurring_events_registration.registrant.config');
  $queue_is_enabled = $config->get('email_notifications_queue');

  // Send an email to all registrants.
  foreach ($registrants as $registrant) {
    if ($queue_is_enabled) {
      // Add each notification to be sent to the queue.
      \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant);
    }
    else {
      // If the queue is not enabled, send this notification immediately.
      recurring_events_registration_send_notification($key, $registrant);
    }
    $registrant->delete();
  }
}

/**
 * Implements hook_entity_update().
 */
function recurring_events_registration_entity_update(EntityInterface $entity) {
  if ($entity->getEntityTypeId() === 'eventinstance') {
    $date_changes = FALSE;
    $original = $entity->original;

    $date_changes = !(serialize($entity->date->getValue()) === serialize($original->date->getValue()));
    if (!$date_changes) {
      return;
    }

    // Only send emails if the event is in the future.
    if ($entity->date->end_date->getTimestamp() > time()) {
      $registration_creation_service = \Drupal::service('recurring_events_registration.creation_service');
      $registration_creation_service->setEventInstance($entity);

      $registrants = $registration_creation_service->retrieveRegisteredParties();
      if (empty($registrants)) {
        return;
      }

      $key = 'instance_modification_notification';

      $config = \Drupal::config('recurring_events_registration.registrant.config');
      $queue_is_enabled = $config->get('email_notifications_queue');

      // Send an email to all registrants.
      foreach ($registrants as $registrant) {
        if ($queue_is_enabled) {
          // Add each notification to be sent to the queue.
          \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant);
        }
        else {
          // If the queue is not enabled, send this notification immediately.
          recurring_events_registration_send_notification($key, $registrant);
        }
      }
    }
  }
}

/**
 * Implements hook_recurring_events_pre_delete_instance().
 */
function recurring_events_registration_recurring_events_pre_delete_instance(EventInstance $instance) {
  $registration_creation_service = \Drupal::service('recurring_events_registration.creation_service');
  $registration_creation_service->setEventInstance($instance);

  $registrants = $registration_creation_service->retrieveRegisteredParties();
  if (empty($registrants)) {
    return;
  }

  $key = 'instance_deletion_notification';

  $config = \Drupal::config('recurring_events_registration.registrant.config');
  $queue_is_enabled = $config->get('email_notifications_queue');

  // Send an email to all registrants.
  foreach ($registrants as $registrant) {
    // Only send email notifications if this event instance is in the future.
    if ($registration_creation_service->eventInstanceIsInFuture()) {
      if ($queue_is_enabled) {
        // Add each notification to be sent to the queue.
        \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant);
      }
      else {
        // If the queue is not enabled, send this notification immediately.
        recurring_events_registration_send_notification($key, $registrant);
      }
    }
    $registrant->delete();
  }
}

/**
 * Implements hook_recurring_events_pre_delete_instances().
 */
function recurring_events_registration_recurring_events_pre_delete_instances(EventSeries $event_series) {
  /** @var \Drupal\recurring_events_registration\RegistrationCreationService $registration_creation_service */
  $registration_creation_service = \Drupal::service('recurring_events_registration.creation_service');
  $registration_creation_service->setEventSeries($event_series);

  // Get the registrants registered for a future event and email them about the
  // series deletion.
  $future_registrants = $registration_creation_service->retrieveAllSeriesRegisteredParties(TRUE);
  if (!empty($future_registrants)) {
    $key = 'series_deletion_notification';

    $config = \Drupal::config('recurring_events_registration.registrant.config');
    $queue_is_enabled = $config->get('email_notifications_queue');

    // Send an email to the future registrants.
    foreach ($future_registrants as $registrant) {
      if ($queue_is_enabled) {
        // Add each notification to be sent to the queue.
        \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant);
      }
      else {
        // If the queue is not enabled, send this notification immediately.
        recurring_events_registration_send_notification($key, $registrant);
      }
    }
  }

  // Now get all the registrants for this series so we can remove them.
  $registrants = $registration_creation_service->retrieveAllSeriesRegisteredParties();
  if (empty($registrants)) {
    return;
  }

  // Send an email to all registrants.
  foreach ($registrants as $registrant) {
    $registrant->delete();
  }
}

/**
 * Send a notification message.
 *
 * @param string $key
 *   The mail key used to determine the message and subject.
 * @param \Drupal\recurring_events_registration\Entity\RegistrantInterface $registrant
 *   The registrant this email relates to.
 */
function recurring_events_registration_send_notification($key, RegistrantInterface $registrant) {
  $config = \Drupal::config('recurring_events_registration.registrant.config');
  $send_email = $config->get('email_notifications');
  $send_email_key = $config->get('notifications.' . $key . '.enabled');

  // Modify $send_email if necessary.
  \Drupal::moduleHandler()->alter('recurring_events_registration_send_notification', $send_email, $registrant);

  if ($send_email && $send_email_key) {
    $params = [
      'registrant' => $registrant,
    ];

    // Allow modules to add data to the `$params`. Developers can get data from
    // `$registrant`. Those `$params` can be used later as the
    // `$params` in `hook_mail()` and `$message['params']` in
    // `hook_mail_alter()`.
    // Although the `$registrant` itself is already being passed in the
    // `$params`, which means that `$registrant` can be accessed via
    // `$params['registrant']` in `hook_mail()` or
    // `$message['params']['registrant']` in `hook_mail_alter()`, that is only
    // true for messages that are not queued (i.e. messages that are sent
    // immediately through this current function). In queued messages, it is
    // not possible to pass the `$registrant` entity, because the registrant
    // could not longer exist when the queue worker takes action and sends the
    // email, so it would be unsafe to try to access it in the mail hooks.
    // For further explanation:
    // @see \Drupal\recurring_events_registration\NotificationService::addEmailNotificationToQueue()
    // We discourage the use of the $registrant entity via
    // `$params['registrant']` in `hook_mail()` and
    // `$message['params']['registrant']` in `hook_mail_alter()`, even for
    // messages that are not queued. For consistency, We encourage developers
    // to make use of the
    // `hook_recurring_events_registration_message_params_alter()` to define
    // any value in the params that could be necessary to perform any logic
    // in the mail hooks (ideally scalar values, custom arrays or custom
    // objects.
    \Drupal::moduleHandler()->alter('recurring_events_registration_message_params', $params, $registrant);

    $to = $registrant->email->value;

    $mail = \Drupal::service('plugin.manager.mail');
    $mail->mail('recurring_events_registration', $key, $to, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
  }
}

/**
 * Implements hook_entity_operation().
 */
function recurring_events_registration_entity_operation(EntityInterface $entity) {
  $operations = [];
  if ($entity instanceof RegistrantInterface) {
    $instance = $entity->getEventInstance();
    if ($instance) {
      $operations['resend'] = [
        'title' => t('Resend Mail'),
        'weight' => 50,
        'url' => Url::fromRoute('entity.registrant.resend_form', [
          'eventinstance' => $instance->id(),
          'registrant' => $entity->id(),
        ]),
      ];
    }
  }

  return $operations;
}

/**
 * Implements hook_entity_operation_alter().
 */
function recurring_events_registration_entity_operation_alter(array &$operations, EntityInterface $entity) {
  if ($entity->getEntityTypeId() == 'registrant_type') {
    if (!empty($operations['delete'])) {
      unset($operations['delete']);
    }
  }
}

/**
 * Implements hook_menu_local_tasks_alter().
 */
function recurring_events_registration_menu_local_tasks_alter(&$data, $route_name, RefinableCacheableDependencyInterface $cacheability) {
  // ISSUE:
  // Devel routes do not use 'eventinstance' parameter which throws the below
  // error. Some mandatory parameters are missing ("eventinstance") to generate
  // a URL for route "entity.registrant.canonical".
  //
  // WORKAROUND.
  // Make sure eventinstance parameter is set for all routes.
  // Based on similar issue in webform_menu_local_tasks_alter in Webform module.
  if (strpos($route_name, 'entity.registrant.devel_') === 0 || $route_name === 'entity.registrant.token_devel') {
    foreach ($data['tabs'] as $tab_level) {
      foreach ($tab_level as $tab) {
        /** @var Drupal\Core\Url $url */
        $url = $tab['#link']['url'];
        $tab_route_name = $url->getRouteName();
        $tab_route_parameters = $url->getRouteParameters();

        if (strpos($tab_route_name, 'entity.registrant.latest_version') !== 0) {
          $registrant = Registrant::load($tab_route_parameters['registrant']);
          $url->setRouteParameter('eventinstance', $registrant->getEventInstance()->id());
        }
      }
    }
  }
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function recurring_events_registration_theme_suggestions_registrant(array $variables) {
  $suggestions = [];
  $entity = $variables['elements']['#registrant'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');

  $suggestions[] = 'registrant__' . $sanitized_view_mode;
  $suggestions[] = 'registrant__' . $entity->bundle();
  $suggestions[] = 'registrant__' . $entity->bundle() . '__' . $sanitized_view_mode;
  $suggestions[] = 'registrant__' . $entity->id();
  $suggestions[] = 'registrant__' . $entity->id() . '__' . $sanitized_view_mode;
  return $suggestions;
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function recurring_events_registration_registrant_insert(EntityInterface $entity) {
  if (\Drupal::isConfigSyncing()) {
    return;
  }
  $entity_type = $entity->getEntityTypeId();
  $bundle = $entity->bundle();
  $inherited_field_ids = \Drupal::entityQuery('field_inheritance')
    ->condition('sourceEntityType', ['eventseries', 'eventinstance'], 'IN')
    ->condition('destinationEntityType', $entity_type)
    ->condition('destinationEntityBundle', $bundle)
    ->accessCheck(FALSE)
    ->execute();

  if (!empty($inherited_field_ids)) {
    $state_key = $entity_type . ':' . $entity->uuid();
    $state = \Drupal::keyValue('field_inheritance');
    $state_values = $state->get($state_key);

    $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids);
    $state_values = [
      'enabled' => TRUE,
    ];
    if (!empty($inherited_fields)) {
      foreach ($inherited_fields as $inherited_field) {
        $name = $inherited_field->idWithoutTypeAndBundle();

        $referenced_entity = NULL;
        switch ($inherited_field->sourceEntityType()) {
          case 'eventseries':
            $referenced_entity = $entity->getEventSeries();
            break;

          case 'eventinstance':
            $referenced_entity = $entity->getEventInstance();
            break;

        }
        if (!empty($referenced_entity)) {
          $state_values[$name] = [
            'entity' => $referenced_entity->id(),
          ];
        }
      }
    }
    $state->set($state_key, $state_values);
  }
}

/**
 * Implements hook_form_alter().
 *
 * @todo Remove when https://www.drupal.org/node/3173241 drops.
 */
function recurring_events_registration_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  /** @var \Drupal\recurring_events_registration\Form\RegistrantForm $form_object */
  $form_object = $form_state->getFormObject();
  if ($form_object instanceof RegistrantForm) {
    /** @var \Drupal\recurring_events_registration\Entity\RegistrantInterface $entity */
    $entity = $form_object->getEntity();
    if (!empty($entity) && $entity instanceof RegistrantInterface && $entity->getEntityTypeId() === 'registrant' && !empty($form['actions'])) {
      foreach ($form['actions']['submit']['#submit'] as $key => $submit) {
        if (is_array($submit) && $submit[0] === 'Drupal\content_moderation\EntityTypeInfo') {
          unset($form['actions']['submit']['#submit'][$key]);
        }
      }
    }
  }
}

/**
 * Implements hook_module_implements_alter().
 *
 * @todo Remove when https://www.drupal.org/node/3173241 drops.
 */
function recurring_events_registration_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'form_alter') {
    // Move recurring_events_registration_form_alter() to the end of the
    // list because we need to make sure we override the content moderation
    // latest-version link template to also pass through the eventinstance ID to
    // the URL.
    // @see recurring_events_registration_form_alter().
    $group = $implementations['recurring_events_registration'];
    unset($implementations['recurring_events_registration']);
    $implementations['recurring_events_registration'] = $group;
  }
}

/**
 * Implements hook_preprocess_field().
 */
function recurring_events_registration_preprocess_page_title(array &$variables) {
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name === 'entity.registrant.add_form') {
    $event_instance = \Drupal::routeMatch()->getParameters()->get('eventinstance');
    if (!empty($event_instance) && !empty($event_instance->title->value)) {
      $variables['title'] = $event_instance->title->value;
    }
  }
}

/**
 * Implements hook_entity_extra_field_info().
 */
function recurring_events_registration_entity_extra_field_info() {
  $extra = [];
  $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('eventinstance');
  if (!empty($bundles)) {
    foreach ($bundles as $bundle_id => $bundle) {
      $extra['eventinstance'][$bundle_id]['display']['register_button'] = [
        'label' => t('Register button'),
        'description' => t('Show a button linking to the registration page for this event instance'),
        'weight' => 999,
      ];
    }
  }
  return $extra;
}

/**
 * Implements hook_ENTITY_NAME_view().
 */
function recurring_events_registration_eventinstance_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if ($display->getComponent('register_button')) {
    $service = \Drupal::service('recurring_events_registration.creation_service');
    $service->setEventInstance($entity);
    if ($service->registrationIsOpen()) {
      $build['register_button'] = [
        '#theme' => 'eventinstance_register_button',
        '#entity' => $entity,
        '#attributes' => [
          'class' => [
            'button',
            'eventinstance-register',
          ],
        ],
      ];
    }
  }
}

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

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