Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • project/recurring_events
  • issue/recurring_events-3183502
  • issue/recurring_events-3183463
  • issue/recurring_events-3183483
  • issue/recurring_events-3190526
  • issue/recurring_events-3191715
  • issue/recurring_events-3190833
  • issue/recurring_events-3188808
  • issue/recurring_events-3180479
  • issue/recurring_events-3122823
  • issue/recurring_events-3196649
  • issue/recurring_events-3196428
  • issue/recurring_events-3196702
  • issue/recurring_events-3196704
  • issue/recurring_events-3198532
  • issue/recurring_events-3164409
  • issue/recurring_events-3206960
  • issue/recurring_events-3115678
  • issue/recurring_events-3218496
  • issue/recurring_events-3207435
  • issue/recurring_events-3219082
  • issue/recurring_events-3217367
  • issue/recurring_events-3229514
  • issue/recurring_events-3231841
  • issue/recurring_events-3238591
  • issue/recurring_events-3282502
  • issue/recurring_events-3283128
  • issue/recurring_events-3240862
  • issue/recurring_events-3247034
  • issue/recurring_events-3071679
  • issue/recurring_events-3264621
  • issue/recurring_events-3266436
  • issue/recurring_events-3268690
  • issue/recurring_events-3269555
  • issue/recurring_events-3271328
  • issue/recurring_events-3272361
  • issue/recurring_events-3163804
  • issue/recurring_events-3297681
  • issue/recurring_events-3299575
  • issue/recurring_events-3300786
  • issue/recurring_events-3302916
  • issue/recurring_events-3304286
  • issue/recurring_events-3298679
  • issue/recurring_events-3309652
  • issue/recurring_events-3310360
  • issue/recurring_events-3311843
  • issue/recurring_events-3311712
  • issue/recurring_events-3312003
  • issue/recurring_events-3312084
  • issue/recurring_events-3312242
  • issue/recurring_events-3316080
  • issue/recurring_events-3295367
  • issue/recurring_events-3196417
  • issue/recurring_events-3309859
  • issue/recurring_events-3318590
  • issue/recurring_events-3244975
  • issue/recurring_events-3318998
  • issue/recurring_events-3321269
  • issue/recurring_events-3320512
  • issue/recurring_events-3321235
  • issue/recurring_events-3321550
  • issue/recurring_events-3322998
  • issue/recurring_events-3315836
  • issue/recurring_events-3324055
  • issue/recurring_events-3328907
  • issue/recurring_events-3318490
  • issue/recurring_events-3339288
  • issue/recurring_events-3345618
  • issue/recurring_events-3347935
  • issue/recurring_events-3362297
  • issue/recurring_events-3359696
  • issue/recurring_events-3318666
  • issue/recurring_events-3366907
  • issue/recurring_events-3366910
  • issue/recurring_events-3403064
  • issue/recurring_events-3404311
  • issue/recurring_events-3405567
  • issue/recurring_events-3376639
  • issue/recurring_events-3384836
  • issue/recurring_events-3382387
  • issue/recurring_events-3384389
  • issue/recurring_events-3315503
  • issue/recurring_events-3411229
  • issue/recurring_events-3415222
  • issue/recurring_events-3415308
  • issue/recurring_events-3172514
  • issue/recurring_events-3419694
  • issue/recurring_events-3178696
  • issue/recurring_events-3408924
  • issue/recurring_events-3447130
  • issue/recurring_events-3416436
  • issue/recurring_events-3451613
  • issue/recurring_events-3452632
  • issue/recurring_events-3453086
  • issue/recurring_events-3452641
  • issue/recurring_events-3454012
  • issue/recurring_events-3455716
  • issue/recurring_events-3456300
  • issue/recurring_events-3456641
  • issue/recurring_events-3462327
  • issue/recurring_events-3463467
  • issue/recurring_events-3463979
  • issue/recurring_events-3462480
  • issue/recurring_events-3464792
  • issue/recurring_events-3456045
  • issue/recurring_events-3468300
  • issue/recurring_events-3468521
  • issue/recurring_events-3475611
  • issue/recurring_events-3477247
  • issue/recurring_events-3477047
  • issue/recurring_events-3477650
  • issue/recurring_events-3257502
  • issue/recurring_events-3090186
  • issue/recurring_events-3478802
  • issue/recurring_events-3479449
  • issue/recurring_events-3479843
  • issue/recurring_events-3479860
  • issue/recurring_events-3480495
  • issue/recurring_events-3480500
  • issue/recurring_events-3480746
  • issue/recurring_events-3480973
  • issue/recurring_events-3481021
  • issue/recurring_events-3481722
  • issue/recurring_events-3482804
  • issue/recurring_events-3483283
  • issue/recurring_events-3484209
  • issue/recurring_events-3170156
  • issue/recurring_events-3484558
  • issue/recurring_events-3485904
  • issue/recurring_events-3485935
  • issue/recurring_events-3487412
  • issue/recurring_events-3496270
  • issue/recurring_events-3480508
  • issue/recurring_events-3499792
  • issue/recurring_events-3500920
  • issue/recurring_events-3510919
  • issue/recurring_events-3510942
  • issue/recurring_events-3478268
  • issue/recurring_events-3515976
139 results
Show changes
Showing
with 1505 additions and 89 deletions
<?php
namespace Drupal\recurring_events_ical;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface for event iCal property mapping entities.
*/
interface EventICalMappingInterface extends ConfigEntityInterface {
/**
* Returns TRUE if a property mapping exists.
*
* @param string $property
* The iCal property.
*
* @return bool
* TRUE if a mapping exists for the property.
*/
public function hasProperty(string $property): bool;
/**
* Returns the value of a property mapping.
*
* @param string $property
* The iCal property.
*
* @return string|null
* The mapped value, or NULL if not mapped.
*/
public function getProperty(string $property): ?string;
/**
* Returns all mapped property values.
*
* @return string[]
* An array of property mappings as $property => $value.
*/
public function getAllProperties(): array;
/**
* Sets the value of a property mapping.
*
* @param string $property
* The iCal property.
* @param string $value
* The value of the property.
*/
public function setProperty(string $property, string $value);
}
<?php
namespace Drupal\recurring_events_ical;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of event iCal property mapping entities.
*/
class EventICalMappingListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['label'] = $this->t('Event instance type');
$header['id'] = $this->t('Machine name');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
$row['label'] = $entity->label();
$row['id'] = $entity->id();
return $row + parent::buildRow($entity);
}
}
<?php
namespace Drupal\recurring_events_ical\Field;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\TypedData\ComputedItemListTrait;
/**
* A computed field that generates a link to download an event's iCalendar data.
*/
class EventICalLinkItemList extends FieldItemList {
use ComputedItemListTrait;
/**
* {@inheritdoc}
*/
protected function computeValue() {
if (!isset($this->list[0])) {
$entity = $this->getEntity();
if (!$entity->isNew()) {
$this->list[0] = $this->createItem(0, [
'uri' => $entity->toUrl('ical')->toUriString(),
'title' => '',
]);
}
}
}
}
<?php
namespace Drupal\recurring_events_ical\Form;
use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Form handler for the event iCal property mapping delete form.
*/
class EventICalMappingDeleteForm extends EntityConfirmFormBase {
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to delete %name?', [
'%name' => $this->entity->label(),
]);
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return $this->entity->toUrl('collection');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Delete');
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->entity->delete();
$this->messenger()->addMessage($this->t('%label iCalendar property mapping has been deleted.', [
'%label' => $this->entity->label(),
]));
$form_state->setRedirectUrl($this->getCancelUrl());
}
}
<?php
namespace Drupal\recurring_events_ical\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\token\TokenEntityMapperInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form handler for the event iCal property mapping add/edit form.
*/
class EventICalMappingForm extends EntityForm {
/**
* The entity being used by this form.
*
* @var \Drupal\recurring_events_ical\EventICalMappingInterface
*/
protected $entity;
/**
* The entity type bundle info service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The token entity mapper service.
*
* @var \Drupal\token\TokenEntityMapperInterface
*/
protected $tokenEntityMapper;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
/** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entityTypeBundleInfo */
$entityTypeBundleInfo = $container->get('entity_type.bundle.info');
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager */
$entityTypeManager = $container->get('entity_type.manager');
/** @var \Drupal\token\TokenEntityMapperInterface $tokenEntityMapper */
$tokenEntityMapper = $container->get('token.entity_mapper');
return new static(
$entityTypeBundleInfo,
$entityTypeManager,
$tokenEntityMapper
);
}
/**
* Constructs an EventICalMappingForm object.
*
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entityTypeBundleInfo
* The entity type bundle info service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager service.
* @param \Drupal\token\TokenEntityMapperInterface $tokenEntityMapper
* The token entity mapper service.
*/
public function __construct(EntityTypeBundleInfoInterface $entityTypeBundleInfo, EntityTypeManagerInterface $entityTypeManager, TokenEntityMapperInterface $tokenEntityMapper) {
$this->entityTypeBundleInfo = $entityTypeBundleInfo;
$this->entityTypeManager = $entityTypeManager;
$this->tokenEntityMapper = $tokenEntityMapper;
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$eventType = $this->entity->isNew() ? $form_state->get('event_type') : $this->entity->id();
// If this is a new mapping, show a selector for unmapped event types.
if ($this->entity->isNew()) {
$form['#ajax_wrapper_id'] = 'event-ical-mapping-form-ajax-wrapper';
$ajax = [
'wrapper' => $form['#ajax_wrapper_id'],
'callback' => '::rebuildForm',
];
$form['#prefix'] = '<div id="' . $form['#ajax_wrapper_id'] . '">';
$form['#suffix'] = '</div>';
$form['id'] = [
'#type' => 'select',
'#title' => $this->t('Event instance type'),
'#description' => $this->t('Select the type of event for which to map iCalendar properties.'),
'#options' => $this->getUnmappedTypes(),
'#default_value' => $eventType,
'#required' => TRUE,
'#ajax' => $ajax + [
'trigger_as' => [
'name' => 'select_id_submit',
],
],
];
$form['select_id_submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#name' => 'select_id_submit',
'#ajax' => $ajax,
'#attributes' => [
'class' => ['js-hide'],
],
];
}
// Hide the rest of the form until a type is selected.
if (!isset($eventType)) {
return $form;
}
// Show the token browser.
$tokenTypes = [
'eventinstance' => $this->tokenEntityMapper->getTokenTypeForEntityType('eventinstance'),
];
$form['token_browser'] = [
'#theme' => 'token_tree_link',
'#token_types' => $tokenTypes,
'#global_types' => TRUE,
'#show_nested' => TRUE,
];
// iCalendar properties.
$form['properties'] = ['#tree' => TRUE];
$propertyDefaults = [
'#type' => 'textfield',
'#size' => 65,
'#maxlength' => 1280,
'#element_validate' => ['token_element_validate'],
'#after_build' => ['token_element_validate'],
'#token_types' => $tokenTypes,
];
$form['properties']['summary'] = [
'#title' => $this->t('Summary'),
'#default_value' => $this->entity->getProperty('summary') ?? '[eventinstance:title]',
'#description' => $this->t('Short summary or subject for the event.'),
'#required' => TRUE,
] + $propertyDefaults;
$form['properties']['contact'] = [
'#title' => $this->t('Contact'),
'#default_value' => $this->entity->getProperty('contact'),
'#description' => $this->t('Contact information for the event.'),
] + $propertyDefaults;
$form['properties']['description'] = [
'#title' => $this->t('Description'),
'#default_value' => $this->entity->getProperty('description') ?? '[eventinstance:description]',
'#description' => $this->t('A more complete description of the event than that provided by the summary.'),
] + $propertyDefaults;
$form['properties']['geo'] = [
'#title' => $this->t('Geographic Position'),
'#default_value' => $this->entity->getProperty('geo'),
'#description' => $this->t('The global position for the event. The value must be two semicolon-separated float values.'),
] + $propertyDefaults;
$form['properties']['location'] = [
'#title' => $this->t('Location'),
'#default_value' => $this->entity->getProperty('location'),
'#description' => $this->t('The intended venue for the event.'),
] + $propertyDefaults;
$form['properties']['priority'] = [
'#title' => $this->t('Priority'),
'#default_value' => $this->entity->getProperty('priority'),
'#description' => $this->t('The relative priority of the event. The value must be an integer in the range 0 to 9. A value of 0 specifies an undefined priority. A value of 1 is the highest priority. A value of 9 is the lowest priority.'),
] + $propertyDefaults;
$form['properties']['url'] = [
'#title' => $this->t('URL'),
'#default_value' => $this->entity->getProperty('url') ?? '[eventinstance:url]',
'#description' => $this->t('A URL associated with the event.'),
] + $propertyDefaults;
return $form;
}
/**
* Ajax form submit handler that returns the rebuilt form.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @return array
* The form structure.
*/
public function rebuildForm(array $form, FormStateInterface $form_state): array {
return $form;
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
if ($this->entity->isNew() && empty($form['id']['#options'])) {
$form['id'] = [
'#markup' => $this->t('All event instance types are already mapped.'),
];
unset($form['actions']['submit']);
$form['actions']['cancel'] = [
'#type' => 'link',
'#title' => $this->t('Cancel'),
'#url' => new Url('entity.event_ical_mapping.collection'),
'#attributes' => [
'class' => [
'button',
],
],
];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function buildEntity(array $form, FormStateInterface $form_state) {
$entity = parent::buildEntity($form, $form_state);
if ($entity->isNew()) {
$type = $form_state->getValue('id');
$types = $this->entityTypeBundleInfo->getBundleInfo('eventinstance');
$entity->set('label', $types[$type]['label']);
}
return $entity;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
if ($form_state->getTriggeringElement()['#name'] === 'select_id_submit') {
$form_state->set('event_type', $form_state->getValue('id'));
$form_state->setRebuild();
}
else {
parent::submitForm($form, $form_state);
}
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$status = parent::save($form, $form_state);
$this->messenger()->addMessage($this->t('%label iCalendar property mapping saved.', [
'%label' => $this->entity->label(),
]));
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
return $status;
}
/**
* Returns an array of unmapped event instance types.
*
* @return array
* A list of unmapped event instance types as $id => $label.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getUnmappedTypes(): array {
$unmappedTypes = [];
$types = $this->entityTypeBundleInfo->getBundleInfo('eventinstance');
if ($types) {
$mappedTypes = $this->entityTypeManager->getStorage('event_ical_mapping')->loadMultiple(array_keys($types));
foreach ($types as $type => $info) {
if (!isset($mappedTypes[$type])) {
$unmappedTypes[$type] = $info['label'];
}
}
}
return $unmappedTypes;
}
}
<?php
namespace Drupal\recurring_events_ical\Plugin\Field\FieldFormatter;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Path\PathValidatorInterface;
use Drupal\link\Plugin\Field\FieldFormatter\LinkFormatter;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'event_ical_link' formatter.
*
* @FieldFormatter(
* id = "event_ical_link",
* label = @Translation("Event iCalendar Link"),
* field_types = {
* "event_ical_link"
* }
* )
*/
class EventICalLinkFormatter extends LinkFormatter {
/**
* The configuration factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
/** @var \Drupal\Core\Path\PathValidatorInterface $pathValidator */
$pathValidator = $container->get('path.validator');
/** @var \Drupal\Core\Config\ConfigFactoryInterface $configFactory */
$configFactory = $container->get('config.factory');
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['label'],
$configuration['view_mode'],
$configuration['third_party_settings'],
$pathValidator,
$configFactory
);
}
/**
* Constructs a new EventICalLinkFormatter.
*
* @param string $plugin_id
* The plugin_id for the formatter.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The definition of the field to which the formatter is associated.
* @param array $settings
* The formatter settings.
* @param string $label
* The formatter label display setting.
* @param string $view_mode
* The view mode.
* @param array $third_party_settings
* Third party settings.
* @param \Drupal\Core\Path\PathValidatorInterface $path_validator
* The path validator service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory service.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, PathValidatorInterface $path_validator, ConfigFactoryInterface $config_factory) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings, $path_validator);
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$entity = $items->getEntity();
$entityType = $entity->getEntityType()->id();
$config = $this->configFactory->get("recurring_events.$entityType.config");
$linkTitle = $config->get('ical_link_title') ?? $this->t('Download as iCal');
foreach ($items as $item) {
$item->title = $linkTitle;
}
return parent::viewElements($items, $langcode);
}
}
<?php
namespace Drupal\recurring_events_ical\Plugin\Field\FieldType;
use Drupal\link\Plugin\Field\FieldType\LinkItem;
/**
* Plugin implementation of the 'event_ical_link' field type.
*
* @FieldType(
* id = "event_ical_link",
* label = @Translation("Event iCalendar Link"),
* description = @Translation("A link to an event's iCalendar download."),
* default_widget = "link_default",
* default_formatter = "event_ical_link",
* constraints = {
* "LinkType" = {},
* "LinkAccess" = {},
* "LinkExternalProtocols" = {},
* "LinkNotExistingInternal" = {},
* }
* )
*/
class EventICalLinkItem extends LinkItem {
// No implementation; only exists to define the default formatter.
}
<?php
namespace Drupal\Tests\recurring_events_ical\Kernel;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\KernelTests\KernelTestBase;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\recurring_events\Entity\EventSeries;
/**
* @coversDefaultClass \Drupal\recurring_events_ical\EventICal
* @group recurring_events_ical
*/
class EventICalTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'datetime',
'datetime_range',
'field',
'field_inheritance',
'options',
'recurring_events',
'recurring_events_ical',
'system',
'text',
'token',
'user',
];
/**
* {@inheritdoc}
*/
protected static $configSchemaCheckerExclusions = [
'core.entity_view_display.eventseries.default.default',
'core.entity_view_display.eventseries.default.list',
'core.entity_view_display.eventinstance.default.default',
'core.entity_view_display.eventinstance.default.list',
];
/**
* The service under test.
*
* @var \Drupal\recurring_events_ical\EventICalInterface
*/
protected $eventICal;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('field_inheritance');
$this->installEntitySchema('eventseries_type');
$this->installEntitySchema('eventinstance_type');
$this->installEntitySchema('eventseries');
$this->installEntitySchema('eventinstance');
$this->installEntitySchema('event_ical_mapping');
$this->installEntitySchema('user');
$this->installConfig([
'field_inheritance',
'recurring_events',
'recurring_events_ical',
'datetime',
'system',
'user',
]);
$this->eventICal = $this->container->get('recurring_events_ical.event_ical');
$this->entityTypeManager = $this->container->get('entity_type.manager');
}
/**
* Tests EventICal::render() for basic values.
*/
public function testRenderBasic() {
$event = $this->createEventSeries(
'Test event with a title that is longer than 75 characters. Seriously, it just keeps going and going.',
[
[
'start' => '2022-01-01 00:00:00',
'end' => '2022-01-01 00:30:00',
],
]
);
$iCal = explode("\r\n", $this->eventICal->render($event));
$this->assertPreamble($iCal);
$this->assertSame('DTSTART:20220101T000000Z', $iCal[6]);
$this->assertSame('DTEND:20220101T003000Z', $iCal[7]);
// cspell:ignore Seriousl
$this->assertSame('SUMMARY:Test event with a title that is longer than 75 characters. Seriousl', $iCal[8]);
$this->assertSame(' y, it just keeps going and going.', $iCal[9]);
$this->assertSame('END:VEVENT', $iCal[10]);
$this->assertSame('END:VCALENDAR', $iCal[11]);
}
/**
* Tests EventICal::render() for mapped token values.
*/
public function testRenderMapped() {
$event = $this->createEventSeries(
'Mapped event series',
[
[
'start' => '2022-01-01 00:00:00',
'end' => '2022-01-01 00:30:00',
],
],
"<h2>Agenda</h2>\n\n<ul>\n\t<li>Talk about a lot of boring things</li>\n<li>Talk about more boring things</li>\n<li>Pizza</li>\n</ul>"
);
$mapping = $this->entityTypeManager->getStorage('event_ical_mapping')->create([
'id' => 'default',
'label' => 'Default',
'properties' => [
'summary' => '[eventinstance:title]',
'contact' => 'That Guy',
'description' => '[eventinstance:description]',
'geo' => '12.34;56.78',
'location' => 'Conference Room',
'priority' => '1',
'url' => '[eventinstance:url]',
],
]);
$mapping->save();
$iCal = explode("\r\n", $this->eventICal->render($event));
$this->assertPreamble($iCal);
$this->assertSame('DTSTART:20220101T000000Z', $iCal[6]);
$this->assertSame('DTEND:20220101T003000Z', $iCal[7]);
$this->assertSame('SUMMARY:Mapped event series', $iCal[8]);
$this->assertSame('CONTACT:That Guy', $iCal[9]);
$this->assertSame('DESCRIPTION:Agenda\n\n\n' . "\t" . 'Talk about a lot of boring things\nTalk about more', $iCal[10]);
$this->assertSame(' boring things\nPizza', $iCal[11]);
$this->assertSame('GEO:12.34;56.78', $iCal[12]);
$this->assertSame('LOCATION:Conference Room', $iCal[13]);
$this->assertSame('PRIORITY:1', $iCal[14]);
$this->assertMatchesRegularExpression('~URL:(http|https)://(.+)/events/([0-9]+)~', $iCal[15]);
$this->assertSame('END:VEVENT', $iCal[16]);
$this->assertSame('END:VCALENDAR', $iCal[17]);
}
/**
* Creates an event series for use in a test.
*
* @param string $title
* The series title.
* @param array $dates
* An array of event start/end dates in the format: [
* [
* 'start' => 'YYYY-MM-DD HH:MM:SS',
* 'end' => 'YYYY-MM-DD HH:MM:SS',
* ],
* ...
* ].
* @param string $body
* (optional) The event's body text.
*
* @return \Drupal\recurring_events\Entity\EventSeries
* The event series.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
protected function createEventSeries(string $title, array $dates, string $body = ''): EventSeries {
$customDates = [];
foreach ($dates as $date) {
$start = new DrupalDateTime($date['start']);
$end = new DrupalDateTime($date['end']);
$customDates[] = [
'value' => $start->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
'end_value' => $end->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT),
];
}
/** @var \Drupal\recurring_events\Entity\EventSeries $event */
$event = $this->entityTypeManager->getStorage('eventseries')->create([
'title' => $title,
'uid' => 1,
'type' => 'default',
'recur_type' => 'custom',
'custom_date' => $customDates,
'body' => $body,
]);
$event->save();
return $event;
}
/**
* Asserts that the first six lines of iCal data are correct.
*
* @param array $iCal
* The iCal rendering exploded as an array.
*/
protected function assertPreamble(array $iCal) {
$this->assertSame('BEGIN:VCALENDAR', $iCal[0]);
$this->assertSame('VERSION:2.0', $iCal[1]);
$this->assertSame('PRODID:-//Drupal//recurring_events_ical//2.0//EN', $iCal[2]);
$this->assertSame('BEGIN:VEVENT', $iCal[3]);
$this->assertMatchesRegularExpression('/UID:([a-z0-9\-]+)@(.+)/', $iCal[4]);
$this->assertMatchesRegularExpression('/DTSTAMP:([0-9]{8})T([0-9]{6})Z/', $iCal[5]);
}
}
show_capacity: true
insert_redirect_choice: current
insert_redirect_other: ''
use_admin_theme: false
limit: 10
date_format: 'F jS, Y h:iA'
title: '[registrant:email]'
......@@ -9,24 +12,32 @@ successfully_updated: Registrant successfully updated.
successfully_updated_waitlist: Successfully updated waitlist registrant.
already_registered: User already registered for this event.
registration_closed: Unfortunately, registration is not available at this time.
registration_notification_enabled: true
registration_notification_subject: 'You''ve Successfully Registered'
registration_notification_body: "Your registration for the [eventinstance:title] [eventinstance:reg_type] was successful.\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
waitlist_notification_enabled: true
waitlist_notification_subject: 'You''ve Been Added To The Waitlist'
waitlist_notification_body: "You have been added to the waitlist for the [eventinstance:title] [eventinstance:reg_type].\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
promotion_notification_enabled: true
promotion_notification_subject: 'You''ve Been Added To The Registration List'
promotion_notification_body: "You have been promoted from the waitlist to the registration list for the [eventinstance:title] [eventinstance:reg_type].\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
instance_deletion_notification_enabled: true
instance_deletion_notification_subject: 'An Event Has Been Deleted'
instance_deletion_notification_body: 'Unfortunately, the [eventinstance:title] [eventinstance:reg_type] has been deleted. Your registration has been deleted.'
series_deletion_notification_enabled: true
series_deletion_notification_subject: 'An Event Series Has Been Deleted'
series_deletion_notification_body: 'Unfortunately, the [eventinstance:title] [eventinstance:reg_type] has been deleted. Your registration has been deleted.'
instance_modification_notification_enabled: true
instance_modification_notification_subject: 'An Event Has Been Modified'
instance_modification_notification_body: "The [eventinstance:title] [eventinstance:reg_type] has been modified, please check back for details.\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
series_modification_notification_enabled: true
series_modification_notification_subject: 'An Event Series Has Been Modified'
series_modification_notification_body: 'The [eventinstance:title] [eventinstance:reg_type] has been modified, and all instances have been removed, and your registration has been deleted.'
notifications:
registration_notification:
enabled: true
subject: 'You''ve Successfully Registered'
body: "Your registration for the [eventinstance:title] [eventinstance:reg_type] was successful.\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
waitlist_notification:
enabled: true
subject: 'You''ve Been Added To The Waitlist'
body: "You have been added to the waitlist for the [eventinstance:title] [eventinstance:reg_type].\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
promotion_notification:
enabled: true
subject: 'You''ve Been Added To The Registration List'
body: "You have been promoted from the waitlist to the registration list for the [eventinstance:title] [eventinstance:reg_type].\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
instance_deletion_notification:
enabled: true
subject: 'An Event Has Been Deleted'
body: 'Unfortunately, the [eventinstance:title] [eventinstance:reg_type] has been deleted. Your registration has been deleted.'
series_deletion_notification:
enabled: true
subject: 'An Event Series Has Been Deleted'
body: 'Unfortunately, the [eventinstance:title] [eventinstance:reg_type] has been deleted. Your registration has been deleted.'
instance_modification_notification:
enabled: true
subject: 'An Event Has Been Modified'
body: "The [eventinstance:title] [eventinstance:reg_type] has been modified, please check back for details.\r\n\r\nModify your registration: [registrant:edit_url]\r\nDelete your registration: [registrant:delete_url]"
series_modification_notification:
enabled: true
subject: 'An Event Series Has Been Modified'
body: 'The [eventinstance:title] [eventinstance:reg_type] has been modified, and all instances have been removed, and your registration has been deleted.'
......@@ -5,6 +5,15 @@ recurring_events_registration.registrant.config:
show_capacity:
type: boolean
label: 'Whether to display the remaining capacity for an event during registration'
insert_redirect_choice:
type: string
label: 'Choose where registrant form redirects'
insert_redirect_other:
type: string
label: 'Type custom URL here'
use_admin_theme:
type: boolean
label: 'Use the administration theme when managing registrations'
limit:
type: integer
label: 'The items per page to show on registrant listing'
......@@ -17,70 +26,42 @@ recurring_events_registration.registrant.config:
email_notifications:
type: boolean
label: 'Whether to enable email notifications'
registration_notification_enabled:
type: boolean
label: 'Whether to enable registration email notifications'
registration_notification_subject:
type: string
label: 'The email subject for the registration emails'
registration_notification_body:
type: string
label: 'The email body for the registration emails'
waitlist_notification_enabled:
type: boolean
label: 'Whether to enable waitlist email notifications'
waitlist_notification_subject:
type: string
label: 'The email subject for the waitlist emails'
waitlist_notification_body:
type: string
label: 'The email body for the waitlist emails'
promotion_notification_enabled:
type: boolean
label: 'Whether to enable promotion email notifications'
promotion_notification_subject:
type: string
label: 'The email subject for the promotion emails'
promotion_notification_body:
type: string
label: 'The email body for the promotion emails'
instance_deletion_notification_enabled:
email_notifications_queue:
type: boolean
label: 'Whether to enable instance deletion email notifications'
instance_deletion_notification_subject:
type: string
label: 'The email subject for the instance deletion emails'
instance_deletion_notification_body:
type: string
label: 'The email body for the instance deletion emails'
series_deletion_notification_enabled:
type: boolean
label: 'Whether to enable series deletion email notifications'
series_deletion_notification_subject:
type: string
label: 'The email subject for the series deletion emails'
series_deletion_notification_body:
type: string
label: 'The email body for the series deletion emails'
instance_modification_notification_enabled:
type: boolean
label: 'Whether to enable instance modification email notifications'
instance_modification_notification_subject:
type: string
label: 'The email subject for the instance modification emails'
instance_modification_notification_body:
type: string
label: 'The email body for the instance modification emails'
series_modification_notification_enabled:
type: boolean
label: 'Whether to enable series modification email notifications'
series_modification_notification_subject:
type: string
label: 'The email subject for the series modification emails'
series_modification_notification_body:
type: string
label: 'The email body for the series modification emails'
label: 'Whether to use the email notifications queue'
successfully_registered:
type: label
label: 'The message to display when a registrant is successfully created'
successfully_registered_waitlist:
type: label
label: 'The message to display when a registrant is successfully added to the waitlist'
successfully_updated:
type: label
label: 'The message to display when a registrant is successfully updated'
successfully_updated_waitlist:
type: label
label: 'The message to display when a registrant on the waitlist is successfully updated'
already_registered:
type: label
label: 'The message to display when a user is already registered for an event'
registration_closed:
type: label
label: 'The message to display when registration is closed for an event'
notifications:
type: sequence
sequence:
type: mapping
label: 'Email notification'
mapping:
enabled:
type: boolean
label: 'Whether to enable these notifications'
subject:
type: label
label: 'The email subject for these notifications'
body:
type: text
label: 'The email body for these notifications'
field.widget.settings.event_registration:
type: mapping
label: 'Recurring Events Show Enable Waitlist'
......
views.filter.eventinstance_registration_availability_count:
type: views.filter.numeric
views.filter_value.eventinstance_registration_availability_count:
type: views.filter_value.numeric
views.argument.eventinstance_registration_availability_count:
type: views.argument.numeric
name: Recurring Events Registration Reminders
type: module
description: Enables reminders to be sent for upcoming events.
package: Recurring Events
core_version_requirement: ^9.3 || ^10
dependencies:
- recurring_events:recurring_events
- recurring_events:recurring_events_registration
<?php
/**
* @file
* Install and update functions for the Registration Reminders submodule.
*/
use Drupal\Core\Field\BaseFieldDefinition;
/**
* Install the schema updates for eventseries entities to add registration.
*
* @see hook_install()
*/
function recurring_events_reminders_install() {
// Add the registration reminders custom field to eventseries.
$storage_definition = BaseFieldDefinition::create('registration_reminders')
->setName('registration_reminders')
->setLabel(t('Event Registration Reminders'))
->setDescription('The event registration reminders configuration.')
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE)
->setRevisionable(TRUE)
->setTranslatable(FALSE)
->setCardinality(1)
->setRequired(FALSE)
->setDisplayOptions('form', [
'type' => 'registration_reminders',
'weight' => 11,
]);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('registration_reminders', 'eventseries', 'eventseries', $storage_definition);
// Add a field to eventinstances to store the desired reminder date.
$storage_definition = BaseFieldDefinition::create('timestamp')
->setName('reminder_date')
->setLabel(t('Reminder Date'))
->setDescription('The date that reminders should be sent.')
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE)
->setRevisionable(FALSE)
->setTranslatable(FALSE)
->setCardinality(1)
->setRequired(FALSE);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('reminder_date', 'eventinstance', 'eventinstance', $storage_definition);
// Add a field to eventinstances to store date reminders were sent.
$storage_definition = BaseFieldDefinition::create('timestamp')
->setName('reminder_sent')
->setLabel(t('Reminder Sent'))
->setDescription('The date that reminders were sent.')
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE)
->setRevisionable(FALSE)
->setTranslatable(FALSE)
->setCardinality(1)
->setRequired(FALSE);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('reminder_sent', 'eventinstance', 'eventinstance', $storage_definition);
// Set the default reminder email subject and body config.
$config = \Drupal::configFactory()->getEditable('recurring_events_registration.registrant.config');
$values = $config->get('notifications');
$values['registration_reminder'] = [
'enabled' => TRUE,
'subject' => 'Upcoming Event Reminder',
'body' => '[eventseries:reminder_message]',
];
$config->set('notifications', $values);
$config->save(TRUE);
}
<?php
/**
* @file
* Primary module hooks for Recurring Events Registration Reminders module.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
/**
* Implements hook_entity_base_field_info_alter().
*/
function recurring_events_reminders_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
$entity_type_id = $entity_type->id();
if ($entity_type_id === 'eventseries') {
$fields['registration_reminders'] = BaseFieldDefinition::create('registration_reminders')
->setName('registration_reminders')
->setLabel(t('Event Registration Reminders'))
->setDescription('The event registration reminders configuration.')
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE)
->setRevisionable(TRUE)
->setTranslatable(FALSE)
->setCardinality(1)
->setRequired(FALSE)
->setTargetEntityTypeId($entity_type->id())
->setDisplayOptions('form', [
'type' => 'registration_reminders',
'weight' => 10,
]);
}
if ($entity_type_id === 'eventinstance') {
$fields['reminder_date'] = BaseFieldDefinition::create('timestamp')
->setName('reminder_date')
->setLabel(t('Reminder Date'))
->setDescription('The date that reminders should be sent.')
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE)
->setRevisionable(FALSE)
->setTranslatable(FALSE)
->setTargetEntityTypeId($entity_type_id)
->setCardinality(1)
->setRequired(FALSE);
$fields['reminder_sent'] = BaseFieldDefinition::create('timestamp')
->setName('reminder_sent')
->setLabel(t('Reminder Sent'))
->setDescription('The date that reminders were sent.')
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE)
->setRevisionable(FALSE)
->setTranslatable(FALSE)
->setTargetEntityTypeId($entity_type_id)
->setCardinality(1)
->setRequired(FALSE);
}
}
/**
* Implements hook_ENTITY_TYPE_insert().
*
* Set the reminder date for all instances in this series.
*/
function recurring_events_reminders_eventseries_insert(EntityInterface $entity) {
if (\Drupal::isConfigSyncing()) {
return;
}
if ($entity->registration_reminders->reminder) {
$amount = $entity->registration_reminders->reminder_amount;
$units = $entity->registration_reminders->reminder_units;
$instances = $entity->event_instances->referencedEntities();
if (!empty($instances)) {
foreach ($instances as $instance) {
$instance_date = $instance->date->start_date->getTimestamp();
$reminder_date = strtotime('-' . $amount . ' ' . $units, $instance_date);
$instance->set('reminder_date', $reminder_date);
$instance->setNewRevision(FALSE);
$instance->save();
}
}
}
}
/**
* Implements hook_ENTITY_TYPE_update().
*
* Set the reminder date for all instances in this series.
*/
function recurring_events_reminders_eventseries_update(EntityInterface $entity) {
$original = $entity->original;
if ($entity->registration_reminders->reminder) {
$entity = $entity->load($entity->id());
if ($original->registration_reminders->reminder_amount !== $entity->registration_reminders->reminder_amount
|| $original->registration_reminders->reminder_units !== $entity->registration_reminders->reminder_units
) {
$amount = $entity->registration_reminders->reminder_amount;
$units = $entity->registration_reminders->reminder_units;
$instances = $entity->event_instances->referencedEntities();
if (!empty($instances)) {
foreach ($instances as $instance) {
$instance_date = $instance->date->start_date->getTimestamp();
$reminder_date = strtotime('-' . $amount . ' ' . $units, $instance_date);
$instance->set('reminder_date', $reminder_date);
$instance->set('reminder_sent', NULL);
$instance->setNewRevision(FALSE);
$instance->save();
}
}
}
}
// If reminders have been disabled, then set the reminder_date to NULL.
elseif ($original->registration_reminders->reminder !== $entity->registration_reminders->reminder) {
$instances = $entity->event_instances->referencedEntities();
if (!empty($instances)) {
foreach ($instances as $instance) {
$instance->set('reminder_date', NULL);
$instance->setNewRevision(FALSE);
$instance->save();
}
}
}
}
/**
* Implements hook_cron().
*/
function recurring_events_reminders_cron() {
$query = \Drupal::entityTypeManager()->getStorage('eventinstance')->getQuery();
$event_instances = $query
->condition('reminder_date', NULL, 'IS NOT NULL')
->condition('reminder_sent', NULL, 'IS NULL')
->condition('reminder_date', time(), '<=')
->accessCheck(FALSE)
->execute();
if (!empty($event_instances)) {
$instances = \Drupal::entityTypeManager()->getStorage('eventinstance')->loadMultiple($event_instances);
/** @var \Drupal\recurring_events\Entity\EventInstance */
foreach ($instances as $instance) {
$instance->set('reminder_sent', time());
$instance->setNewRevision(FALSE);
$instance->save();
/** @var \Drupal\recurring_events_registration\RegistrationCreationService */
$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 = 'registration_reminder';
$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_registration_notification_types_alter().
*/
function recurring_events_reminders_recurring_events_registration_notification_types_alter(array &$notification_types) {
$notification_types += [
'registration_reminder' => [
'name' => t('Registration Reminder'),
'description' => t('Send an email to remind registrants about upcoming events? Note: The event series must be configured to send reminders.'),
],
];
}
/**
* Implements hook_config_schema_info_alter().
*/
function recurring_events_reminders_config_schema_info_alter(&$definitions) {
$definitions['recurring_events_registration.registrant.config']['mapping']['registration_reminder_enabled'] = [
'type' => 'boolean',
'label' => 'Whether to enable email reminders for upcoming events',
];
$definitions['recurring_events_registration.registrant.config']['mapping']['registration_reminder_subject'] = [
'type' => 'string',
'label' => 'The email subject for the reminder emails',
];
$definitions['recurring_events_registration.registrant.config']['mapping']['registration_reminder_body'] = [
'type' => 'string',
'label' => 'The email body for the reminder emails',
];
}
<?php
/**
* @file
* Tokens for the recurring_events_reminders module.
*/
use Drupal\Core\Render\BubbleableMetadata;
/**
* Implements hook_token_info().
*/
function recurring_events_reminders_token_info() {
$eventseries = [];
$eventseries_type = [
'name' => t('Event Series'),
'description' => t('Tokens for the eventseries entity type.'),
'needs-data' => 'eventseries',
];
$eventseries['reminder_message'] = [
'name' => t('Event Series Reminder Message'),
'description' => t('The reminder message to send to registrants.'),
];
return [
'types' => [
'eventseries' => $eventseries_type,
],
'tokens' => [
'eventseries' => $eventseries,
],
];
}
/**
* Implements hook_tokens().
*/
function recurring_events_reminders_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
$replacements = [];
if ($type == 'eventseries' && !empty($data['eventseries'])) {
$event_series = $data['eventseries'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'reminder_message':
$replacements[$original] = $event_series->registration_reminders->value;
break;
}
}
}
return $replacements;
}
<?php
namespace Drupal\recurring_events_reminders\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\text\Plugin\Field\FieldType\TextLongItem;
/**
* Plugin implementation of the 'registration_reminder' field type.
*
* @FieldType (
* id = "registration_reminders",
* label = @Translation("Event Registration Reminders"),
* description = @Translation("Stores an event registration reminders configuration"),
* default_widget = "registration_reminders",
* default_formatter = "registration_reminders"
* )
*/
class RegistrationReminders extends TextLongItem {
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
$schema = parent::schema($field_definition);
$schema['columns']['reminder'] = [
'type' => 'int',
'default' => 0,
'unsigned' => TRUE,
];
$schema['columns']['reminder_amount'] = [
'type' => 'int',
'default' => 0,
'unsigned' => TRUE,
];
$schema['columns']['reminder_units'] = [
'type' => 'varchar',
'length' => 255,
];
return $schema;
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$reminder = $this->get('reminder')->getValue();
$reminder_amount = $this->get('reminder_amount')->getValue();
$reminder_units = $this->get('reminder_units')->getValue();
return parent::isEmpty() &&
empty($reminder) &&
empty($reminder_amount) &&
empty($reminder_units);
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties = parent::propertyDefinitions($field_definition);
$properties['reminder'] = DataDefinition::create('boolean')
->setLabel(t('Enable Email Reminder'))
->setDescription(t('Select whether to enable email reminders for registrants.'));
$properties['reminder_amount'] = DataDefinition::create('integer')
->setLabel(t('Reminder Time'))
->setDescription(t('Select when the reminder should be sent out.'));
$properties['reminder_units'] = DataDefinition::create('string')
->setLabel(t('Reminder Time Units'))
->setDescription(t('Select when the reminder should be sent out (units).'));
return $properties;
}
}
<?php
namespace Drupal\recurring_events_reminders\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\recurring_events_registration\RegistrationCreationService;
use Drupal\text\Plugin\Field\FieldWidget\TextareaWidget;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'event registration reminders' widget.
*
* @FieldWidget (
* id = "registration_reminders",
* label = @Translation("Event registration reminders widget"),
* field_types = {
* "registration_reminders"
* }
* )
*/
class RegistrationRemindersWidget extends TextareaWidget {
use StringTranslationTrait;
/**
* The registration creation service.
*
* @var \Drupal\recurring_events_registration\RegistrationCreationService
*/
protected $creationService;
/**
* Constructs a WidgetBase object.
*
* @param string $plugin_id
* The plugin_id for the widget.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The definition of the field to which the widget is associated.
* @param array $settings
* The widget settings.
* @param array $third_party_settings
* Any third party settings.
* @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service
* The registration creation service.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, RegistrationCreationService $creation_service) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
$this->fieldDefinition = $field_definition;
$this->settings = $settings;
$this->thirdPartySettings = $third_party_settings;
$this->creationService = $creation_service;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['third_party_settings'],
$container->get('recurring_events_registration.creation_service')
);
}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$message = parent::formElement($items, $delta, $element, $form, $form_state);
$element['data'] = [
'#type' => 'fieldset',
'#title' => $this->t('Event Registration Reminders'),
'#states' => [
'visible' => [
'input[name="event_registration[0][registration]"]' => [
'checked' => TRUE,
],
],
],
];
$element['data']['reminder'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable Registration Reminders'),
'#description' => $this->t('Select this box to enable registration reminders for this event.'),
'#weight' => 0,
'#default_value' => $items[$delta]->reminder ?: '',
];
$element['data']['reminder_data'] = [
'#type' => 'container',
'#states' => [
'visible' => [
'input[name="registration_reminders[0][data][reminder]"]' => [
'checked' => TRUE,
],
],
],
];
$element['data']['reminder_data']['reminder_amount'] = [
'#type' => 'number',
'#prefix' => $this->t('Send a reminder'),
'#title' => '',
'#weight' => 1,
'#default_value' => $items[$delta]->reminder_amount ?? '1',
'#min' => 0,
];
$element['data']['reminder_data']['reminder_units'] = [
'#type' => 'select',
'#title' => '',
'#weight' => 2,
'#default_value' => $items[$delta]->reminder_units ?? 'month',
'#options' => [
'month' => $this->t('months'),
'week' => $this->t('weeks'),
'day' => $this->t('days'),
'hour' => $this->t('hours'),
'minute' => $this->t('minutes'),
],
'#suffix' => $this->t('before the event starts'),
];
$element['data']['reminder_data']['message'] = $message;
$element['data']['reminder_data']['message']['#title'] = $this->t('Reminder Message');
$element['data']['reminder_data']['message']['#weight'] = 99;
$registrant_tokens = $this->creationService->getAvailableTokens([
'registrant',
'eventseries',
'eventinstance',
]);
$element['data']['reminder_data']['tokens'] = $registrant_tokens;
$element['data']['reminder_data']['tokens']['#weight'] = 100;
return $element;
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
foreach ($values as &$item) {
$item['reminder'] = $item['data']['reminder'] ?? 0;
$item['reminder_amount'] = $item['data']['reminder_data']['reminder_amount'];
$item['reminder_units'] = $item['data']['reminder_data']['reminder_units'];
$item['value'] = $item['data']['reminder_data']['message']['value'] ?? '';
$item['format'] = $item['data']['reminder_data']['message']['format'];
unset($item['data']);
}
$values = parent::massageFormValues($values, $form, $form_state);
return $values;
}
}
......@@ -6,6 +6,7 @@
*/
use Drupal\recurring_events_registration\Entity\Registrant;
use Drupal\recurring_events_registration\Entity\RegistrantInterface;
/**
* Alter the registrant to be promoted from the waitlist.
......@@ -16,10 +17,10 @@ use Drupal\recurring_events_registration\Entity\Registrant;
* instance of Drupal\recurring_events_registration\Entity\Registrant for the
* specified event, which can be retrieved from the registrant entity.
*
* @param Drupal\recurring_events_registration\Entity\Registrant $registrant
* @param \Drupal\recurring_events_registration\Entity\Registrant $registrant
* The default selected registrant.
*
* @return Drupal\recurring_events_registration\Entity\Registrant
* @return \Drupal\recurring_events_registration\Entity\Registrant
* A valid registrant entity.
*/
function hook_recurring_events_registration_first_waitlist_alter(Registrant $registrant) {
......@@ -29,6 +30,20 @@ function hook_recurring_events_registration_first_waitlist_alter(Registrant $reg
return $new_registrant;
}
/**
* Alter if a notification will be sent based on properties of the Registrant.
*
* @param bool $send_email
* Whether the notification email is sent.
* @param \Drupal\recurring_events_registration\Entity\RegistrantInterface $registrant
* The registrant entity.
*/
function hook_recurring_events_registration_send_notification_alter(bool &$send_email, RegistrantInterface $registrant) {
if ($registrant->id() == 100) {
$send_email = FALSE;
}
}
/**
* Alter the types of notification available in the registrant settings.
*
......@@ -44,8 +59,37 @@ function hook_recurring_events_registration_first_waitlist_alter(Registrant $reg
* The notification types array.
*/
function hook_recurring_events_registration_notification_types_alter(array &$notification_types) {
$notification_types['rename'] = [
$notification_types['rename_notification'] = [
'name' => t('Event Rename Notification'),
'description' => t('Send an email to registrants when the event name changes?'),
];
}
/**
* Alter the `$params` passed to email functions when sending notifications.
*
* Developers can get the data from `$registrant` entity. The `$params` array
* is used later as `$params` in `hook_mail()` and `$message['params']` in
* `hook_mail_alter()`.
*
* We encourage developers to make use of this hook 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. No loaded entities
* and no configuration objects (since for queued messages, those could have
* changed or been deleted by the moment the queue worker is called).
*
* @param array $params
* The params array.
* @param \Drupal\recurring_events_registration\Entity\RegistrantInterface $registrant
* The Registrant entity. Based on it, developers can perform the logic to
* alter the params array.
*/
function hook_recurring_events_registration_message_params_alter(array &$params, RegistrantInterface $registrant) {
// Add a new parameter to the params based on some logic over a registrant
// field.
if ($registrant->hasField('some_field') && !$registrant->get('some_field')->isEmpty()) {
$some_field_value = $registrant->get('some_field')->first()->getString();
$value = do_something($some_field_value);
$params['custom_param'] = $value;
}
}
recurring_events_registration.registrant.config:
title: 'Recurring Events Registration configuration'
base_route_name: registrant.settings
names:
- recurring_events_registration.registrant.config
name: 'Recurring Events Registration'
type: module
description: 'Provides the ability to register for recurring events'
core: 8.x
core_version_requirement: ^8 || ^9
core_version_requirement: ^9.3 || ^10
package: 'Recurring Events'
dependencies:
- recurring_events:recurring_events