diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..ec9c9dc6da74243090a1f013b73e4b60bbe2656e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,101 @@ +language: php + +# The Travis CI container mode has random functional test fails, so we must use +# sudo here. +sudo: true + +php: + - 7.1 + - 7.2 + - 7.3 + +services: + - mysql + +env: + global: + - MODULE=recurring_events + matrix: + - DRUPAL_CORE=8.8.x DRUSH_VER=9.0 + - DRUPAL_CORE=8.9.x DRUSH_VER=9.0 + - DRUPAL_CORE=9.0.x DRUSH_VER=10.0 + +matrix: + fast_finish: true + exclude: + - php: 7.1 + env: DRUPAL_CORE=9.0.x DRUSH_VER=10.0 + - php: 7.2 + env: DRUPAL_CORE=9.0.x DRUSH_VER=10.0 + +# Be sure to cache composer downloads. +cache: + directories: + - $HOME/.composer + +before_script: + # Remove Xdebug as we don't need it and it causes + # PHP Fatal error: Maximum function nesting level of '256' reached. + # We also don't care if that file exists or not on PHP 7. + - phpenv config-rm xdebug.ini || true + + # Navigate out of module directory to prevent blown stack by recursive module + # lookup. + - cd .. + + # Create database. + - mysql -e "create database $MODULE" + # Export database variable for kernel tests. + - export SIMPLETEST_DB=mysql://root:@127.0.0.1/$MODULE + + # Create a new Drupal project using the appropriate version using Composer. + - COMPOSER_MEMORY_LIMIT=-1 composer create-project drupal/recommended-project:$DRUPAL_CORE drupal --stability dev --no-interaction + - cd drupal + - DRUPAL_ROOT=$(pwd) + + # Add the necessary third party dependencies to run these tests. + - COMPOSER_MEMORY_LIMIT=-1 composer require drupal/field_inheritance + - COMPOSER_MEMORY_LIMIT=-1 composer require drush/drush:^$DRUSH_VER + - COMPOSER_MEMORY_LIMIT=-1 composer require mglaman/drupal-check --dev + - COMPOSER_MEMORY_LIMIT=-1 composer require drupal/group:1.x-dev + + - cd $DRUPAL_ROOT + + # The recurring events module artifact is already available, so copy it in + # to the contrib module directory so we can run our tests. + - cp -R $TRAVIS_BUILD_DIR web/modules/contrib/$MODULE + + # Coder is already installed as part of composer install. We just need to set + # the installed_paths to pick up the Drupal standards. + - $DRUPAL_ROOT/vendor/bin/phpcs --config-set installed_paths $DRUPAL_ROOT/vendor/drupal/coder/coder_sniffer + + # Export web server URL for browser tests. + - export SIMPLETEST_BASE_URL=http://localhost:8888 + +script: + # Install the site using Drush and set up some configuration. + - ./vendor/bin/drush site-install standard --yes --account-pass=admin --db-url=$SIMPLETEST_DB + - ./vendor/bin/drush config-set system.performance css.preprocess 0 --yes + - ./vendor/bin/drush config-set system.performance js.preprocess 0 --yes + - ./vendor/bin/drush config-set system.logging error_level all --yes + + # Enable the modules we care to run the tests. + - ./vendor/bin/drush en simpletest $MODULE recurring_events_registration recurring_events_views --yes + + # Start up a HTTP server for tests. + - ./vendor/bin/drush runserver --default-server=builtin 8888 > /dev/null & + + # Run the PHPUnit tests. + - ./vendor/bin/phpunit -c ./web/core/phpunit.xml.dist --verbose --group=$MODULE ./web/modules/contrib/$MODULE + + # Run the deprecation checks. + - ./vendor/bin/drupal-check ./web/modules/contrib/$MODULE + + # Check for coding standards. First change directory to our module. + - cd $DRUPAL_ROOT/web/modules/contrib/$MODULE + + # Show the violations in detail and do not fail for any errors or warnings. + - $DRUPAL_ROOT/vendor/bin/phpcs --standard=drupal,drupalPractice --ignore=vendor --report-width=130 --colors --runtime-set ignore_warnings_on_exit 1 --runtime-set ignore_errors_on_exit 0 . + + # Run again to give a summary and total count. + - $DRUPAL_ROOT/vendor/bin/phpcs --standard=drupal,drupalPractice --ignore=vendor --report-width=130 --colors --runtime-set ignore_warnings_on_exit 1 --runtime-set ignore_errors_on_exit 0 --report=summary . diff --git a/README.md b/README.md deleted file mode 100644 index 9c2d9b243983cac921dc24f2fc2407d7ba98f426..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Recurring Events (recurring_events) -============ - -## Introduction -The Recurring Events module is a plug-and-play recurring events and registration system designed to be site agnostic and extensible. Detailed information about the module is available on the module's help page at /admin/help/recurring_events. \ No newline at end of file diff --git a/composer.json b/composer.json index 4cc8f4dba4369e720ddd5ad40e48e4ac29ba1d4f..8e57f38c3b3e2179756e2b93e7ef8b7a198f79a6 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "drupal/recurring_events", "type": "drupal-module", - "description": "Events and Registration Management Module", + "description": "Recurring Events and Registration Management Module", "keywords": ["Drupal"], "license": "GPL-2.0+", "homepage": "https://www.drupal.org/project/recurring_events", @@ -10,5 +10,7 @@ "issues": "https://www.drupal.org/project/issues/recurring_events", "source": "http://cgit.drupalcode.org/recurring_events" }, - "require": { } + "require": { + "drupal/field_inheritance": "^1" + } } diff --git a/config/install/core.entity_form_display.eventseries.eventseries.default.yml b/config/install/core.entity_form_display.eventseries.default.default.yml similarity index 93% rename from config/install/core.entity_form_display.eventseries.eventseries.default.yml rename to config/install/core.entity_form_display.eventseries.default.default.yml index adbba6f41169eb8504e78a44cf1f562dfd1f3cd8..c426d6fde2036971b377315bd578f8e28c2ba9da 100644 --- a/config/install/core.entity_form_display.eventseries.eventseries.default.yml +++ b/config/install/core.entity_form_display.eventseries.default.default.yml @@ -1,13 +1,15 @@ langcode: en status: true dependencies: + config: + - recurring_events.eventseries_type.default module: - datetime_range - recurring_events - text -id: eventseries.eventseries.default +id: eventseries.default.default targetEntityType: eventseries -bundle: eventseries +bundle: default mode: default content: body: @@ -26,7 +28,6 @@ content: third_party_settings: { } custom_date: type: daterange_default - label: above weight: 7 region: content settings: { } @@ -39,14 +40,12 @@ content: third_party_settings: { } excluded_dates: type: daterange_default - label: above weight: 8 settings: { } region: content third_party_settings: { } included_dates: type: daterange_default - label: above weight: 9 settings: { } region: content @@ -85,6 +84,7 @@ content: match_operator: CONTAINS size: 60 placeholder: '' + match_limit: 10 region: content third_party_settings: { } weekly_recurring_date: diff --git a/config/install/core.entity_view_display.eventinstance.eventinstance.default.yml b/config/install/core.entity_view_display.eventinstance.default.default.yml similarity index 63% rename from config/install/core.entity_view_display.eventinstance.eventinstance.default.yml rename to config/install/core.entity_view_display.eventinstance.default.default.yml index 2fb3cc9959de6528bb382d54b1737d9df443e440..60f6ba50528c91589d6df8912bcf6528359e34b0 100644 --- a/config/install/core.entity_view_display.eventinstance.eventinstance.default.yml +++ b/config/install/core.entity_view_display.eventinstance.default.default.yml @@ -1,33 +1,41 @@ langcode: en status: true dependencies: + config: + - recurring_events.eventinstance_type.default module: - datetime_range - recurring_events - text -id: eventinstance.eventinstance.default +id: eventinstance.default.default targetEntityType: eventinstance -bundle: eventinstance +bundle: default mode: default content: date: label: above type: daterange_default - weight: 2 + weight: 1 settings: - fromto: both - separator: '-' - format_type: medium timezone_override: '' + format_type: long + separator: '-' region: content third_party_settings: { } description: type: text_default - weight: 1 + weight: 2 region: content label: above settings: { } third_party_settings: { } + title: + type: string + weight: 0 + region: content + label: above + settings: + link_to_entity: false + third_party_settings: { } hidden: body: true - title: true diff --git a/config/install/core.entity_view_display.eventinstance.default.list.yml b/config/install/core.entity_view_display.eventinstance.default.list.yml new file mode 100644 index 0000000000000000000000000000000000000000..12fb9f8fed12d19299454b87aa5aaf5e0c9be720 --- /dev/null +++ b/config/install/core.entity_view_display.eventinstance.default.list.yml @@ -0,0 +1,42 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.eventinstance.list + - recurring_events.eventinstance_type.default + module: + - datetime_range + - text +id: eventinstance.default.list +targetEntityType: eventinstance +bundle: default +mode: list +content: + date: + label: hidden + type: daterange_default + weight: 1 + settings: + timezone_override: '' + format_type: short + separator: '-' + region: content + third_party_settings: { } + description: + type: text_trimmed + weight: 2 + region: content + label: visually_hidden + settings: + trim_length: 200 + third_party_settings: { } + title: + type: string + weight: 0 + region: content + label: hidden + settings: + link_to_entity: true + third_party_settings: { } +hidden: + body: true diff --git a/config/install/core.entity_view_display.eventseries.eventseries.default.yml b/config/install/core.entity_view_display.eventseries.default.default.yml similarity index 77% rename from config/install/core.entity_view_display.eventseries.eventseries.default.yml rename to config/install/core.entity_view_display.eventseries.default.default.yml index cc48ff79b39708cfe0958365b1655346d54af6ac..3ee75d19dd8b25d57c98a3e4babffbebe1615e12 100644 --- a/config/install/core.entity_view_display.eventseries.eventseries.default.yml +++ b/config/install/core.entity_view_display.eventseries.default.default.yml @@ -1,49 +1,53 @@ langcode: en status: true dependencies: + config: + - recurring_events.eventseries_type.default module: - options - recurring_events - text -id: eventseries.eventseries.default +id: eventseries.default.default targetEntityType: eventseries -bundle: eventseries +bundle: default mode: default content: body: label: above - weight: 10 + weight: 1 region: content settings: { } third_party_settings: { } type: text_default event_instances: type: recurring_events_eventinstance_date + weight: 3 + region: content label: above - weight: 10 settings: - link: true + link: '1' date_format: 'F jS, Y h:iA' separator: ' - ' - region: content third_party_settings: { } recur_type: label: above - weight: 10 + weight: 2 region: content settings: { } third_party_settings: { } type: list_default title: label: above - weight: 10 + weight: 0 region: content settings: link_to_entity: false third_party_settings: { } type: string hidden: + consecutive_recurring_date: true custom_date: true + daily_recurring_date: true event_registration: true monthly_recurring_date: true weekly_recurring_date: true diff --git a/config/install/core.entity_view_display.eventseries.default.list.yml b/config/install/core.entity_view_display.eventseries.default.list.yml new file mode 100644 index 0000000000000000000000000000000000000000..b3f4281ce716f0dec71e8552fb05458707951fac --- /dev/null +++ b/config/install/core.entity_view_display.eventseries.default.list.yml @@ -0,0 +1,38 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.eventseries.list + - recurring_events.eventseries_type.default + module: + - text +id: eventseries.default.list +targetEntityType: eventseries +bundle: default +mode: list +content: + body: + label: hidden + weight: 1 + region: content + settings: + trim_length: 200 + third_party_settings: { } + type: text_trimmed + title: + label: hidden + weight: 0 + region: content + settings: + link_to_entity: true + third_party_settings: { } + type: string +hidden: + consecutive_recurring_date: true + custom_date: true + daily_recurring_date: true + event_instances: true + event_registration: true + monthly_recurring_date: true + recur_type: true + weekly_recurring_date: true diff --git a/config/install/core.entity_view_mode.eventinstance.list.yml b/config/install/core.entity_view_mode.eventinstance.list.yml new file mode 100644 index 0000000000000000000000000000000000000000..4e18aa05bea63b3293396b03c7d2a6d33db3b65b --- /dev/null +++ b/config/install/core.entity_view_mode.eventinstance.list.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: + module: + - recurring_events +id: eventinstance.list +label: List +targetEntityType: eventinstance +cache: true diff --git a/config/install/core.entity_view_mode.eventseries.list.yml b/config/install/core.entity_view_mode.eventseries.list.yml new file mode 100644 index 0000000000000000000000000000000000000000..62bae030254fe0ce498a6f2e294b315297deeaf7 --- /dev/null +++ b/config/install/core.entity_view_mode.eventseries.list.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: + module: + - recurring_events +id: eventseries.list +label: List +targetEntityType: eventseries +cache: true diff --git a/config/install/field_inheritance.field_inheritance.eventinstance_default_description.yml b/config/install/field_inheritance.field_inheritance.eventinstance_default_description.yml new file mode 100644 index 0000000000000000000000000000000000000000..2bd1b02b4bd590fbc3957aa9e6abf596cac353a0 --- /dev/null +++ b/config/install/field_inheritance.field_inheritance.eventinstance_default_description.yml @@ -0,0 +1,13 @@ +langcode: en +status: true +dependencies: { } +id: eventinstance_default_description +label: Description +type: append +sourceEntityType: eventseries +sourceEntityBundle: default +sourceField: body +destinationEntityType: eventinstance +destinationEntityBundle: default +destinationField: body +plugin: default_inheritance diff --git a/config/install/field_inheritance.field_inheritance.eventinstance_default_title.yml b/config/install/field_inheritance.field_inheritance.eventinstance_default_title.yml new file mode 100644 index 0000000000000000000000000000000000000000..0332bd54aac1836f84592dcdd36ac6dd03d2bd79 --- /dev/null +++ b/config/install/field_inheritance.field_inheritance.eventinstance_default_title.yml @@ -0,0 +1,12 @@ +langcode: en +status: true +dependencies: { } +id: eventinstance_default_title +label: Title +type: inherit +sourceEntityType: eventseries +sourceEntityBundle: default +sourceField: title +destinationEntityType: eventinstance +destinationEntityBundle: default +plugin: default_inheritance diff --git a/config/install/recurring_events.eventinstance_type.default.yml b/config/install/recurring_events.eventinstance_type.default.yml new file mode 100644 index 0000000000000000000000000000000000000000..a5b42dd93e4c23460dad80a9b24d14a272830c56 --- /dev/null +++ b/config/install/recurring_events.eventinstance_type.default.yml @@ -0,0 +1,6 @@ +langcode: en +status: true +dependencies: { } +label: Default +id: default +description: 'A default event instance type.' diff --git a/config/install/recurring_events.eventseries_type.default.yml b/config/install/recurring_events.eventseries_type.default.yml new file mode 100644 index 0000000000000000000000000000000000000000..f3865a6e07eb41be1599329318eb21a13e50ed1a --- /dev/null +++ b/config/install/recurring_events.eventseries_type.default.yml @@ -0,0 +1,6 @@ +langcode: en +status: true +dependencies: { } +label: Default +id: default +description: 'A default event series type.' diff --git a/config/install/recurring_events.field_inheritance.description.yml b/config/install/recurring_events.field_inheritance.description.yml deleted file mode 100644 index b775e48a033c4b014426824a036ffe79e895cb9d..0000000000000000000000000000000000000000 --- a/config/install/recurring_events.field_inheritance.description.yml +++ /dev/null @@ -1,9 +0,0 @@ -langcode: en -status: true -dependencies: { } -id: description -label: Description -type: append -sourceField: body -entityField: body -plugin: text_inheritance diff --git a/config/install/recurring_events.field_inheritance.title.yml b/config/install/recurring_events.field_inheritance.title.yml deleted file mode 100644 index 0ff470604ed269c0e4b921dd600445b9b6ed2d44..0000000000000000000000000000000000000000 --- a/config/install/recurring_events.field_inheritance.title.yml +++ /dev/null @@ -1,9 +0,0 @@ -langcode: en -status: true -dependencies: { } -id: title -label: Title -type: inherit -sourceField: title -entityField: '' -plugin: string_inheritance diff --git a/config/schema/eventinstance_type.schema.yml b/config/schema/eventinstance_type.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..a7c8a2157e4d091409d9651bfe180ceeed6ac98f --- /dev/null +++ b/config/schema/eventinstance_type.schema.yml @@ -0,0 +1,15 @@ +recurring_events.eventinstance_type.*: + type: config_entity + label: 'Event instance type config' + mapping: + id: + type: string + label: 'ID' + label: + type: label + label: 'Label' + description: + type: string + label: 'Description' + uuid: + type: string diff --git a/config/schema/eventseries_type.schema.yml b/config/schema/eventseries_type.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..6b5608ca3d6e7f5a27415543cd2a0c58f77c0236 --- /dev/null +++ b/config/schema/eventseries_type.schema.yml @@ -0,0 +1,15 @@ +recurring_events.eventseries_type.*: + type: config_entity + label: 'Event series type config' + mapping: + id: + type: string + label: 'ID' + label: + type: label + label: 'Label' + description: + type: string + label: 'Description' + uuid: + type: string diff --git a/config/schema/field_inheritance.schema.yml b/config/schema/field_inheritance.schema.yml deleted file mode 100644 index 0bde2530d5d0abd2befea9c964422d6cbce2f5c5..0000000000000000000000000000000000000000 --- a/config/schema/field_inheritance.schema.yml +++ /dev/null @@ -1,20 +0,0 @@ -recurring_events.field_inheritance.*: - type: config_entity - label: 'Field inheritance config' - mapping: - id: - type: string - label: 'ID' - label: - type: label - label: 'Label' - uuid: - type: string - type: - type: string - sourceField: - type: string - entityField: - type: string - plugin: - type: string diff --git a/config/schema/recurring_events.schema.yml b/config/schema/recurring_events.schema.yml index 036148ed0dc6f6a3fff11743c2b6545895f4d190..3f8647895bd16555f68a533f629f03c918e9a10c 100644 --- a/config/schema/recurring_events.schema.yml +++ b/config/schema/recurring_events.schema.yml @@ -55,3 +55,17 @@ recurring_events.eventinstance.config: limit: type: integer label: 'The items per page to show on event instance listing' + +field.formatter.settings.recurring_events_eventinstance_date: + type: mapping + label: 'Recurring Events Event Instance Date Formatter' + mapping: + link: + type: string + label: 'Whether to format the date as a link' + date_format: + type: string + label: 'The date format to use to display the date' + separator: + type: string + label: 'The separator to use between start and end dates' diff --git a/js/recurring_events_create_form.js b/js/recurring_events_create_form.js index 80ea729ee5bb8b819dae26e73d6e93955bedbbd9..969c17d681f5cb9e4d07d2a4193fcb43969b3ac8 100644 --- a/js/recurring_events_create_form.js +++ b/js/recurring_events_create_form.js @@ -1,3 +1,8 @@ +/** + * @file + * Javascript functionality for the recurring events create form. + */ + (function ($) { 'use strict'; @@ -5,7 +10,7 @@ * Add weekday selection based on date range. */ Drupal.behaviors.recurring_events_weekday_selection = { - attach: function(context, settings) { + attach: function (context, settings) { var weekdays = new Array(7); weekdays[0] = "sunday"; weekdays[1] = "monday"; @@ -16,7 +21,7 @@ weekdays[6] = "saturday"; // When the weekly occurrence start date is changed. - $('#edit-weekly-recurring-date-0-value-date').on('change', function(event) { + $('#edit-weekly-recurring-date-0-value-date').on('change', function (event) { var value = $(this).val(); var date_parts = value.split('-'); if (date_parts.length > 0) { @@ -24,7 +29,7 @@ var weekday = weekdays[date.getDay()]; // Remove all the weekday recurrence options. - $('#edit-weekly-recurring-date-0-days').find('input').each(function(key, item) { + $('#edit-weekly-recurring-date-0-days').find('input').each(function (key, item) { $(item).prop('checked', false); }); @@ -35,7 +40,7 @@ }); // When the monthly occurrence start date is changed. - $('#edit-monthly-recurring-date-0-value-date').on('change', function(event) { + $('#edit-monthly-recurring-date-0-value-date').on('change', function (event) { var value = $(this).val(); var date_parts = value.split('-'); if (date_parts.length > 0) { @@ -43,7 +48,7 @@ var weekday = weekdays[date.getDay()]; // Remove all the monthly recurrence options. - $('#edit-monthly-recurring-date-0-days').find('input').each(function(key, item) { + $('#edit-monthly-recurring-date-0-days').find('input').each(function (key, item) { $(item).prop('checked', false); }); @@ -59,12 +64,12 @@ * Set end date for excluded and included dates to be the same as the start. */ Drupal.behaviors.recurring_events_excluded_included_dates = { - attach: function(context, settings) { - $('#edit-excluded-dates-wrapper, #edit-included-dates-wrapper').find('input.form-date').once().on('change', function(e) { + attach: function (context, settings) { + $('#edit-excluded-dates-wrapper, #edit-included-dates-wrapper').find('input.form-date').once().on('change', function (e) { if ($(this).attr('name').includes('[value][date]')) { var start_date = this; var parent = $(this).closest('.form-wrapper'); - $(parent).find('input.form-date').each(function(index, item) { + $(parent).find('input.form-date').each(function (index, item) { if (index == 1) { if ($(item).val() == '') { $(item).val($(start_date).val()); @@ -76,4 +81,4 @@ } }; -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/js/recurring_events_date_form.js b/js/recurring_events_date_form.js index 320d913a5834b1bca536c0e65437fc26e44b1715..69ec49da9df82d73ccdb87d912f4884566fc0ceb 100644 --- a/js/recurring_events_date_form.js +++ b/js/recurring_events_date_form.js @@ -1,3 +1,8 @@ +/** + * @file + * Javascript functionality for the included/excluded date forms. + */ + (function ($) { 'use strict'; @@ -5,9 +10,9 @@ * Set end date for excluded and included dates to be the same as the start. */ Drupal.behaviors.recurring_events_excluded_included_config_dates = { - attach: function(context, settings) { + attach: function (context, settings) { - $('#edit-start').once().on('change', function(e) { + $('#edit-start').once().on('change', function (e) { if ($('#edit-end').val() == '') { $('#edit-end').val($(this).val()); } @@ -15,4 +20,4 @@ } }; -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/modules/recurring_events_registration/README.md b/modules/recurring_events_registration/README.md index 33e8cf404494c1e62df521200a6dac9dc12517b7..b2009856af1b039a71dfe228b4d766192f682048 100644 --- a/modules/recurring_events_registration/README.md +++ b/modules/recurring_events_registration/README.md @@ -2,4 +2,7 @@ Recurring Events (recurring_events) ============ ## Introduction -The Recurring Events Registration module is a submodule of recurring_events. It provides a registration system designed to be site agnostic and extensible. Detailed information about the module is available on the module's help page at /admin/help/recurring_events_registration. \ No newline at end of file +The Recurring Events Registration module is a submodule of recurring_events. It +provides a registration system designed to be site agnostic and extensible. +Detailed information about the module is available on the module's help page at +/admin/help/recurring_events_registration. diff --git a/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.registrant.default.yml b/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.default.default.yml similarity index 77% rename from modules/recurring_events_registration/config/install/core.entity_form_display.registrant.registrant.default.yml rename to modules/recurring_events_registration/config/install/core.entity_form_display.registrant.default.default.yml index 34e3adb35693b30f1859c6a68d9959924b214f0e..20993e5e8fac93634711e9905af376c28e429a05 100644 --- a/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.registrant.default.yml +++ b/modules/recurring_events_registration/config/install/core.entity_form_display.registrant.default.default.yml @@ -2,16 +2,15 @@ langcode: en status: true dependencies: config: - - field.field.registrant.registrant.field_first_name - - field.field.registrant.registrant.field_last_name - - field.field.registrant.registrant.field_phone + - field.field.registrant.default.field_first_name + - field.field.registrant.default.field_last_name + - field.field.registrant.default.field_phone + - recurring_events_registration.registrant_type.default module: - recurring_events_registration -_core: - default_config_hash: ea3xG3Ezt8XlAj9nlwP6v3hT-_F8IcEQHN6pb5OI55g -id: registrant.registrant.default +id: registrant.default.default targetEntityType: registrant -bundle: registrant +bundle: default mode: default content: email: @@ -53,6 +52,7 @@ content: match_operator: CONTAINS size: 60 placeholder: '' + match_limit: 10 region: content third_party_settings: { } hidden: { } diff --git a/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.registrant.default.yml b/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.default.default.yml similarity index 75% rename from modules/recurring_events_registration/config/install/core.entity_view_display.registrant.registrant.default.yml rename to modules/recurring_events_registration/config/install/core.entity_view_display.registrant.default.default.yml index 8b773bad3a260802952b453900da37de0dc31456..7b5ac92c750fcebfddc4376fe647f0cab4f30629 100644 --- a/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.registrant.default.yml +++ b/modules/recurring_events_registration/config/install/core.entity_view_display.registrant.default.default.yml @@ -2,17 +2,16 @@ langcode: en status: true dependencies: config: - - field.field.registrant.registrant.field_first_name - - field.field.registrant.registrant.field_last_name - - field.field.registrant.registrant.field_phone + - field.field.registrant.default.field_first_name + - field.field.registrant.default.field_last_name + - field.field.registrant.default.field_phone + - recurring_events_registration.registrant_type.default module: - recurring_events_registration - user -_core: - default_config_hash: 3clqPdEmzURlNSnHkS8qcIi_HNNeDJgzA336NT77DCE -id: registrant.registrant.default +id: registrant.default.default targetEntityType: registrant -bundle: registrant +bundle: default mode: default content: email: diff --git a/modules/recurring_events_registration/config/install/core.entity_view_mode.registrant.list.yml b/modules/recurring_events_registration/config/install/core.entity_view_mode.registrant.list.yml new file mode 100644 index 0000000000000000000000000000000000000000..375bf0a84d6210b5caddc71d3b568645cfe78cba --- /dev/null +++ b/modules/recurring_events_registration/config/install/core.entity_view_mode.registrant.list.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: + module: + - recurring_events_registration +id: registrant.list +label: List +targetEntityType: registrant +cache: true diff --git a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_first_name.yml b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_first_name.yml similarity index 76% rename from modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_first_name.yml rename to modules/recurring_events_registration/config/install/field.field.registrant.default.field_first_name.yml index 3c4342422f6620f93bc476f35d8913a0e1403abc..3ce536df2037998a5d7e8a405bdb0a8177298a58 100644 --- a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_first_name.yml +++ b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_first_name.yml @@ -3,12 +3,13 @@ status: true dependencies: config: - field.storage.registrant.field_first_name + - recurring_events_registration.registrant_type.default module: - recurring_events_registration -id: registrant.registrant.field_first_name +id: registrant.default.field_first_name field_name: field_first_name entity_type: registrant -bundle: registrant +bundle: default label: 'First Name' description: 'Enter your first name.' required: false diff --git a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_last_name.yml b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_last_name.yml similarity index 76% rename from modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_last_name.yml rename to modules/recurring_events_registration/config/install/field.field.registrant.default.field_last_name.yml index 28ba1a5127e8f9c89f0cda99eeabf120e15bb841..421a221151e814a7092556c69fa3d898a089f1e5 100644 --- a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_last_name.yml +++ b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_last_name.yml @@ -3,12 +3,13 @@ status: true dependencies: config: - field.storage.registrant.field_last_name + - recurring_events_registration.registrant_type.default module: - recurring_events_registration -id: registrant.registrant.field_last_name +id: registrant.default.field_last_name field_name: field_last_name entity_type: registrant -bundle: registrant +bundle: default label: 'Last Name' description: 'Enter your last name.' required: false diff --git a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_phone.yml b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_phone.yml similarity index 76% rename from modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_phone.yml rename to modules/recurring_events_registration/config/install/field.field.registrant.default.field_phone.yml index c5f9131451931bddf74082048ddf0f67b0035b76..5a788670e3e98c8d4a98be01245f03dfbefc965c 100644 --- a/modules/recurring_events_registration/config/install/field.field.registrant.registrant.field_phone.yml +++ b/modules/recurring_events_registration/config/install/field.field.registrant.default.field_phone.yml @@ -3,12 +3,13 @@ status: true dependencies: config: - field.storage.registrant.field_phone + - recurring_events_registration.registrant_type.default module: - recurring_events_registration -id: registrant.registrant.field_phone +id: registrant.default.field_phone field_name: field_phone entity_type: registrant -bundle: registrant +bundle: default label: Phone description: 'Enter your phone number.' required: false diff --git a/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml index 2705292b6db083e099c7c6857bc914913be7ee09..54f3f30364dd68323a0433ecf423c39803f632c8 100644 --- a/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml +++ b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant.config.yml @@ -4,7 +4,6 @@ date_format: 'F jS, Y h:iA' title: '[registrant:email]' email_notifications: true registration_notification_enabled: true -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 @@ -24,4 +23,4 @@ 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.' \ No newline at end of file +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.' diff --git a/modules/recurring_events_registration/config/install/recurring_events_registration.registrant_type.default.yml b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant_type.default.yml new file mode 100644 index 0000000000000000000000000000000000000000..cf5ee47afe712292a3b75db734171b56a4340fca --- /dev/null +++ b/modules/recurring_events_registration/config/install/recurring_events_registration.registrant_type.default.yml @@ -0,0 +1,6 @@ +langcode: en +status: true +dependencies: { } +label: Default +id: default +description: 'A default registrant type.' diff --git a/modules/recurring_events_registration/config/schema/registrant_type.schema.yml b/modules/recurring_events_registration/config/schema/registrant_type.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..cb4bb3f81360050d8bd5d6aa18ec406dfff7bd17 --- /dev/null +++ b/modules/recurring_events_registration/config/schema/registrant_type.schema.yml @@ -0,0 +1,15 @@ +recurring_events_registration.registrant_type.*: + type: config_entity + label: 'registrant type config' + mapping: + id: + type: string + label: 'ID' + label: + type: label + label: 'Label' + description: + type: string + label: 'Description' + uuid: + type: string diff --git a/modules/recurring_events_registration/recurring_events_registration.api.php b/modules/recurring_events_registration/recurring_events_registration.api.php index d928c67de1c4fdc54ab3d74de54a573467c0a74f..59df1093b034a21e5fd70551dba98a7815635c27 100644 --- a/modules/recurring_events_registration/recurring_events_registration.api.php +++ b/modules/recurring_events_registration/recurring_events_registration.api.php @@ -24,6 +24,7 @@ use Drupal\recurring_events_registration\Entity\Registrant; */ function hook_recurring_events_registration_first_waitlist_alter(Registrant $registrant) { // Find the ID of the registrant you wish to promote, then load the entity. + $id = 1234567; $new_registrant = \Drupal::entityTypeManager()->getStorage('registrant')->load($id); return $new_registrant; } diff --git a/modules/recurring_events_registration/recurring_events_registration.install b/modules/recurring_events_registration/recurring_events_registration.install index bb121908b0cb89d4787b31ca641e82de8f943f59..aab9be8a4f3d96cf543f48381a1034e3f0bc1447 100644 --- a/modules/recurring_events_registration/recurring_events_registration.install +++ b/modules/recurring_events_registration/recurring_events_registration.install @@ -26,11 +26,25 @@ function recurring_events_registration_install() { ->setRequired(FALSE) ->setDisplayOptions('form', [ 'type' => 'event_registration', - 'weight' => 4, + 'weight' => 10, ]); \Drupal::entityDefinitionUpdateManager() ->installFieldStorageDefinition('event_registration', 'eventseries', 'eventseries', $storage_definition); + + // When enabling registrations make sure we create all the registrant types + // to match the existing series and instance types. + foreach (\Drupal::entityTypeManager()->getStorage('eventseries_type')->loadMultiple() as $type) { + $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($type->id()); + if (empty($registrant_type)) { + $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->create([ + 'id' => $type->id(), + 'label' => $type->label(), + 'description' => $type->getDescription(), + ]); + $registrant_type->save(); + } + } } /** @@ -51,3 +65,16 @@ function recurring_events_registration_update_8001() { ->set('title', '[registrant:email]') ->save(TRUE); } + +/** + * Install the new type basefields for registrant. + */ +function recurring_events_registration_update_8002() { + $registrant_type = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Bundle')) + ->setDescription(t('The registrant type.')) + ->setSetting('target_type', 'registrant_type') + ->setReadOnly(TRUE); + + \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition('bundle', 'registrant', 'registrant', $registrant_type); +} diff --git a/modules/recurring_events_registration/recurring_events_registration.links.action.yml b/modules/recurring_events_registration/recurring_events_registration.links.action.yml index ca2e9c9451f4077768ca78776ed34fc0c0120e9d..f453125a4228686b99da3053a0e3d14a2f5fa821 100644 --- a/modules/recurring_events_registration/recurring_events_registration.links.action.yml +++ b/modules/recurring_events_registration/recurring_events_registration.links.action.yml @@ -3,4 +3,5 @@ entity.registrant.instance_contact: route_name: entity.registrant.instance_contact title: 'Contact Registrants' appears_on: - - entity.registrant.instance_listing \ No newline at end of file + - entity.registrant.instance_listing + - view.registrations.event_registrant_list diff --git a/modules/recurring_events_registration/recurring_events_registration.links.menu.yml b/modules/recurring_events_registration/recurring_events_registration.links.menu.yml index 5ba44cb2d70cfb5bf7d30e6b7e4183666a6c8644..7881024c5b7a99e2f11b4a1578a23dcb6f728d76 100644 --- a/modules/recurring_events_registration/recurring_events_registration.links.menu.yml +++ b/modules/recurring_events_registration/recurring_events_registration.links.menu.yml @@ -2,14 +2,22 @@ # Registrant menu items definition entity.registrant.collection: title: 'Registrants' - route_name: entity.registrant.collection + route_name: entity.registrant.admin_collection description: 'List Registrant entities' parent: events.admin.content weight: 100 registrant.admin.structure.settings: - title: 'Registrant settings' + title: 'Registrant Settings' description: 'Configure Registrant entities' route_name: registrant.settings parent: events.admin.overview weight: 12 + +# Registrant types admin page. +entity.registrant_type.collection: + title: 'Registrant Types' + description: 'Configure Registrant Types' + route_name: entity.registrant_type.collection + parent: events.admin.overview + weight: 13 diff --git a/modules/recurring_events_registration/recurring_events_registration.module b/modules/recurring_events_registration/recurring_events_registration.module index c2ae082d7c26343361965ee0b163f7a2ed152fce..3b489adc3e2157ac78f713fd672f13637a08c9d4 100644 --- a/modules/recurring_events_registration/recurring_events_registration.module +++ b/modules/recurring_events_registration/recurring_events_registration.module @@ -122,7 +122,7 @@ function recurring_events_registration_entity_base_field_info_alter(&$fields, En ->setTargetEntityTypeId($entity_type->id()) ->setDisplayOptions('form', [ 'type' => 'event_registration', - 'weight' => 4, + 'weight' => 10, ]); } } @@ -162,10 +162,6 @@ function template_preprocess_registrant(array &$variables) { * Implements hook_mail(). */ function recurring_events_registration_mail($key, &$message, $params) { - $options = [ - 'langcode' => $message['langcode'], - ]; - $service = \Drupal::service('recurring_events_registration.notification_service'); $service->setKey($key)->setEntity($params['registrant']); @@ -359,3 +355,77 @@ function recurring_events_registration_entity_operation(EntityInterface $entity) 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_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) { + $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) + ->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); + } +} diff --git a/modules/recurring_events_registration/recurring_events_registration.permissions.yml b/modules/recurring_events_registration/recurring_events_registration.permissions.yml index 315ed22b5254e78c347058de5ca5c8e0ff9159be..d86dd49dfba62d3a77cf63e91961e496d9557c75 100644 --- a/modules/recurring_events_registration/recurring_events_registration.permissions.yml +++ b/modules/recurring_events_registration/recurring_events_registration.permissions.yml @@ -32,10 +32,14 @@ resend registrant emails: contact registrants: title: 'Contact registrants' decription: 'Allow a role to set contact registrants' -administer registrant entities: +administer registrant entity: title: 'Administer registrant entities' description: 'Allow to access the administration form to configure registrant entities' restrict access: true +administer registrant types: + title: 'Administer registrant types' + description: 'Manage types of registrant' + restrict access: true # Registrant Administration. access registrant overview: diff --git a/modules/recurring_events_registration/recurring_events_registration.routing.yml b/modules/recurring_events_registration/recurring_events_registration.routing.yml index 6b310fc18ded43bdd606a165547bf4c0c1904010..c80f322d6c7ea2c8e06abc8e195ebeae9c07b097 100644 --- a/modules/recurring_events_registration/recurring_events_registration.routing.yml +++ b/modules/recurring_events_registration/recurring_events_registration.routing.yml @@ -15,6 +15,8 @@ entity.registrant.admin_collection: _title: 'Registrations' requirements: _permission: 'access registrant overview' + options: + _admin_route: TRUE # Registrant settings admin page. registrant.settings: @@ -27,7 +29,7 @@ registrant.settings: # Registrant view route. entity.registrant.canonical: - path: '/events/{eventinstance}/registration/{registrant}' + path: '/events/{eventinstance}/registrations/{registrant}' defaults: _entity_view: 'registrant' _title_callback: '\Drupal\recurring_events_registration\Controller\RegistrantController::getTitle' @@ -42,7 +44,7 @@ entity.registrant.canonical: # Registrant add route. entity.registrant.add_form: - path: '/events/{eventinstance}/registration/add' + path: '/events/{eventinstance}/registrations/add' defaults: # Calls the form.add controller, defined in the Registrant entity. _entity_form: registrant.add @@ -56,7 +58,7 @@ entity.registrant.add_form: # Registrant edit route. entity.registrant.edit_form: - path: '/events/{eventinstance}/registration/{registrant}/edit' + path: '/events/{eventinstance}/registrations/{registrant}/edit' defaults: # Calls the form.edit controller, defined in the Registrant entity. _entity_form: registrant.edit @@ -72,7 +74,7 @@ entity.registrant.edit_form: # Registrant delete route. entity.registrant.delete_form: - path: '/events/{eventinstance}/registration/{registrant}/delete' + path: '/events/{eventinstance}/registrations/{registrant}/delete' defaults: # Calls the form.delete controller, defined in the Registrant entity. _entity_form: registrant.delete @@ -88,7 +90,7 @@ entity.registrant.delete_form: # Resend Registrant email. entity.registrant.resend_form: - path: '/events/{eventinstance}/registration/{registrant}/resend' + path: '/events/{eventinstance}/registrations/{registrant}/resend' defaults: _form: \Drupal\recurring_events_registration\Form\RegistrantResendForm _title: 'Resend Registration Email' @@ -103,7 +105,7 @@ entity.registrant.resend_form: # Registrant anonymous edit route. entity.registrant.anon_edit_form: - path: '/events/{eventinstance}/registration/{registrant}/{uuid}/edit' + path: '/events/{eventinstance}/registrations/{registrant}/{uuid}/edit' defaults: # Calls the form.edit controller, defined in the Registrant entity. _entity_form: registrant.edit @@ -121,7 +123,7 @@ entity.registrant.anon_edit_form: # Registrant anonymous delete route. entity.registrant.anon_delete_form: - path: '/events/{eventinstance}/registration/{registrant}/{uuid}/delete' + path: '/events/{eventinstance}/registrations/{registrant}/{uuid}/delete' defaults: # Calls the form.delete controller, defined in the Registrant entity. _entity_form: registrant.delete @@ -177,4 +179,15 @@ entity.registrant.instance_contact: options: parameters: eventinstance: - type: entity:eventinstance \ No newline at end of file + type: entity:eventinstance + +# Registrant types route. +entity.registrant_type.collection: + path: '/admin/structure/events/registrant/types' + defaults: + _entity_list: 'registrant_type' + _title: 'Registrant types' + requirements: + _permission: 'administer registrant types' + options: + _admin_route: TRUE diff --git a/modules/recurring_events_registration/recurring_events_registration.services.yml b/modules/recurring_events_registration/recurring_events_registration.services.yml index 121738644419547c2e40dc94976ca1655d0190b3..08712920f23cabbe5511146279dafb96cccc7da8 100644 --- a/modules/recurring_events_registration/recurring_events_registration.services.yml +++ b/modules/recurring_events_registration/recurring_events_registration.services.yml @@ -5,4 +5,6 @@ services: recurring_events_registration.notification_service: class: Drupal\recurring_events_registration\NotificationService arguments: ['@string_translation', '@config.factory', '@logger.factory', '@messenger', '@token', '@module_handler', '@recurring_events_registration.creation_service'] - \ No newline at end of file + recurring_events_registration.access_handler: + class: Drupal\recurring_events_registration\AccessHandler + arguments: ['@string_translation', '@recurring_events_registration.creation_service', '@current_route_match', '@entity_type.manager'] diff --git a/modules/recurring_events_registration/recurring_events_registration.tokens.inc b/modules/recurring_events_registration/recurring_events_registration.tokens.inc index 85e0b02a5672697a8df1fbf394352dd08a59ca23..b59cbe898549d2b138672b33bc2876aa638c1114 100644 --- a/modules/recurring_events_registration/recurring_events_registration.tokens.inc +++ b/modules/recurring_events_registration/recurring_events_registration.tokens.inc @@ -70,7 +70,6 @@ function recurring_events_registration_tokens($type, $tokens, array $data, array $replacements = []; if ($type == 'eventinstance' && !empty($data['eventinstance'])) { $event_instance = $data['eventinstance']; - $event_series = $event_instance->getEventSeries(); $creation_service = \Drupal::service('recurring_events_registration.creation_service'); $creation_service->setEventInstance($event_instance); foreach ($tokens as $name => $original) { diff --git a/modules/recurring_events_registration/recurring_events_registration.views.inc b/modules/recurring_events_registration/recurring_events_registration.views.inc new file mode 100644 index 0000000000000000000000000000000000000000..092da90d3615bfe787c9311eb320693f133014cc --- /dev/null +++ b/modules/recurring_events_registration/recurring_events_registration.views.inc @@ -0,0 +1,14 @@ +<?php + +/** + * @file + * Views functionality for the recurring_events_registration module. + */ + +/** + * Implements hook_views_data_alter(). + */ +function recurring_events_registration_views_data_alter(array &$data) { + // Set the default field for a view based on registrants. + $data['registrant']['table']['base']['defaults']['field'] = 'email'; +} diff --git a/modules/recurring_events_registration/src/AccessHandler.php b/modules/recurring_events_registration/src/AccessHandler.php new file mode 100644 index 0000000000000000000000000000000000000000..0b4f3208c2380b3b1ade63cf20ddbe7977148e35 --- /dev/null +++ b/modules/recurring_events_registration/src/AccessHandler.php @@ -0,0 +1,127 @@ +<?php + +namespace Drupal\recurring_events_registration; + +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\Core\Session\AccountInterface; +use Symfony\Component\Routing\Route; +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Routing\CurrentRouteMatch; +use Drupal\recurring_events\EventInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; + +/** + * AccessHandler class definition. + */ +class AccessHandler { + /** + * The translation interface. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface + */ + private $translation; + + /** + * The registration creation service. + * + * @var \Drupal\recurring_events_registration\RegistrationCreationService + */ + protected $creationService; + + /** + * The current route match. + * + * @var \Drupal\Core\Routing\CurrentRouteMatch + */ + protected $routeMatch; + + /** + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Class constructor. + * + * @param \Drupal\Core\StringTranslation\TranslationInterface $translation + * The translation interface. + * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service + * The registration creation service. + * @param Drupal\Core\Routing\CurrentRouteMatch $route_match + * The current route match. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager service. + */ + public function __construct(TranslationInterface $translation, RegistrationCreationService $creation_service, CurrentRouteMatch $route_match, EntityTypeManagerInterface $entity_type_manager) { + $this->translation = $translation; + $this->creationService = $creation_service; + $this->routeMatch = $route_match; + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('string_translation'), + $container->get('recurring_events_registration.creation_service'), + $container->get('current_route_match'), + $container->get('entity_type.manager') + ); + } + + /** + * Access control based on whether event has registration. + * + * @return bool + * TRUE if event has registration, FALSE otherwise. + */ + public function eventHasRegistration() { + $has_registration = FALSE; + $event_instance = $this->routeMatch->getParameter('eventinstance'); + if (!empty($event_instance)) { + + if (!$event_instance instanceof EventInterface && is_numeric($event_instance)) { + $event_instance = $this->entityTypeManager->getStorage('eventinstance')->load($event_instance); + } + + if ($event_instance instanceof EventInterface) { + $this->creationService->setEventInstance($event_instance); + $has_registration = $this->creationService->hasRegistration(); + } + } + return $has_registration; + } + + /** + * Access control based on whether the account has the right permission. + * + * @param Drupal\Core\Session\AccountInterface $account + * The current route. + * + * @return bool + * TRUE if user has access, FALSE otherwise. + */ + public function userHasPermission(AccountInterface $account) { + return $account->hasPermission('access registrant overview'); + } + + /** + * Access control for the Event Registration List view. + */ + public function eventRegistrationListAccess(AccountInterface $account, Route $route) { + if (!$this->eventHasRegistration()) { + return AccessResult::forbidden(); + } + + if (!$this->userHasPermission($account)) { + return AccessResult::forbidden(); + } + return AccessResult::allowed(); + } + +} diff --git a/modules/recurring_events_registration/src/Controller/RegistrantController.php b/modules/recurring_events_registration/src/Controller/RegistrantController.php index 8e2d9651cf563edd93e7f35c4b3c84b0b8027dc8..63bd10570cbf4b422324aec6f3243ee98f134b88 100644 --- a/modules/recurring_events_registration/src/Controller/RegistrantController.php +++ b/modules/recurring_events_registration/src/Controller/RegistrantController.php @@ -10,7 +10,7 @@ use Drupal\recurring_events_registration\Entity\RegistrantInterface; use Drupal\Core\Access\AccessResult; use Drupal\recurring_events\Entity\EventInstance; use Drupal\Core\Session\AccountProxyInterface; -use Drupal\user\Entity\User; +use Drupal\Core\Entity\EntityTypeManagerInterface; /** * The RegistrantController class. @@ -31,6 +31,13 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI */ protected $currentUser; + /** + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + /** * Constructs a RegistrantController object. * @@ -38,10 +45,13 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI * The renderer service. * @param \Drupal\Core\Session\AccountProxyInterface $current_user * The current user. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager service. */ - public function __construct(RendererInterface $renderer, AccountProxyInterface $current_user) { + public function __construct(RendererInterface $renderer, AccountProxyInterface $current_user, EntityTypeManagerInterface $entity_type_manager) { $this->renderer = $renderer; $this->currentUser = $current_user; + $this->entityTypeManager = $entity_type_manager; } /** @@ -50,7 +60,8 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI public static function create(ContainerInterface $container) { return new static( $container->get('renderer'), - $container->get('current_user') + $container->get('current_user'), + $container->get('entity_type.manager') ); } @@ -88,7 +99,7 @@ class RegistrantController extends ControllerBase implements ContainerInjectionI */ public function canContactRegistrants(EventInstance $eventinstance) { if (!empty($eventinstance)) { - $account = User::load($this->currentUser->id()); + $account = $this->entityTypeManager->getStorage('user')->load($this->currentUser->id()); return AccessResult::allowedIfHasPermission($account, 'contact registrants'); } return AccessResult::forbidden(); diff --git a/modules/recurring_events_registration/src/Entity/Registrant.php b/modules/recurring_events_registration/src/Entity/Registrant.php index 38319be24449d88df99e4cf5cb8d805c9c41b121..37a2293317986a99c4189ee8044be46df8d3f280 100644 --- a/modules/recurring_events_registration/src/Entity/Registrant.php +++ b/modules/recurring_events_registration/src/Entity/Registrant.php @@ -20,6 +20,7 @@ use Drupal\recurring_events_registration\Plugin\Field\ComputedRegistrantTitleFie * @ContentEntityType( * id = "registrant", * label = @Translation("Registrant"), + * bundle_label = @Translation("Registrant type"), * handlers = { * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", * "list_builder" = "Drupal\recurring_events_registration\RegistrantListBuilder", @@ -44,15 +45,17 @@ use Drupal\recurring_events_registration\Plugin\Field\ComputedRegistrantTitleFie * "uuid" = "uuid", * "uid" = "user_id", * "label" = "title", + * "bundle" = "bundle", * }, * links = { - * "canonical" = "/events/{eventinstance}/registrant/{registrant}", - * "edit-form" = "/events/{eventinstance}/registrant/{registrant}/edit", - * "delete-form" = "/events/{eventinstance}/registrant/{registrant}/delete", - * "anon-edit-form" = "/events/{eventinstance}/registrant/{registrant}/{uuid}/edit", - * "anon-delete-form" = "/events/{eventinstance}/registrant/{registrant}/{uuid}/delete" + * "canonical" = "/events/{eventinstance}/registrations//{registrant}", + * "edit-form" = "/events/{eventinstance}/registrations//{registrant}/edit", + * "delete-form" = "/events/{eventinstance}/registrations/{registrant}/delete", + * "anon-edit-form" = "/events/{eventinstance}/registrations/{registrant}/{uuid}/edit", + * "anon-delete-form" = "/events/{eventinstance}/registrations/{registrant}/{uuid}/delete" * }, - * field_ui_base_route = "registrant.settings" + * bundle_entity_type = "registrant_type", + * field_ui_base_route = "entity.registrant_type.edit_form" * ) */ class Registrant extends ContentEntityBase implements RegistrantInterface { @@ -66,6 +69,7 @@ class Registrant extends ContentEntityBase implements RegistrantInterface { parent::preCreate($storage_controller, $values); $values += [ 'user_id' => \Drupal::currentUser()->id(), + 'bundle' => !empty(\Drupal::request()->attributes->get('eventinstance')) ? \Drupal::request()->attributes->get('eventinstance')->getType() : 'default', ]; } @@ -83,6 +87,13 @@ class Registrant extends ContentEntityBase implements RegistrantInterface { } } + /** + * {@inheritdoc} + */ + public function getBundle() { + return $this->bundle(); + } + /** * {@inheritdoc} */ @@ -152,6 +163,7 @@ class Registrant extends ContentEntityBase implements RegistrantInterface { 'size' => '60', 'autocomplete_type' => 'tags', 'placeholder' => '', + 'match_limit' => 10, ], ]) ->setDisplayConfigurable('form', TRUE) @@ -176,6 +188,12 @@ class Registrant extends ContentEntityBase implements RegistrantInterface { ->setDescription(t('The UUID of the registrant entity.')) ->setReadOnly(TRUE); + $fields['bundle'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Bundle')) + ->setDescription(t('The registrant type.')) + ->setSetting('target_type', 'registrant_type') + ->setReadOnly(TRUE); + $fields['eventseries_id'] = BaseFieldDefinition::create('entity_reference') ->setLabel(t('Event Series ID')) ->setDescription(t('The ID of the eventseries entity.')) diff --git a/modules/recurring_events_registration/src/Entity/RegistrantType.php b/modules/recurring_events_registration/src/Entity/RegistrantType.php new file mode 100644 index 0000000000000000000000000000000000000000..7a761d81f386843c8ab8d53def9c0292145d69ec --- /dev/null +++ b/modules/recurring_events_registration/src/Entity/RegistrantType.php @@ -0,0 +1,80 @@ +<?php + +namespace Drupal\recurring_events_registration\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityBundleBase; + +/** + * Defines the registrant type entity. + * + * @ConfigEntityType( + * id = "registrant_type", + * label = @Translation("registrant type"), + * handlers = { + * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", + * "list_builder" = "Drupal\recurring_events_registration\RegistrantTypeListBuilder", + * "form" = { + * "edit" = "Drupal\recurring_events_registration\Form\RegistrantTypeForm", + * }, + * "route_provider" = { + * "html" = "Drupal\recurring_events_registration\RegistrantTypeHtmlRouteProvider", + * }, + * }, + * config_prefix = "registrant_type", + * bundle_of = "registrant", + * admin_permission = "administer registrant entity", + * entity_keys = { + * "id" = "id", + * "label" = "label", + * "uuid" = "uuid" + * }, + * links = { + * "canonical" = "/admin/structure/events/registrants/types/registrant_type/{registrant_type}", + * "edit-form" = "/admin/structure/events/registrants/types/registrant_type/{registrant_type}/edit", + * "collection" = "/admin/structure/events/registrants/types/registrant_type" + * }, + * config_export = { + * "label", + * "id", + * "description", + * } + * ) + */ +class RegistrantType extends ConfigEntityBundleBase implements RegistrantTypeInterface { + + /** + * The registrant type ID. + * + * @var string + */ + protected $id; + + /** + * The registrant type label. + * + * @var string + */ + protected $label; + + /** + * A brief description of this Registrant type. + * + * @var string + */ + protected $description; + + /** + * {@inheritdoc} + */ + public function id() { + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->description; + } + +} diff --git a/modules/recurring_events_registration/src/Entity/RegistrantTypeInterface.php b/modules/recurring_events_registration/src/Entity/RegistrantTypeInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..661a38a3bca275350f079e83ce2fc0ebe61907c9 --- /dev/null +++ b/modules/recurring_events_registration/src/Entity/RegistrantTypeInterface.php @@ -0,0 +1,20 @@ +<?php + +namespace Drupal\recurring_events_registration\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityInterface; + +/** + * Provides an interface for defining Registrant type entities. + */ +interface RegistrantTypeInterface extends ConfigEntityInterface { + + /** + * Gets the description. + * + * @return string + * The description of this Registrant type. + */ + public function getDescription(); + +} diff --git a/modules/recurring_events_registration/src/Form/ContactForm.php b/modules/recurring_events_registration/src/Form/ContactForm.php index 725380ba9c25ab4994355a8ccf8fdede2dc6c728..047adabc1621305552133349df01717a60471db2 100644 --- a/modules/recurring_events_registration/src/Form/ContactForm.php +++ b/modules/recurring_events_registration/src/Form/ContactForm.php @@ -11,9 +11,9 @@ use Drupal\recurring_events_registration\NotificationService; use Drupal\Core\Messenger\Messenger; use Drupal\Core\Mail\MailManager; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Drupal\recurring_events\Entity\EventInstance; use Drupal\Core\Link; use Drupal\Core\Url; +use Drupal\Core\Language\LanguageManagerInterface; /** * Registrant contact form. @@ -62,6 +62,13 @@ class ContactForm extends FormBase { */ protected $eventInstance; + /** + * The language manager service. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + /** * Constructs a ContactForm object. * @@ -75,13 +82,16 @@ class ContactForm extends FormBase { * The messenger service. * @param \Drupal\Core\Mail\MailManager $mail * The mail manager service. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager service. */ - public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail) { + public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail, LanguageManagerInterface $language_manager) { $this->request = $request; $this->creationService = $creation_service; $this->notificationService = $notification_service; $this->messenger = $messenger; $this->mail = $mail; + $this->languageManager = $language_manager; $request = $this->request->getCurrentRequest(); $params = $request->attributes->all(); @@ -104,7 +114,8 @@ class ContactForm extends FormBase { $container->get('recurring_events_registration.creation_service'), $container->get('recurring_events_registration.notification_service'), $container->get('messenger'), - $container->get('plugin.manager.mail') + $container->get('plugin.manager.mail'), + $container->get('language_manager') ); } @@ -208,7 +219,7 @@ class ContactForm extends FormBase { $params['registrant'] = $registrant; $to = $registrant->mail->value; - $this->mail->mail('recurring_events_registration', 'custom', $to, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params); + $this->mail->mail('recurring_events_registration', 'custom', $to, $this->languageManager->getDefaultLanguage()->getId(), $params); if ($registrant->getWaitlist() == '1') { $wait_count++; diff --git a/modules/recurring_events_registration/src/Form/RegistrantForm.php b/modules/recurring_events_registration/src/Form/RegistrantForm.php index 18569fcdf3d5dc598ef6c57b9311238f296b9adc..274c158c3a79ad226499eaa69afb0e814634d441 100644 --- a/modules/recurring_events_registration/src/Form/RegistrantForm.php +++ b/modules/recurring_events_registration/src/Form/RegistrantForm.php @@ -5,7 +5,7 @@ namespace Drupal\recurring_events_registration\Form; use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Messenger\Messenger; use Drupal\recurring_events_registration\RegistrationCreationService; use Drupal\Core\Session\AccountProxyInterface; @@ -75,7 +75,7 @@ class RegistrantForm extends ContentEntityForm { */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), + $container->get('entity.repository'), $container->get('messenger'), $container->get('recurring_events_registration.creation_service'), $container->get('current_user'), @@ -89,8 +89,8 @@ class RegistrantForm extends ContentEntityForm { /** * Construct an RegistrantForm. * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager service. + * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository + * The entity repository service. * @param \Drupal\Core\Messenger\Messenger $messenger * The messenger service. * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service @@ -107,7 +107,7 @@ class RegistrantForm extends ContentEntityForm { * The entity type manager service. */ public function __construct( - EntityManagerInterface $entity_manager, + EntityRepositoryInterface $entity_repository, Messenger $messenger, RegistrationCreationService $creation_service, AccountProxyInterface $current_user, @@ -122,7 +122,7 @@ class RegistrantForm extends ContentEntityForm { $this->fieldManager = $field_manager; $this->routeMatch = $route_match; $this->entityTypeManager = $entity_type_manager; - parent::__construct($entity_manager); + parent::__construct($entity_repository); } /** @@ -241,7 +241,9 @@ class RegistrantForm extends ContentEntityForm { $form['availability'] = [ '#type' => 'markup', '#prefix' => '<span class="registration-availability">', - '#markup' => $this->t('Spaces Available: @availability', ['@availability' => $availability]), + '#markup' => $this->t('Spaces Available: @availability', [ + '@availability' => ($availability == -1) ? $this->t('Unlimited') : $availability, + ]), '#suffix' => '</span>', '#weight' => -99, ]; @@ -295,12 +297,11 @@ class RegistrantForm extends ContentEntityForm { * The form state interface. */ protected function hideFormFields(array &$form, FormStateInterface $form_state) { - $form_fields = $this->fieldManager->getFieldDefinitions('registrant', 'registrant'); + $form_fields = $this->fieldManager->getFieldDefinitions('registrant', $this->entity->getBundle()); $availability = $this->creationService->retrieveAvailability(); $waitlist = $this->creationService->hasWaitlist(); $registration_open = $this->creationService->registrationIsOpen(); - $reg_type = $this->creationService->getRegistrationType(); // Prevent the form being displayed if registration is closed, or there are // no spaces left, and no waitlist. @@ -351,7 +352,6 @@ class RegistrantForm extends ContentEntityForm { $availability = $this->creationService->retrieveAvailability(); $waitlist = $this->creationService->hasWaitlist(); $registration_open = $this->creationService->registrationIsOpen(); - $reg_type = $this->creationService->getRegistrationType(); $add_to_waitlist = $form_state->getValue('add_to_waitlist'); @@ -381,8 +381,6 @@ class RegistrantForm extends ContentEntityForm { * {@inheritdoc} */ public function save(array $form, FormStateInterface $form_state) { - $entity = $this->entity; - $event_series = $form_state->getTemporaryValue('series'); // We need to grab a fresh copy of the series to check for updates. $event_series = $this->entityTypeManager->getStorage('eventseries')->load($event_series->id()); diff --git a/modules/recurring_events_registration/src/Form/RegistrantResendForm.php b/modules/recurring_events_registration/src/Form/RegistrantResendForm.php index 734707518a0b01a29a5be37242ede803231d5d82..ddd4a1885f7fe2fa6ab4013bad1934a029d1bf31 100644 --- a/modules/recurring_events_registration/src/Form/RegistrantResendForm.php +++ b/modules/recurring_events_registration/src/Form/RegistrantResendForm.php @@ -11,10 +11,10 @@ use Drupal\recurring_events_registration\NotificationService; use Drupal\Core\Messenger\Messenger; use Drupal\Core\Mail\MailManager; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Drupal\recurring_events\Entity\EventInstance; use Drupal\Core\Render\Renderer; use Drupal\Core\Link; use Drupal\Core\Url; +use Drupal\Core\Language\LanguageManagerInterface; /** * Provides a form for resending Registrant registration emails. @@ -79,6 +79,13 @@ class RegistrantResendForm extends FormBase { */ protected $registrant; + /** + * The language manager service. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + /** * Constructs a ContactForm object. * @@ -94,14 +101,17 @@ class RegistrantResendForm extends FormBase { * The mail manager service. * @param \Drupal\Core\Render\Renderer $renderer * The renderer service. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager service. */ - public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail, Renderer $renderer) { + public function __construct(RequestStack $request, RegistrationCreationService $creation_service, NotificationService $notification_service, Messenger $messenger, MailManager $mail, Renderer $renderer, LanguageManagerInterface $language_manager) { $this->request = $request; $this->creationService = $creation_service; $this->notificationService = $notification_service; $this->messenger = $messenger; $this->mail = $mail; $this->renderer = $renderer; + $this->languageManager = $language_manager; $request = $this->request->getCurrentRequest(); $params = $request->attributes->all(); @@ -131,7 +141,8 @@ class RegistrantResendForm extends FormBase { $container->get('recurring_events_registration.notification_service'), $container->get('messenger'), $container->get('plugin.manager.mail'), - $container->get('renderer') + $container->get('renderer'), + $container->get('language_manager') ); } @@ -222,7 +233,7 @@ class RegistrantResendForm extends FormBase { ]; $to = $this->registrant->mail->value; - $this->mail->mail('recurring_events_registration', 'custom', $to, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params); + $this->mail->mail('recurring_events_registration', 'custom', $to, $this->languageManager->getDefaultLanguage()->getId(), $params); $this->messenger->addMessage($this->t('Registrant email successfully resent.')); } diff --git a/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php b/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php index a651023b869bc64b03100c50742e3d1bc1ed9e1e..5add1a1a3cb849b254fd96b652f2dbf5a4985044 100644 --- a/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php +++ b/modules/recurring_events_registration/src/Form/RegistrantSettingsForm.php @@ -9,6 +9,7 @@ use Drupal\Core\Url; use Drupal\Core\Link; use Drupal\recurring_events_registration\NotificationService; use Drupal\recurring_events_registration\RegistrationCreationService; +use Drupal\Core\Extension\ModuleHandler; /** * Class RegistrantSettingsForm. @@ -31,6 +32,13 @@ class RegistrantSettingsForm extends ConfigFormBase { */ protected $creationService; + /** + * The module handler service. + * + * @var \Drupal\Core\Extension\ModuleHandler + */ + protected $moduleHandler; + /** * Constructs a RegistrantSettingsForm object. * @@ -38,10 +46,13 @@ class RegistrantSettingsForm extends ConfigFormBase { * The registration notification service. * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service * The registration creation service. + * @param \Drupal\Core\Extension\ModuleHandler $module_handler + * The module handler service. */ - public function __construct(NotificationService $notification_service, RegistrationCreationService $creation_service) { + public function __construct(NotificationService $notification_service, RegistrationCreationService $creation_service, ModuleHandler $module_handler) { $this->notificationService = $notification_service; $this->creationService = $creation_service; + $this->moduleHandler = $module_handler; } /** @@ -50,7 +61,8 @@ class RegistrantSettingsForm extends ConfigFormBase { public static function create(ContainerInterface $container) { return new static( $container->get('recurring_events_registration.notification_service'), - $container->get('recurring_events_registration.creation_service') + $container->get('recurring_events_registration.creation_service'), + $container->get('module_handler') ); } @@ -88,7 +100,7 @@ class RegistrantSettingsForm extends ConfigFormBase { ->set('email_notifications', $form_state->getValue('email_notifications')); $notification_types = []; - \Drupal::moduleHandler()->alter('recurring_events_registration_notification_types', $notification_types); + $this->moduleHandler->alter('recurring_events_registration_notification_types', $notification_types); foreach ($notification_types as $type => $notification) { $config @@ -194,7 +206,7 @@ class RegistrantSettingsForm extends ConfigFormBase { $tokens = $this->notificationService->getAvailableTokens(); $notification_types = []; - \Drupal::moduleHandler()->alter('recurring_events_registration_notification_types', $notification_types); + $this->moduleHandler->alter('recurring_events_registration_notification_types', $notification_types); foreach ($notification_types as $type => $notification) { $form['notifications'][$type] = [ diff --git a/modules/recurring_events_registration/src/Form/RegistrantTypeForm.php b/modules/recurring_events_registration/src/Form/RegistrantTypeForm.php new file mode 100644 index 0000000000000000000000000000000000000000..7d14bd84824627f4a2163d377798435a8ab964eb --- /dev/null +++ b/modules/recurring_events_registration/src/Form/RegistrantTypeForm.php @@ -0,0 +1,97 @@ +<?php + +namespace Drupal\recurring_events_registration\Form; + +use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\Messenger; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Class RegistrantTypeForm. + */ +class RegistrantTypeForm extends EntityForm { + + /** + * The messenger service. + * + * @var \Drupal\Core\Messenger\Messenger + */ + protected $messenger; + + /** + * Constructs a RegistrantTypeForm object. + * + * @param \Drupal\Core\Messenger\Messenger $messenger + * The messenger service. + */ + public function __construct(Messenger $messenger) { + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('messenger') + ); + } + + /** + * {@inheritdoc} + */ + public function form(array $form, FormStateInterface $form_state) { + $form = parent::form($form, $form_state); + + $registrant_type = $this->entity; + $form['label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $registrant_type->label(), + '#description' => $this->t("Label for the registrant type."), + '#required' => TRUE, + ]; + + $form['id'] = [ + '#type' => 'machine_name', + '#default_value' => $registrant_type->id(), + '#machine_name' => [ + 'exists' => '\Drupal\recurring_events_registration\Entity\RegistrantType::load', + ], + '#disabled' => !$registrant_type->isNew(), + ]; + + $form['description'] = [ + '#title' => $this->t('Description'), + '#type' => 'textarea', + '#default_value' => $registrant_type->getDescription(), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function save(array $form, FormStateInterface $form_state) { + $registrant_type = $this->entity; + $status = $registrant_type->save(); + + switch ($status) { + case SAVED_NEW: + $this->messenger->addMessage($this->t('Created the %label registrant type.', [ + '%label' => $registrant_type->label(), + ])); + break; + + default: + $this->messenger->addMessage($this->t('Saved the %label registrant type.', [ + '%label' => $registrant_type->label(), + ])); + } + $form_state->setRedirectUrl($registrant_type->toUrl('collection')); + } + +} diff --git a/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php b/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php index 183e036332f57115e317775b4ddc73b5b1a9c5e8..15fcb2540f23bd8b9eb343f7f3f73282bcbd1c12 100644 --- a/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php +++ b/modules/recurring_events_registration/src/Plugin/Field/FieldWidget/EventRegistrationWidget.php @@ -5,6 +5,7 @@ namespace Drupal\recurring_events_registration\Plugin\Field\FieldWidget; use Drupal\Core\Field\FieldItemListInterface; use Drupal\datetime_range\Plugin\Field\FieldWidget\DateRangeDefaultWidget; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'event registration' widget. @@ -19,6 +20,8 @@ use Drupal\Core\Form\FormStateInterface; */ class EventRegistrationWidget extends DateRangeDefaultWidget { + use StringTranslationTrait; + /** * {@inheritdoc} */ @@ -29,21 +32,21 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { $element['registration'] = [ '#type' => 'checkbox', - '#title' => t('Enable Registration'), - '#description' => t('Select this box to enable registrations for this event. By doing so you will be able to specify the capacity of the event, and if applicable enable a waitlist.'), + '#title' => $this->t('Enable Registration'), + '#description' => $this->t('Select this box to enable registrations for this event. By doing so you will be able to specify the capacity of the event, and if applicable enable a waitlist.'), '#weight' => 0, '#default_value' => $items[$delta]->registration ?: '', ]; $element['registration_type'] = [ '#type' => 'radios', - '#title' => t('Registration Type'), - '#description' => t('Select whether registrations are for the entire series, or for individual instances.'), + '#title' => $this->t('Registration Type'), + '#description' => $this->t('Select whether registrations are for the entire series, or for individual instances.'), '#weight' => 1, '#default_value' => $items[$delta]->registration_type ?: 'instance', '#options' => [ - 'instance' => t('Individual Event Registration'), - 'series' => t('Entire Series Registration'), + 'instance' => $this->t('Individual Event Registration'), + 'series' => $this->t('Entire Series Registration'), ], '#states' => [ 'visible' => [ @@ -54,13 +57,13 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { $element['registration_dates'] = [ '#type' => 'radios', - '#title' => t('Registration Dates'), - '#description' => t('Choose between open or scheduled registration.'), + '#title' => $this->t('Registration Dates'), + '#description' => $this->t('Choose between open or scheduled registration.'), '#weight' => 2, '#default_value' => $items[$delta]->registration_dates ?: 'open', '#options' => [ - 'open' => t('Open Registration'), - 'scheduled' => t('Scheduled Registration'), + 'open' => $this->t('Open Registration'), + 'scheduled' => $this->t('Scheduled Registration'), ], '#states' => [ 'visible' => [ @@ -71,7 +74,7 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { $element['series_registration'] = [ '#type' => 'fieldset', - '#title' => t('Series Registration'), + '#title' => $this->t('Series Registration'), '#weight' => 3, '#states' => [ 'visible' => [ @@ -87,12 +90,12 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { unset($element['value']); unset($element['end_value']); - $element['series_registration']['value']['#title'] = t('Registration Opens'); - $element['series_registration']['end_value']['#title'] = t('Registration Closes'); + $element['series_registration']['value']['#title'] = $this->t('Registration Opens'); + $element['series_registration']['end_value']['#title'] = $this->t('Registration Closes'); $element['instance_registration'] = [ '#type' => 'fieldset', - '#title' => t('Instance Registration'), + '#title' => $this->t('Instance Registration'), '#weight' => 3, '#states' => [ 'visible' => [ @@ -105,8 +108,8 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { $element['instance_registration']['time_amount'] = [ '#type' => 'number', - '#title' => t('Registration Time Amount'), - '#description' => t('Enter the amount of time in days or hours before the event(s) start time(s) that registration should open.'), + '#title' => $this->t('Registration Time Amount'), + '#description' => $this->t('Enter the amount of time in days or hours before the event(s) start time(s) that registration should open.'), '#weight' => 0, '#default_value' => $items[$delta]->time_amount ?: '', '#min' => 0, @@ -114,20 +117,20 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { $element['instance_registration']['time_type'] = [ '#type' => 'select', - '#title' => t('Registration Time Type'), - '#description' => t("Select either Days or Hours to choose how long before which an event's registration will open."), + '#title' => $this->t('Registration Time Type'), + '#description' => $this->t("Select either Days or Hours to choose how long before which an event's registration will open."), '#weight' => 1, '#default_value' => $items[$delta]->time_type ?: '', '#options' => [ - 'days' => t('Days'), - 'hours' => t('Hours'), + 'days' => $this->t('Days'), + 'hours' => $this->t('Hours'), ], ]; $element['capacity'] = [ '#type' => 'number', - '#title' => t('Total Number of Spaces Available'), - '#description' => t('Maximum number of attendees available for each series, or individual event.'), + '#title' => $this->t('Total Number of Spaces Available'), + '#description' => $this->t('Maximum number of attendees available for each series, or individual event. Leave blank for unlimited.'), '#weight' => 4, '#default_value' => $items[$delta]->capacity ?: '', '#min' => 0, @@ -140,8 +143,8 @@ class EventRegistrationWidget extends DateRangeDefaultWidget { $element['waitlist'] = [ '#type' => 'checkbox', - '#title' => t('Enable Waiting List'), - '#description' => t('Enable a waiting list if the number of registrations reaches capacity.'), + '#title' => $this->t('Enable Waiting List'), + '#description' => $this->t('Enable a waiting list if the number of registrations reaches capacity.'), '#weight' => 5, '#default_value' => $items[$delta]->waitlist ?: '', '#states' => [ diff --git a/modules/recurring_events_registration/src/Plugin/views/access/EventRegistrationListAccess.php b/modules/recurring_events_registration/src/Plugin/views/access/EventRegistrationListAccess.php new file mode 100644 index 0000000000000000000000000000000000000000..2bfc1d48a0db1f8a0a766498a30bd745717c4ca7 --- /dev/null +++ b/modules/recurring_events_registration/src/Plugin/views/access/EventRegistrationListAccess.php @@ -0,0 +1,81 @@ +<?php + +namespace Drupal\recurring_events_registration\Plugin\views\access; + +use Drupal\views\Plugin\views\access\AccessPluginBase; +use Drupal\Core\Session\AccountInterface; +use Symfony\Component\Routing\Route; +use Drupal\recurring_events_registration\AccessHandler; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Custom access plugin for Event Registration views. + * + * @ingroup views_access_plugins + * + * @ViewsAccess( + * id = "event_registration_list_access", + * title = @Translation("View Event Registration List"), + * help = @Translation("Access will be granted depending on the registration configuration of an event.") + * ) + */ +class EventRegistrationListAccess extends AccessPluginBase { + + /** + * The access handler. + * + * @var \Drupal\recurring_events_registration\AccessHandler + */ + protected $accessHandler; + + /** + * Constructs an EventRegistrationListAccess object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param Drupal\recurring_events_registration\AccessHandler $access_handler + * The access handler. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, AccessHandler $access_handler) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->accessHandler = $access_handler; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('recurring_events_registration.access_handler') + ); + } + + /** + * {@inheritdoc} + */ + public function summaryTitle() { + return $this->t('Event Registration Access'); + } + + /** + * {@inheritdoc} + */ + public function access(AccountInterface $account) { + return $this->accessHandler->eventHasRegistration() && $this->accessHandler->userHasPermission($account); + } + + /** + * {@inheritdoc} + */ + public function alterRouteDefinition(Route $route) { + $route->setRequirement('_custom_access', 'recurring_events_registration.access_handler::eventRegistrationListAccess'); + } + +} diff --git a/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php b/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php index f1d814a684a193e2f10624fef4616cc2fb08d50b..3d58f29c721f7c5bcc8d06ad4253c2f3601bef8f 100644 --- a/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php +++ b/modules/recurring_events_registration/src/RegistrantAccessControlHandler.php @@ -10,6 +10,7 @@ use Drupal\Component\Uuid\Uuid; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityHandlerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; /** * Access controller for the Registrant entity. @@ -25,6 +26,13 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen */ protected $creationService; + /** + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + /** * RegistrantAccessControlHandler constructor. * @@ -32,10 +40,13 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen * The entity type. * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service * The creation service. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager service. */ - public function __construct(EntityTypeInterface $entity_type, RegistrationCreationService $creation_service) { + public function __construct(EntityTypeInterface $entity_type, RegistrationCreationService $creation_service, EntityTypeManagerInterface $entity_type_manager) { parent::__construct($entity_type); $this->creationService = $creation_service; + $this->entityTypeManager = $entity_type_manager; } /** @@ -44,7 +55,8 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { return new static( $entity_type, - $container->get('recurring_events_registration.creation_service') + $container->get('recurring_events_registration.creation_service'), + $container->get('entity_type.manager') ); } @@ -87,6 +99,9 @@ class RegistrantAccessControlHandler extends EntityAccessControlHandler implemen protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { $params = \Drupal::request()->attributes->all(); if (!empty($params['eventinstance'])) { + if (is_string($params['eventinstance']) || is_numeric($params['eventinstance'])) { + $params['eventinstance'] = $this->entityTypeManager->getStorage('eventinstance')->load($params['eventinstance']); + } $this->creationService->setEventInstance($params['eventinstance']); if ($this->creationService->hasRegistration()) { return AccessResult::allowedIfHasPermission($account, 'add registrant entities'); diff --git a/modules/recurring_events_registration/src/RegistrantListBuilder.php b/modules/recurring_events_registration/src/RegistrantListBuilder.php index 7d12a9c50f1044d62565f499c53a982350715cc1..5d0fdb4f71476b97b3ea713f7c68ecf6a44e00eb 100644 --- a/modules/recurring_events_registration/src/RegistrantListBuilder.php +++ b/modules/recurring_events_registration/src/RegistrantListBuilder.php @@ -113,7 +113,7 @@ class RegistrantListBuilder extends EntityListBuilder { $row['id'] = $entity->id(); $row['series'] = $series->toLink($series->title->value); - $timezone = new \DateTimeZone(drupal_get_user_timezone()); + $timezone = new \DateTimeZone(date_default_timezone_get()); $date = $instance->date->start_date; $date->setTimezone($timezone); $row['instance'] = $instance->toLink($date->format($this->config->get('recurring_events_registration.registrant.config')->get('date_format'))); diff --git a/modules/recurring_events_registration/src/RegistrantTypeHtmlRouteProvider.php b/modules/recurring_events_registration/src/RegistrantTypeHtmlRouteProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..899a5c071b4dfb1b21eeb3be5d8eb17f1aedae55 --- /dev/null +++ b/modules/recurring_events_registration/src/RegistrantTypeHtmlRouteProvider.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\recurring_events_registration; + +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider; + +/** + * Provides routes for Registrant type entities. + * + * @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider + * @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider + */ +class RegistrantTypeHtmlRouteProvider extends AdminHtmlRouteProvider { + + /** + * {@inheritdoc} + */ + public function getRoutes(EntityTypeInterface $entity_type) { + $collection = parent::getRoutes($entity_type); + return $collection; + } + +} diff --git a/modules/recurring_events_registration/src/RegistrantTypeListBuilder.php b/modules/recurring_events_registration/src/RegistrantTypeListBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..fb31d343f39abedddaa95b44c7044a15f02c2017 --- /dev/null +++ b/modules/recurring_events_registration/src/RegistrantTypeListBuilder.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\recurring_events_registration; + +use Drupal\Core\Config\Entity\ConfigEntityListBuilder; +use Drupal\Core\Entity\EntityInterface; + +/** + * Provides a listing of Registrant type entities. + */ +class RegistrantTypeListBuilder extends ConfigEntityListBuilder { + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Registrant type'); + $header['id'] = $this->t('Machine name'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOperations(EntityInterface $entity) { + $operations = parent::getDefaultOperations($entity); + // Place the edit operation after the operations added by field_ui.module + // which have the weights 15, 20, 25. + if (isset($operations['edit'])) { + $operations['edit']['weight'] = 30; + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $entity->label(); + $row['id'] = $entity->id(); + // You probably want a few more properties here... + return $row + parent::buildRow($entity); + } + +} diff --git a/modules/recurring_events_registration/src/RegistrationCreationService.php b/modules/recurring_events_registration/src/RegistrationCreationService.php index 6451c48830ff249c72f42e2b09bbafabc56b920a..c2f3e017284f756658b9d82018058141b57271f8 100644 --- a/modules/recurring_events_registration/src/RegistrationCreationService.php +++ b/modules/recurring_events_registration/src/RegistrationCreationService.php @@ -227,7 +227,8 @@ class RegistrationCreationService { $capacity = $this->eventSeries->event_registration->capacity; if (empty($capacity)) { - $capacity = 0; + // Set capacity to unlimited if no capacity is specified. + return -1; } $availability = $capacity - count($parties); if ($availability < 0) { @@ -292,8 +293,6 @@ class RegistrationCreationService { * Whether this user has already registered for this event. */ public function hasUserRegisteredById($uid) { - $properties = []; - $registrants = $this->retrieveRegisteredParties(TRUE, TRUE, $uid); return !empty($registrants); } @@ -323,7 +322,7 @@ class RegistrationCreationService { $waitlisted_users = $this->retrieveWaitlistedParties(); if (!empty($waitlisted_users)) { $first = reset($waitlisted_users); - \Drupal::moduleHandler()->alter('recurring_events_registration_first_waitlist', $first); + $this->moduleHandler->alter('recurring_events_registration_first_waitlist', $first); return $first; } return NULL; @@ -431,7 +430,7 @@ class RegistrationCreationService { $reg_type = $this->getRegistrationType(); $reg_dates_type = $this->getRegistrationDatesType(); - $timezone = new \DateTimeZone(drupal_get_user_timezone()); + $timezone = new \DateTimeZone(date_default_timezone_get()); $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $now = new DrupalDateTime(); diff --git a/modules/recurring_events_views/README.md b/modules/recurring_events_views/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cb9113f340b5532ad3ea0dac13c28193cbbcf838 --- /dev/null +++ b/modules/recurring_events_views/README.md @@ -0,0 +1,28 @@ +# Recurring Events Views (recurring_events_views) +--- + +## Introduction +Recurring Events provides listings for event series, event instances and +registrations. For many installations this will provide a satisfactory way of +managing events without the need to install extra modules. + +For those cases which call for something more flexible, views integration is +provided by an optional sub-module called Recurring Events Views +(recurring_events_views). + +After enabling this submodule, all listings are replaced by views and no further +configuration is necessary. + +### Views are provided for; + +- Event Series +- Event Instances +- Registrations + +Admin views are available to user roles with suitable permissions. There are +also views for anonymous and authenticated users, for the front end. + +- Admin views are provided with sensible default settings and exposed filters. +- The front end event series listings, display only future or current events. + +The default views can be further customized as needed. diff --git a/modules/recurring_events_views/config/install/views.view.event_series.yml b/modules/recurring_events_views/config/install/views.view.event_series.yml new file mode 100644 index 0000000000000000000000000000000000000000..13c81fdac0e9038e66afc34058891ab31bbc8824 --- /dev/null +++ b/modules/recurring_events_views/config/install/views.view.event_series.yml @@ -0,0 +1,1426 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.eventseries.list + - system.menu.main + module: + - options + - recurring_events + - user +id: event_series +label: 'Event Series' +module: views +description: 'A view showing all the event series on the site.' +tag: '' +base_table: eventseries_field_data +base_field: id +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'view eventseries entity' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + tags: + previous: ‹‹ + next: ›› + first: '« First' + last: 'Last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + style: + type: table + row: + type: fields + fields: + title: + id: title + table: eventseries_field_data + field: title + relationship: none + group_type: group + admin_label: '' + label: Title + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: null + entity_field: title + plugin_id: field + type: + id: type + table: eventseries_field_data + field: type + relationship: none + group_type: group + admin_label: '' + label: Type + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: type + plugin_id: field + recur_type: + id: recur_type + table: eventseries_field_data + field: recur_type + relationship: none + group_type: group + admin_label: '' + label: 'Recur Type' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: list_default + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: recur_type + plugin_id: field + eventseries_instance_count: + id: eventseries_instance_count + table: eventseries_field_data + field: eventseries_instance_count + relationship: none + group_type: group + admin_label: '' + label: Instances + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + entity_type: eventseries + plugin_id: eventseries_instance_count + eventseries_start_date: + id: eventseries_start_date + table: eventseries_field_data + field: eventseries_start_date + relationship: none + group_type: group + admin_label: '' + label: 'Series Starts' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + entity_type: eventseries + plugin_id: eventseries_start_date + uid: + id: uid + table: eventseries_field_data + field: uid + relationship: none + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: true + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: uid + plugin_id: field + status: + id: status + table: eventseries_field_data + field: status + relationship: none + group_type: group + admin_label: '' + label: Published + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: yes-no + format_custom_true: '' + format_custom_false: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: status + plugin_id: field + created: + id: created + table: eventseries_field_data + field: created + relationship: none + group_type: group + admin_label: '' + label: Created + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: medium + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: created + plugin_id: field + changed: + id: changed + table: eventseries_field_data + field: changed + relationship: none + group_type: group + admin_label: '' + label: Changed + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: medium + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: changed + plugin_id: field + operations: + id: operations + table: eventseries + field: operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: false + entity_type: eventseries + plugin_id: entity_operations + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: Title + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + type: + id: type + table: eventseries_field_data + field: type + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: type + plugin_id: bundle + recur_type: + id: recur_type + table: eventseries_field_data + field: recur_type + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: recur_type_op + label: 'Recur Type' + description: '' + use_operator: false + operator: recur_type_op + identifier: recur_type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: recur_type + plugin_id: string + uid: + id: uid + table: users_field_data + field: uid + relationship: uid + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: uid_op + label: Author + description: '' + use_operator: false + operator: uid_op + identifier: uid + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: user + entity_field: uid + plugin_id: user_name + created: + id: created + table: eventseries_field_data + field: created + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_op + label: 'Created After' + description: '' + use_operator: false + operator: created_op + identifier: created + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: created + plugin_id: date + created_1: + id: created_1 + table: eventseries_field_data + field: created + relationship: none + group_type: group + admin_label: '' + operator: '<=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_1_op + label: 'Created Before' + description: '' + use_operator: false + operator: created_1_op + identifier: created_1 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: created + plugin_id: date + status: + id: status + table: eventseries_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Published + description: '' + use_operator: false + operator: status_op + identifier: status + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: status + plugin_id: boolean + sorts: + title: + id: title + table: eventseries_field_data + field: title + relationship: none + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + entity_type: eventseries + entity_field: title + plugin_id: standard + title: 'Event Series' + header: { } + footer: { } + empty: { } + relationships: + uid: + id: uid + table: eventseries_field_data + field: uid + relationship: none + group_type: group + admin_label: User + required: false + entity_type: eventseries + entity_field: uid + plugin_id: standard + arguments: { } + display_extenders: { } + filter_groups: + operator: AND + groups: + 1: AND + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + admin_page: + display_plugin: page + id: admin_page + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: admin/content/events/series + access: + type: perm + options: + perm: 'access eventseries overview' + defaults: + access: false + pager: false + filters: false + filter_groups: false + pager: + type: full + options: + items_per_page: 25 + offset: 0 + id: 0 + total_pages: null + tags: + previous: ‹‹ + next: ›› + first: '« First' + last: 'Last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: Title + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + type: + id: type + table: eventseries_field_data + field: type + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: type + plugin_id: bundle + recur_type: + id: recur_type + table: eventseries_field_data + field: recur_type + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: recur_type_op + label: 'Recur Type' + description: '' + use_operator: false + operator: recur_type_op + operator_limit_selection: false + operator_list: { } + identifier: recur_type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + is_grouped: true + group_info: + label: 'Recur Type' + description: '' + identifier: recur_type + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: Consecutive + operator: contains + value: consecutive_recurring_date + 2: + title: Daily + operator: contains + value: daily_recurring_date + 3: + title: Weekly + operator: contains + value: weekly_recurring_date + 4: + title: Monthly + operator: contains + value: monthly_recurring_date + 5: + title: Custom + operator: contains + value: custom + entity_type: eventseries + entity_field: recur_type + plugin_id: string + status: + id: status + table: eventseries_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Published + description: '' + use_operator: false + operator: status_op + operator_limit_selection: false + operator_list: { } + identifier: status + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: true + group_info: + label: Published + description: '' + identifier: status + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: Published + operator: '=' + value: '1' + 2: + title: Unpublished + operator: '=' + value: '0' + entity_type: eventseries + entity_field: status + plugin_id: boolean + filter_groups: + operator: AND + groups: + 1: AND + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + eventseries_listing: + display_plugin: page + id: eventseries_listing + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: events/series + menu: + type: normal + title: 'Event Series' + description: 'Event series listing' + expanded: false + parent: '' + weight: 0 + context: '0' + menu_name: main + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + defaults: + style: false + row: false + filters: false + filter_groups: false + row: + type: 'entity:eventseries' + options: + relationship: none + view_mode: list + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: Title + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + status: + id: status + table: eventseries_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: status + plugin_id: boolean + filter_groups: + operator: AND + groups: + 1: AND + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } diff --git a/modules/recurring_events_views/config/install/views.view.events.yml b/modules/recurring_events_views/config/install/views.view.events.yml new file mode 100644 index 0000000000000000000000000000000000000000..f9d6805cdb4eae2a31d4b3a3d2e6765f03d33ed2 --- /dev/null +++ b/modules/recurring_events_views/config/install/views.view.events.yml @@ -0,0 +1,2127 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.eventinstance.list + - system.menu.main + module: + - datetime + - datetime_range + - recurring_events + - user +id: events +label: Events +module: views +description: 'A view showing all the event instances on the site' +tag: '' +base_table: eventinstance_field_data +base_field: id +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'view eventinstance entity' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + tags: + previous: ‹‹ + next: ›› + first: '« First' + last: 'Last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + override: true + sticky: false + caption: '' + summary: '' + description: '' + columns: + title: title + view_eventseries: view_eventseries + view_eventinstance: view_eventinstance + title_2: title_2 + title_1: title_1 + date__value: date__value + info: + title: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + view_eventseries: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + view_eventinstance: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + title_2: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + title_1: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + date__value: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + default: '-1' + empty_table: false + row: + type: 'entity:eventinstance' + fields: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + view_eventseries: + id: view_eventseries + table: eventseries + field: view_eventseries + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: view + output_url_as_text: true + absolute: false + entity_type: eventseries + plugin_id: entity_link + view_eventinstance: + id: view_eventinstance + table: eventinstance + field: view_eventinstance + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '{{ title }}' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: '' + output_url_as_text: true + absolute: false + entity_type: eventinstance + plugin_id: entity_link + title_2: + id: title_2 + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: 'Event Name' + exclude: false + alter: + alter_text: true + text: '{{ title }}' + make_link: true + path: '{{ view_eventinstance }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + title_1: + id: title_1 + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: Series + exclude: false + alter: + alter_text: true + text: '{{ "View Series"|t }}' + make_link: true + path: '{{ view_eventseries }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + type: + id: type + table: eventinstance_field_data + field: type + relationship: none + group_type: group + admin_label: '' + label: Type + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: type + plugin_id: field + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + label: 'Event Date' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: daterange_default + settings: + timezone_override: '' + format_type: medium + fromto: start_date + separator: '-' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: date + plugin_id: field + uid: + id: uid + table: eventinstance_field_data + field: uid + relationship: none + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: true + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: uid + plugin_id: field + status: + id: status + table: eventinstance_field_data + field: status + relationship: none + group_type: group + admin_label: '' + label: Published + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: yes-no + format_custom_true: '' + format_custom_false: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: status + plugin_id: field + created: + id: created + table: eventinstance_field_data + field: created + relationship: none + group_type: group + admin_label: '' + label: Created + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: medium + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: created + plugin_id: field + changed: + id: changed + table: eventinstance_field_data + field: changed + relationship: none + group_type: group + admin_label: '' + label: Changed + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: medium + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: changed + plugin_id: field + operations: + id: operations + table: eventinstance + field: operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: false + entity_type: eventinstance + plugin_id: entity_operations + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: 'Event Name' + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + type: + id: type + table: eventinstance_field_data + field: type + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: type + plugin_id: bundle + uid: + id: uid + table: users_field_data + field: uid + relationship: uid + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: uid_op + label: Author + description: '' + use_operator: false + operator: uid_op + identifier: uid + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: user + entity_field: uid + plugin_id: user_name + created: + id: created + table: eventinstance_field_data + field: created + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_op + label: 'Created After' + description: '' + use_operator: false + operator: created_op + identifier: created + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: created + plugin_id: date + created_1: + id: created_1 + table: eventinstance_field_data + field: created + relationship: none + group_type: group + admin_label: '' + operator: '<=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_1_op + label: 'Created Before' + description: '' + use_operator: false + operator: created_1_op + identifier: created_1 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: created + plugin_id: date + status: + id: status + table: eventinstance_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Published + description: '' + use_operator: false + operator: status_op + identifier: status + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: status + plugin_id: boolean + sorts: + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + entity_type: eventinstance + entity_field: date + plugin_id: standard + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + entity_type: eventseries + entity_field: title + plugin_id: standard + title: Events + header: { } + footer: { } + empty: { } + relationships: + eventseries_id: + id: eventseries_id + table: eventinstance_field_data + field: eventseries_id + relationship: none + group_type: group + admin_label: 'Event series entity' + required: true + entity_type: eventinstance + entity_field: eventseries_id + plugin_id: standard + uid: + id: uid + table: eventinstance_field_data + field: uid + relationship: none + group_type: group + admin_label: User + required: false + entity_type: eventinstance + entity_field: uid + plugin_id: standard + arguments: { } + display_extenders: { } + filter_groups: + operator: AND + groups: + 1: AND + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + admin_page: + display_plugin: page + id: admin_page + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: admin/content/events/instances + access: + type: perm + options: + perm: 'access eventinstance overview' + defaults: + access: false + pager: false + filters: false + filter_groups: false + pager: + type: full + options: + items_per_page: 25 + offset: 0 + id: 0 + total_pages: null + tags: + previous: ‹‹ + next: ›› + first: '« First' + last: 'Last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + exposed_block: false + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: 'Event Name' + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + type: + id: type + table: eventinstance_field_data + field: type + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: type + plugin_id: bundle + date__value_2: + id: date__value_2 + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: date__value_2_op + label: 'Event Date' + description: null + use_operator: false + operator: date__value_2_op + operator_limit_selection: false + operator_list: { } + identifier: date__value_2 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + placeholder: null + min_placeholder: null + max_placeholder: null + is_grouped: true + group_info: + label: 'Event Date' + description: '' + identifier: date__value_2 + optional: true + widget: select + multiple: false + remember: false + default_group: '1' + default_group_multiple: { } + group_items: + 1: + title: Future + operator: '>=' + value: + type: offset + value: today + min: '' + max: '' + 2: + title: Past + operator: '<=' + value: + type: offset + value: today + min: '' + max: '' + entity_type: eventinstance + entity_field: date + plugin_id: datetime + status: + id: status + table: eventinstance_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Published + description: '' + use_operator: false + operator: status_op + operator_limit_selection: false + operator_list: { } + identifier: status + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: true + group_info: + label: Published + description: '' + identifier: status + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: Published + operator: '=' + value: '1' + 2: + title: Unpublished + operator: '=' + value: '0' + entity_type: eventinstance + entity_field: status + plugin_id: boolean + filter_groups: + operator: AND + groups: + 1: AND + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + events_listing: + display_plugin: page + id: events_listing + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: events + menu: + type: normal + title: Events + description: 'Events listing page' + expanded: false + parent: '' + weight: 0 + context: '0' + menu_name: main + fields: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + view_eventseries: + id: view_eventseries + table: eventseries + field: view_eventseries + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: view + output_url_as_text: true + absolute: false + entity_type: eventseries + plugin_id: entity_link + view_eventinstance: + id: view_eventinstance + table: eventinstance + field: view_eventinstance + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '{{ title }}' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: '' + output_url_as_text: true + absolute: false + entity_type: eventinstance + plugin_id: entity_link + title_2: + id: title_2 + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: 'Event Name' + exclude: false + alter: + alter_text: true + text: '{{ title }}' + make_link: true + path: '{{ view_eventinstance }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + title_1: + id: title_1 + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: Series + exclude: false + alter: + alter_text: true + text: '{{ "View Series"|t }}' + make_link: true + path: '{{ view_eventseries }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + label: 'Event Date' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: daterange_default + settings: + timezone_override: '' + format_type: medium + fromto: start_date + separator: '-' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: date + plugin_id: field + defaults: + fields: false + filters: false + filter_groups: false + style: false + row: false + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: 'Event Name' + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: date__value_op + label: 'Date After' + description: '' + use_operator: false + operator: date__value_op + operator_limit_selection: false + operator_list: { } + identifier: date__value + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: date + plugin_id: datetime + date__value_1: + id: date__value_1 + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + operator: '<=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: date__value_1_op + label: 'Date Before' + description: '' + use_operator: false + operator: date__value_1_op + operator_limit_selection: false + operator_list: { } + identifier: date__value_1 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: date + plugin_id: datetime + status: + id: status + table: eventinstance_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: status + plugin_id: boolean + date__value_2: + id: date__value_2 + table: eventinstance_field_data + field: date__value + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: today + type: offset + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + operator_limit_selection: false + operator_list: { } + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + placeholder: '' + min_placeholder: '' + max_placeholder: '' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventinstance + entity_field: date + plugin_id: datetime + filter_groups: + operator: AND + groups: + 1: AND + style: + type: default + options: + row_class: '' + default_row_class: true + uses_fields: false + row: + type: 'entity:eventinstance' + options: + relationship: none + view_mode: list + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } diff --git a/modules/recurring_events_views/config/optional/views.view.registrations.yml b/modules/recurring_events_views/config/optional/views.view.registrations.yml new file mode 100644 index 0000000000000000000000000000000000000000..289190adf2153616e97e5628bd4a12be6d50b2b1 --- /dev/null +++ b/modules/recurring_events_views/config/optional/views.view.registrations.yml @@ -0,0 +1,2515 @@ +langcode: en +status: true +dependencies: + module: + - datetime + - datetime_range + - recurring_events + - recurring_events_registration + - user +id: registrations +label: Registrations +module: views +description: 'A view showing all the registrants on the site' +tag: '' +base_table: registrant +base_field: id +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access registrant overview' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 25 + offset: 0 + id: 0 + total_pages: null + tags: + previous: ‹‹ + next: ›› + first: '« First' + last: 'Last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + style: + type: table + row: + type: fields + fields: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + view_eventinstance: + id: view_eventinstance + table: eventinstance + field: view_eventinstance + relationship: eventinstance_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: view + output_url_as_text: true + absolute: false + entity_type: eventinstance + plugin_id: entity_link + view_eventseries: + id: view_eventseries + table: eventseries + field: view_eventseries + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: view + output_url_as_text: true + absolute: false + entity_type: eventseries + plugin_id: entity_link + id: + id: id + table: registrant + field: id + relationship: none + group_type: group + admin_label: '' + label: ID + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: id + plugin_id: field + title_1: + id: title_1 + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: 'Event Series' + exclude: false + alter: + alter_text: true + text: '{{ title }}' + make_link: true + path: '{{ view_eventseries }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: eventinstance_id + group_type: group + admin_label: '' + label: 'Event Date' + exclude: false + alter: + alter_text: true + text: '{{ date__value }}' + make_link: true + path: '{{ view_eventinstance }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: daterange_default + settings: + timezone_override: '' + format_type: medium + fromto: start_date + separator: '-' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: date + plugin_id: field + waitlist: + id: waitlist + table: registrant + field: waitlist + relationship: none + group_type: group + admin_label: '' + label: Waitlist + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: yes-no + format_custom_true: '' + format_custom_false: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: waitlist + plugin_id: field + type: + id: type + table: registrant + field: type + relationship: none + group_type: group + admin_label: '' + label: Type + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: type + plugin_id: field + bundle: + id: bundle + table: registrant + field: bundle + relationship: none + group_type: group + admin_label: '' + label: Bundle + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: bundle + plugin_id: field + user_id: + id: user_id + table: registrant + field: user_id + relationship: none + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: true + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: user_id + plugin_id: field + operations: + id: operations + table: registrant + field: operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: false + entity_type: registrant + plugin_id: entity_operations + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: 'Event Name' + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + waitlist: + id: waitlist + table: registrant + field: waitlist + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Waitlist + description: '' + use_operator: false + operator: waitlist_op + identifier: waitlist + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: waitlist + plugin_id: boolean + type: + id: type + table: registrant + field: type + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: type + plugin_id: string + bundle: + id: bundle + table: registrant + field: bundle + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: bundle_op + label: Bundle + description: '' + use_operator: false + operator: bundle_op + identifier: bundle + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: bundle + plugin_id: bundle + created_1: + id: created_1 + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + operator: '<=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_1_op + label: 'Created Before' + description: '' + use_operator: false + operator: created_1_op + identifier: created_1 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: created + plugin_id: date + created_2: + id: created_2 + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_2_op + label: 'Created After' + description: '' + use_operator: false + operator: created_2_op + identifier: created_2 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: created + plugin_id: date + uid: + id: uid + table: users_field_data + field: uid + relationship: user_id + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: uid_op + label: Author + description: '' + use_operator: false + operator: uid_op + identifier: uid + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: user + entity_field: uid + plugin_id: user_name + sorts: { } + title: Registrations + header: { } + footer: { } + empty: + area: + id: area + table: views + field: area + relationship: none + group_type: group + admin_label: '' + empty: true + tokenize: false + content: + value: '<h2>No registrations found</h2>' + format: basic_html + plugin_id: text + relationships: + eventinstance_id: + id: eventinstance_id + table: registrant + field: eventinstance_id + relationship: none + group_type: group + admin_label: 'Event Instance entity' + required: false + entity_type: registrant + entity_field: eventinstance_id + plugin_id: standard + eventseries_id: + id: eventseries_id + table: registrant + field: eventseries_id + relationship: none + group_type: group + admin_label: 'Event series entity' + required: false + entity_type: registrant + entity_field: eventseries_id + plugin_id: standard + user_id: + id: user_id + table: registrant + field: user_id + relationship: none + group_type: group + admin_label: User + required: false + entity_type: registrant + entity_field: user_id + plugin_id: standard + arguments: { } + display_extenders: { } + filter_groups: + operator: AND + groups: + 1: AND + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + admin_page: + display_plugin: page + id: admin_page + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: admin/content/events/registrations + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + event_registrant_list: + display_plugin: page + id: event_registrant_list + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: events/%eventinstance/registrations + defaults: + access: false + arguments: false + filters: false + filter_groups: false + fields: false + sorts: false + arguments: { } + filters: + waitlist: + id: waitlist + table: registrant + field: waitlist + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Waitlist + description: '' + use_operator: false + operator: waitlist_op + identifier: waitlist + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: waitlist + plugin_id: boolean + created_1: + id: created_1 + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + operator: '<=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_1_op + label: 'Created Before' + description: '' + use_operator: false + operator: created_1_op + identifier: created_1 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: created + plugin_id: date + created_2: + id: created_2 + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_2_op + label: 'Created After' + description: '' + use_operator: false + operator: created_2_op + identifier: created_2 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: created + plugin_id: date + uid: + id: uid + table: users_field_data + field: uid + relationship: user_id + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: uid_op + label: Author + description: '' + use_operator: false + operator: uid_op + identifier: uid + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: user + entity_field: uid + plugin_id: user_name + filter_groups: + operator: AND + groups: + 1: AND + fields: + id: + id: id + table: registrant + field: id + relationship: none + group_type: group + admin_label: '' + label: ID + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: id + plugin_id: field + waitlist: + id: waitlist + table: registrant + field: waitlist + relationship: none + group_type: group + admin_label: '' + label: Waitlist + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: yes-no + format_custom_true: '' + format_custom_false: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: waitlist + plugin_id: field + user_id: + id: user_id + table: registrant + field: user_id + relationship: none + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: true + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: user_id + plugin_id: field + operations: + id: operations + table: registrant + field: operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: false + entity_type: registrant + plugin_id: entity_operations + menu: + type: none + title: '' + description: '' + expanded: false + parent: '' + weight: 0 + context: '0' + menu_name: main + sorts: + created: + id: created + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + granularity: second + entity_type: registrant + entity_field: created + plugin_id: date + access: + type: event_registration_list_access + options: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + tags: { } + user_event_registrations: + display_plugin: page + id: user_event_registrations + display_title: Page + position: 3 + display_options: + display_extenders: { } + path: user/%user/registrations + arguments: + user_id: + id: user_id + table: registrant + field: user_id + relationship: none + group_type: group + admin_label: '' + default_action: default + exception: + value: all + title_enable: false + title: All + title_enable: false + title: '' + default_argument_type: user + default_argument_options: + user: false + default_argument_skip_url: false + summary_options: + base_path: '' + count: true + items_per_page: 25 + override: false + summary: + sort_order: asc + number_of_records: 0 + format: default_summary + specify_validation: false + validate: + type: none + fail: 'not found' + validate_options: { } + break_phrase: false + not: false + entity_type: registrant + entity_field: user_id + plugin_id: numeric + defaults: + arguments: false + filters: false + filter_groups: false + fields: false + sorts: false + filters: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: 'Event Name' + description: '' + use_operator: false + operator: title_op + identifier: title + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: eventseries + entity_field: title + plugin_id: string + waitlist: + id: waitlist + table: registrant + field: waitlist + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Waitlist + description: '' + use_operator: false + operator: waitlist_op + identifier: waitlist + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: waitlist + plugin_id: boolean + type: + id: type + table: registrant + field: type + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: type + plugin_id: string + created_1: + id: created_1 + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + operator: '<=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_1_op + label: 'Created Before' + description: '' + use_operator: false + operator: created_1_op + identifier: created_1 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: created + plugin_id: date + created_2: + id: created_2 + table: registrant + field: created + relationship: none + group_type: group + admin_label: '' + operator: '>=' + value: + min: '' + max: '' + value: '' + type: date + group: 1 + exposed: true + expose: + operator_id: created_2_op + label: 'Created After' + description: '' + use_operator: false + operator: created_2_op + identifier: created_2 + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + placeholder: '' + min_placeholder: '' + max_placeholder: '' + operator_limit_selection: false + operator_list: { } + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: registrant + entity_field: created + plugin_id: date + filter_groups: + operator: AND + groups: + 1: AND + fields: + title: + id: title + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + view_eventinstance: + id: view_eventinstance + table: eventinstance + field: view_eventinstance + relationship: eventinstance_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: view + output_url_as_text: true + absolute: false + entity_type: eventinstance + plugin_id: entity_link + view_eventseries: + id: view_eventseries + table: eventseries + field: view_eventseries + relationship: eventseries_id + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: view + output_url_as_text: true + absolute: false + entity_type: eventseries + plugin_id: entity_link + id: + id: id + table: registrant + field: id + relationship: none + group_type: group + admin_label: '' + label: ID + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: id + plugin_id: field + title_1: + id: title_1 + table: eventseries_field_data + field: title + relationship: eventseries_id + group_type: group + admin_label: '' + label: 'Event Series' + exclude: false + alter: + alter_text: true + text: '{{ title }}' + make_link: true + path: '{{ view_eventseries }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventseries + entity_field: title + plugin_id: field + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: eventinstance_id + group_type: group + admin_label: '' + label: 'Event Date' + exclude: false + alter: + alter_text: true + text: '{{ date__value }}' + make_link: true + path: '{{ view_eventinstance }}' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: daterange_default + settings: + timezone_override: '' + format_type: medium + fromto: start_date + separator: '-' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: eventinstance + entity_field: date + plugin_id: field + waitlist: + id: waitlist + table: registrant + field: waitlist + relationship: none + group_type: group + admin_label: '' + label: Waitlist + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: yes-no + format_custom_true: '' + format_custom_false: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: waitlist + plugin_id: field + type: + id: type + table: registrant + field: type + relationship: none + group_type: group + admin_label: '' + label: Type + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: registrant + entity_field: type + plugin_id: field + operations: + id: operations + table: registrant + field: operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: false + entity_type: registrant + plugin_id: entity_operations + sorts: + date__value: + id: date__value + table: eventinstance_field_data + field: date__value + relationship: eventinstance_id + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + granularity: second + entity_type: eventinstance + entity_field: date + plugin_id: datetime + menu: + type: tab + title: Registrations + description: '' + expanded: false + parent: '' + weight: 0 + context: '0' + menu_name: account + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } diff --git a/modules/recurring_events_views/recurring_events_views.info.yml b/modules/recurring_events_views/recurring_events_views.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..19105633810bda52ab85af665b0e8d1e5385135d --- /dev/null +++ b/modules/recurring_events_views/recurring_events_views.info.yml @@ -0,0 +1,9 @@ +name: 'Recurring Events Views' +type: module +description: 'Swaps all recurring events list builders for views' +core: 8.x +package: 'Recurring Events' +core_version_requirement: ^8 || ^9 +dependencies: + - drupal:views + - recurring_events:recurring_events diff --git a/modules/recurring_events_views/recurring_events_views.install b/modules/recurring_events_views/recurring_events_views.install new file mode 100644 index 0000000000000000000000000000000000000000..706035c6a00b91174f39d290dd747ddbe8464d28 --- /dev/null +++ b/modules/recurring_events_views/recurring_events_views.install @@ -0,0 +1,28 @@ +<?php + +/** + * @file + * Install and update functionalit for the recurring_events_views module. + */ + +use Drupal\views\Views; + +/** + * Install the menu tab view display option for the user registration view. + */ +function recurring_events_views_update_8001() { + $view = Views::getView('registrations'); + $display = &$view->storage->getDisplay('user_event_registrations'); + $display['display_options']['menu'] = [ + 'type' => 'tab', + 'title' => 'Registrations', + 'description' => '', + 'expanded' => FALSE, + 'parent' => '', + 'weight' => 0, + 'context' => '0', + 'menu_name' => 'account', + ]; + $view->storage->save(); + $view->storage->invalidateCaches(); +} diff --git a/modules/recurring_events_views/recurring_events_views.module b/modules/recurring_events_views/recurring_events_views.module new file mode 100644 index 0000000000000000000000000000000000000000..0624dc42c3b35130984275873d1aaced6f1b70fb --- /dev/null +++ b/modules/recurring_events_views/recurring_events_views.module @@ -0,0 +1,151 @@ +<?php + +/** + * @file + * Contains recurring_events_views.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\views\ViewExecutable; +use Drupal\views\Plugin\views\query\QueryPluginBase; +use Drupal\Component\Utility\Html; +use Symfony\Component\Routing\Exception\RouteNotFoundException; + +/** + * Implements hook_help(). + */ +function recurring_events_views_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // Main module help for the recurring_events_views module. + case 'help.page.recurring_events_views': + $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_local_tasks_alter(). + */ +function recurring_events_views_local_tasks_alter(&$local_tasks) { + if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) { + try { + if (\Drupal::service('router.route_provider')->getRouteByName('view.registrations.event_registrant_list')) { + if (!empty($local_tasks['entity.registrant.instance_listing'])) { + $local_tasks['entity.registrant.instance_listing']['route_name'] = 'view.registrations.event_registrant_list'; + $local_tasks['entity.registrant.instance_listing']['id'] = 'view.registrations.event_registrant_list'; + } + } + } + catch (RouteNotFoundException $exception) { + \Drupal::logger('recurring_events_views')->error($exception->getMessage()); + } + + if (!empty($local_tasks['views_view:view.registrations.user_event_registrations'])) { + unset($local_tasks['entity.user.registrations']); + } + } +} + +/** + * Implements hook_views_query_alter(). + */ +function recurring_events_views_views_query_alter(ViewExecutable $view, QueryPluginBase $query) { + // Because registration is complicated by series vs instance registration we + // need to modify the view to accomodate that. If an event has series + // registration then viewing the registration list on any of the instances + // should display all registrations for that event. However, if the event has + // instance registration, then we should only see registrations for the + // particular instance being viewed. + if ($view->id() === 'registrations' && $view->current_display === 'event_registrant_list') { + if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) { + $eventinstance_id = \Drupal::routeMatch()->getParameters()->get('eventinstance'); + + if (!empty($eventinstance_id)) { + $eventinstance = \Drupal::entityTypeManager()->getStorage('eventinstance')->load($eventinstance_id); + if (!empty($eventinstance)) { + $service = \Drupal::service('recurring_events_registration.creation_service'); + $service->setEventInstance($eventinstance); + switch ($service->getRegistrationType()) { + case 'instance': + $field = 'registrant.eventinstance_id'; + $value = [ + $eventinstance->id(), + ]; + break; + + case 'series': + default: + $field = 'registrant.eventseries_id'; + $value = [ + $eventinstance->getEventSeries()->id(), + ]; + break; + } + } + + if (!empty($field) && !empty($value)) { + $query->where[1]['conditions'][] = [ + 'field' => $field, + 'value' => $value, + 'operator' => '=', + ]; + } + } + } + } +} + +/** + * Implements hook_views_pre_render(). + */ +function recurring_events_views_views_pre_render(ViewExecutable $view) { + // Because registration is complicated by series vs instance registration we + // need to modify the view title to accomodate that. + if ($view->id() === 'registrations' && $view->current_display === 'event_registrant_list') { + if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) { + $eventinstance_id = \Drupal::routeMatch()->getParameters()->get('eventinstance'); + + if (!empty($eventinstance_id)) { + $eventinstance = \Drupal::entityTypeManager()->getStorage('eventinstance')->load($eventinstance_id); + $service = \Drupal::service('recurring_events_registration.creation_service'); + if (!empty($eventinstance)) { + $service->setEventInstance($eventinstance); + $config = \Drupal::config('recurring_events.eventinstance.config'); + $format = $config->get('date_format'); + $name = $eventinstance->title->value; + switch ($service->getRegistrationType()) { + case 'instance': + $title = t('Registrations for %name on %date', [ + '%name' => $name, + '%date' => $eventinstance->date->start_date->format($format), + ]); + break; + + case 'series': + default: + $title = t('Registrations for series: %name', [ + '%name' => $name, + ]); + break; + } + + if (!empty($title)) { + $view->setTitle($title); + } + } + } + } + + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000000000000000000000000000000000000..08d699d118f1c53371827f6ad6772c2802b5b0a8 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<phpunit colors="true"> + <php> + <!-- Set error reporting to E_ALL. --> + <ini name="error_reporting" value="32767"/> + <!-- Do not limit the amount of memory tests take to run. --> + <ini name="memory_limit" value="-1"/> + </php> + <testsuites> + <testsuite name="Recurring Events Test Suite"> + <directory>./tests</directory> + <!-- directory>./modules/recurring_events_registration/tests</directory --> + <!-- directory>./modules/recurring_events_views/tests</directory --> + </testsuite> + </testsuites> +</phpunit> diff --git a/recurring_events.api.php b/recurring_events.api.php index 798bf2a1608e05241ec96ac51d81f0c16535b6a1..fdfadb85cb5211d621c3c5b446ded79d737595b4 100644 --- a/recurring_events.api.php +++ b/recurring_events.api.php @@ -90,7 +90,7 @@ function hook_recurring_events_form_config_array_alter(array &$form_config = []) */ function hook_recurring_events_entity_config_array_alter(array &$entity_config = []) { // Remove the first custom date. - unset($form_config['custom_dates'][0]); + unset($entity_config['custom_dates'][0]); } /** @@ -101,21 +101,7 @@ function hook_recurring_events_entity_config_array_alter(array &$entity_config = */ function hook_recurring_events_diff_array_alter(array &$diff = []) { // Do not show differences in custom dates. - unset($form_config['custom_dates']); -} - -/** - * Alter the inheritance class used to build the inherited basefield. - * - * @var string $class - * The class to alter. - * @var Drupal\Core\Field\FieldDefinitionInterface $field - * The field context. - */ -function hook_recurring_events_inheritance_class_alter(&$class, $field) { - if ($field->plugin() === 'entity_reference_inheritance') { - $class = '\Drupal\my_module\EntityReferenceFieldInheritanceFactory'; - } + unset($diff['custom_dates']); } /** diff --git a/recurring_events.info.yml b/recurring_events.info.yml index 071ecf065df854b622837d18fe025e354a13c49a..9b534c83e430b2b90e4bdf3741f8fd2bb462baef 100644 --- a/recurring_events.info.yml +++ b/recurring_events.info.yml @@ -6,4 +6,5 @@ core_version_requirement: ^8 || ^9 package: 'Recurring Events' dependencies: - drupal:datetime_range - - drupal:options \ No newline at end of file + - drupal:options + - field_inheritance:field_inheritance diff --git a/recurring_events.install b/recurring_events.install index cf479472ff87ad71fb49f229ecdb9c87c4b51310..131f4207839015b0d0600d32834da351cf99b81d 100644 --- a/recurring_events.install +++ b/recurring_events.install @@ -5,8 +5,10 @@ * Installation and update functionality for the recurring_events module. */ +use Drupal\Core\Config\Entity\ConfigEntityType; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Config\FileStorage; /** * Install the excluded and included date fields. @@ -28,7 +30,6 @@ function recurring_events_update_8001() { ->setSetting('datetime_type', 'date') ->setDisplayOptions('form', [ 'type' => 'daterange_default', - 'label' => 'above', 'weight' => 6, 'settings' => [ 'format_type' => 'html_date', @@ -50,7 +51,6 @@ function recurring_events_update_8001() { ->setSetting('datetime_type', 'date') ->setDisplayOptions('form', [ 'type' => 'daterange_default', - 'label' => 'above', 'weight' => 6, 'settings' => [ 'format_type' => 'html_date', @@ -169,3 +169,260 @@ function recurring_events_update_8004() { $config->set('threshold_prevent_save', 0); $config->save(TRUE); } + +/** + * Install the new config entities for event series and instance bundles. + */ +function recurring_events_update_8005() { + /* + * @see https://www.drupal.org/node/3069090 + */ + \Drupal::entityDefinitionUpdateManager()->installEntityType(new ConfigEntityType([ + 'id' => 'eventseries_type', + 'label' => new TranslatableMarkup('Event series type'), + 'handlers' => [ + 'view_builder' => 'Drupal\Core\Entity\EntityViewBuilder', + 'list_builder' => 'Drupal\recurring_events\EventSeriesTypeListBuilder', + 'form' => [ + 'add' => 'Drupal\recurring_events\Form\EventSeriesTypeForm', + 'edit' => 'Drupal\recurring_events\Form\EventSeriesTypeForm', + 'delete' => 'Drupal\recurring_events\Form\EventSeriesTypeDeleteForm', + ], + 'route_provider' => [ + 'html' => 'Drupal\recurring_events\EventSeriesTypeHtmlRouteProvider', + ], + ], + 'config_prefix' => 'eventseries_type', + 'bundle_of' => 'eventseries', + 'admin_permission' => 'administer eventseries entity', + 'entity_keys' => [ + 'id' => 'id', + 'label' => 'label', + 'uuid' => 'uuid', + ], + 'links' => [ + 'canonical' => '/admin/structure/events/series/types/eventseries_type/{eventseries_type}', + 'add-form' => '/admin/structure/events/series/types/eventseries_type/add', + 'edit-form' => '/admin/structure/events/series/types/eventseries_type/{eventseries_type}/edit', + 'delete-form' => '/admin/structure/events/series/types/eventseries_type/{eventseries_type}/delete', + 'collection' => '/admin/structure/events/series/types/eventseries_type', + ], + 'config_export' => [ + 'label', + 'id', + 'description', + ], + ])); + + \Drupal::entityDefinitionUpdateManager()->installEntityType(new ConfigEntityType([ + 'id' => 'eventinstance_type', + 'label' => new TranslatableMarkup('Event instance type'), + 'handlers' => [ + 'view_builder' => 'Drupal\Core\Entity\EntityViewBuilder', + 'list_builder' => 'Drupal\recurring_events\EventSeriesTypeListBuilder', + 'form' => [ + 'add' => 'Drupal\recurring_events\Form\EventSeriesTypeForm', + 'edit' => 'Drupal\recurring_events\Form\EventSeriesTypeForm', + 'delete' => 'Drupal\recurring_events\Form\EventSeriesTypeDeleteForm', + ], + 'route_provider' => [ + 'html' => 'Drupal\recurring_events\EventSeriesTypeHtmlRouteProvider', + ], + ], + 'config_prefix' => 'eventinstance_type', + 'bundle_of' => 'eventinstance', + 'admin_permission' => 'administer eventinstance entity', + 'entity_keys' => [ + 'id' => 'id', + 'label' => 'label', + 'uuid' => 'uuid', + ], + 'links' => [ + 'canonical' => '/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}', + 'add-form' => '/admin/structure/events/instance/types/eventinstance_type/add', + 'edit-form' => '/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}/edit', + 'delete-form' => '/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}/delete', + 'collection' => '/admin/structure/events/instance/types/eventinstance_type', + ], + 'config_export' => [ + 'label', + 'id', + 'description', + ], + ])); +} + +/** + * Install the new type basefields for series and instances. + */ +function recurring_events_update_8006() { + $series_type = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Type')) + ->setDescription(t('The eventseries type.')) + ->setSetting('target_type', 'eventseries_type') + ->setReadOnly(TRUE); + + \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition('type', 'eventseries', 'eventseries', $series_type); + + $instance_type = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Type')) + ->setDescription(t('The eventinstance type.')) + ->setSetting('target_type', 'eventinstance_type') + ->setReadOnly(TRUE); + + \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition('type', 'eventinstance', 'eventinstance', $instance_type); +} + +/** + * Transition existing field inheritance entities over to new module. + */ +function recurring_events_update_8007() { + \Drupal::service('module_installer')->install(['field_inheritance']); + $database = \Drupal::database(); + $inherited_fields = $database->select('config', 'c') + ->fields('c', ['name']) + ->condition('name', 'recurring_events.field_inheritance.%', 'LIKE') + ->execute() + ->fetchCol(); + $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('eventseries'); + + if (!empty($inherited_fields)) { + foreach ($inherited_fields as $inherited_field) { + $field = \Drupal::configFactory()->getEditable($inherited_field); + foreach ($bundles as $bundle_key => $bundle) { + $data = $field->getRawData(); + $id_parts = [ + 'eventinstance', + $bundle_key, + $data['id'], + ]; + $name = 'field_inheritance.field_inheritance.' . implode('_', $id_parts); + + $data['id'] = implode('_', $id_parts); + $data['sourceEntityType'] = 'eventseries'; + $data['sourceEntityBundle'] = $bundle_key; + $data['destinationEntityType'] = 'eventinstance'; + $data['destinationEntityBundle'] = $bundle_key; + $data['plugin'] = 'default_inheritance'; + + if (!empty($data['entityField'])) { + $data['destinationField'] = $data['entityField']; + unset($data['entityField']); + } + $field->setName($name)->setData($data)->save(); + } + } + $database->delete('config') + ->condition('name', 'recurring_events.field_inheritance.%', 'LIKE') + ->execute(); + } + + drupal_flush_all_caches(); +} + +/** + * Enable the eventinstance bundles to allow inheritance. + */ +function recurring_events_update_8008() { + // Enable the eventinstance bundles to allow inheritance. + $config = \Drupal::configFactory()->getEditable('field_inheritance.config'); + $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('eventseries'); + $data = $config->getRawData(); + + $included_entities = $data['included_entities']; + $included_entities = explode(',', $included_entities); + $included_entities[] = 'eventinstance'; + sort($included_entities); + $data['included_entities'] = implode(',', $included_entities); + + $included_bundles = $data['included_bundles']; + $included_bundles = explode(',', $included_bundles); + foreach ($bundles as $bundle_key => $bundle) { + $included_bundles[] = 'eventinstance:' . $bundle_key; + } + sort($included_bundles); + $data['included_bundles'] = implode(',', $included_bundles); + $config->setData($data)->save(); + + drupal_flush_all_caches(); +} + +/** + * Update all existing event instances. + */ +function recurring_events_update_8009(&$sandbox) { + // This is a multipass update. + if (empty($sandbox['events'])) { + $events = \Drupal::entityQuery('eventinstance')->execute(); + $sandbox['events'] = $events; + $sandbox['max'] = count($events); + $sandbox['limit'] = 50; + $sandbox['progress'] = 0; + } + + if (count($sandbox['events']) > 0) { + // Loop through chunks of 20 events at a time. + $events = array_splice($sandbox['events'], 0, $sandbox['limit'], []); + if (!empty($events)) { + $loaded_events = \Drupal::entityTypeManager()->getStorage('eventinstance')->loadMultiple($events); + $state = \Drupal::keyValue('field_inheritance'); + foreach ($loaded_events as $event) { + $entity_type = $event->getEntityTypeId(); + $bundle = $event->bundle(); + + $state_key = $event->getEntityTypeId() . ':' . $event->uuid(); + $state_values = $state->get($state_key); + + $inherited_field_ids = \Drupal::entityQuery('field_inheritance') + ->condition('sourceEntityType', 'eventseries') + ->condition('destinationEntityType', $entity_type) + ->condition('destinationEntityBundle', $bundle) + ->execute(); + + if (!empty($inherited_field_ids)) { + $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(); + $state_values[$name] = [ + 'entity' => $event->getEventSeries()->id(), + ]; + } + } + } + $state->set($state_key, $state_values); + + $sandbox['progress']++; + } + echo 'Updated: ' . count($events) . ' event instances. Total: ' . $sandbox['progress'] . ' of ' . $sandbox['max'] . "\r\n"; + $sandbox['#finished'] = ($sandbox['progress'] / $sandbox['max']); + } + } + else { + $sandbox['#finished'] = 1; + drupal_flush_all_caches(); + } +} + +/** + * Import new default config added for views submodule support. + */ +function recurring_events_update_8010() { + $configs = [ + 'core.entity_view_display.eventinstance.default.list', + 'core.entity_view_mode.eventinstance.list', + 'core.entity_view_display.eventseries.default.list', + 'core.entity_view_mode.eventseries.list', + ]; + + foreach ($configs as $config) { + $path = drupal_get_path('module', 'recurring_events') . '/config/install'; + $source = new FileStorage($path); + /** @var \Drupal\Core\Config\StorageInterface $active_storage */ + $active_storage = \Drupal::service('config.storage'); + $active_storage->write($config, $source->read($config)); + } +} diff --git a/recurring_events.libraries.yml b/recurring_events.libraries.yml index 79e065dfe9371ee747907971159c2e413feb1922..6950c953fd7aabd90b841c10333872f6ca90bc8b 100644 --- a/recurring_events.libraries.yml +++ b/recurring_events.libraries.yml @@ -12,4 +12,4 @@ recurring_events.date_form: js/recurring_events_date_form.js: {} dependencies: - core/drupal - - core/jquery \ No newline at end of file + - core/jquery diff --git a/recurring_events.links.action.yml b/recurring_events.links.action.yml index a8faa12bca2b49d984891374e66fbaefa7ee073a..813d4c726755f27aa82a062adba233aaa666a98b 100644 --- a/recurring_events.links.action.yml +++ b/recurring_events.links.action.yml @@ -1,6 +1,6 @@ # Add Event Series button. -entity.eventseries.add_form: - route_name: entity.eventseries.add_form +entity.eventseries.add_page: + route_name: entity.eventseries.add_page title: 'Add Event' appears_on: - entity.eventseries.admin_collection @@ -8,13 +8,11 @@ entity.eventseries.add_form: - entity.eventinstance.admin_collection - entity.eventinstance.collection - -# Add Field Inheritance button. -entity.field_inheritance.add_form: - route_name: entity.field_inheritance.add_form - title: 'Add Field inheritance' +entity.eventseries_type.add_form: + route_name: entity.eventseries_type.add_form + title: 'Add Event Series Type' appears_on: - - entity.field_inheritance.collection + - entity.eventseries_type.collection entity.excluded_dates.add_form: route_name: entity.excluded_dates.add_form diff --git a/recurring_events.links.menu.yml b/recurring_events.links.menu.yml index 7ded46c04401cba7b7ecd2274b5f219b95519b5f..235f7216aaeffb8c8b7450c03f8913fba4270b3b 100644 --- a/recurring_events.links.menu.yml +++ b/recurring_events.links.menu.yml @@ -13,10 +13,10 @@ events.admin.content: parent: system.admin_content # Add Event page. -eventseries.add: +entity.eventseries.add_page: title: 'Add Event' description: 'Add a new event.' - route_name: entity.eventseries.add_form + route_name: entity.eventseries.add_page parent: events.admin.content weight: 1 @@ -24,7 +24,7 @@ eventseries.add: eventseries.listing: title: 'Event Series' description: 'Event series listing.' - route_name: entity.eventseries.collection + route_name: entity.eventseries.admin_collection parent: events.admin.content weight: 2 @@ -32,7 +32,7 @@ eventseries.listing: eventinstance.listing: title: 'Event Instances' description: 'Event instance listing.' - route_name: entity.eventinstance.collection + route_name: entity.eventinstance.admin_collection parent: events.admin.content weight: 3 @@ -50,4 +50,28 @@ eventinstance.admin.structure.settings: description: 'Configure Event Instance Entity' route_name: eventinstance.settings parent: events.admin.overview + weight: 2 + +# Events Series types admin page. +entity.eventseries_type.collection: + title: 'Event Series Types' + description: 'Configure Event Series Types' + route_name: entity.eventseries_type.collection + parent: events.admin.overview weight: 1 + +# Event Series types add page. +entity.eventseries_type.add_form: + title: 'Add Series Type' + description: 'Add An Event Series Type' + route_name: entity.eventseries_type.add_form + parent: entity.eventseries_type.collection + weight: -99 + +# Events Instance types admin page. +entity.eventinstance_type.collection: + title: 'Event Instance Types' + description: 'Configure Event Instance Types' + route_name: entity.eventinstance_type.collection + parent: events.admin.overview + weight: 3 diff --git a/recurring_events.links.task.yml b/recurring_events.links.task.yml index 6b27e3dc09a9aa6f9117e8cec1fdd91dba1008ee..00e21a83cda54d79754061c10f8e2ad3964e9273 100644 --- a/recurring_events.links.task.yml +++ b/recurring_events.links.task.yml @@ -94,12 +94,6 @@ entity.eventinstance.settings: title: Event Instance Settings base_route: eventinstance.settings -# Field Inheritance settings admin page. -entity.field_inheritance.collection: - route_name: entity.field_inheritance.collection - title: Field Inheritance - base_route: eventinstance.settings - # Excluded dates settings admin page. entity.excluded_dates.collection: route_name: entity.excluded_dates.collection @@ -110,4 +104,4 @@ entity.excluded_dates.collection: entity.included_dates.collection: route_name: entity.included_dates.collection title: Included dates - base_route: eventseries.settings \ No newline at end of file + base_route: eventseries.settings diff --git a/recurring_events.module b/recurring_events.module index 3145ca1a5df19dc215ff108fcf20aa87921a6bb6..b305b87fc5d93e419702acf665607bab56b36806 100644 --- a/recurring_events.module +++ b/recurring_events.module @@ -8,14 +8,16 @@ use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Render\Element; -use Drupal\Core\Entity\EntityTypeInterface; -use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Form\FormStateInterface; use Drupal\recurring_events\Entity\EventSeries; +use Drupal\recurring_events\EventInterface; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Url; +use Drupal\Core\Link; +use Drupal\Core\Entity\EntityForm; /** * Implements hook_help(). @@ -101,57 +103,6 @@ function recurring_events_help($route_name, RouteMatchInterface $route_match) { } } -/** - * Implements hook_entity_base_field_info_alter(). - */ -function recurring_events_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) { - if ($entity_type->id() === 'eventinstance') { - $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple(); - if (!empty($inherited_fields)) { - foreach ($inherited_fields as $field) { - $settings = [ - 'source field' => $field->sourceField(), - 'method' => $field->type(), - 'plugin' => $field->plugin(), - ]; - - if ($field->entityField()) { - $settings['entity field'] = $field->entityField(); - } - - $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('eventseries', 'eventseries'); - - $type = 'string'; - if (!empty($field_definitions[$field->sourceField()])) { - $settings = array_merge($settings, $field_definitions[$field->sourceField()]->getSettings()); - $type = $field_definitions[$field->sourceField()]->getType(); - } - - $class = '\Drupal\recurring_events\FieldInheritanceFactory'; - if ($field->plugin() === 'entity_reference_inheritance') { - $class = '\Drupal\recurring_events\EntityReferenceFieldInheritanceFactory'; - } - - // Allow developers to override the class to use for a field. - \Drupal::moduleHandler()->alter('recurring_events_inheritance_class', $class, $field); - - $fields[$field->id()] = BaseFieldDefinition::create($type) - ->setLabel(t('Inherited @label', ['@label' => $field->label()])) - ->setName($field->id()) - ->setDescription(t('The inherited field: @field', ['@field' => $field->label()])) - ->setComputed(TRUE) - ->setClass($class) - ->setSettings($settings) - ->setTargetEntityTypeId($entity_type->id()) - ->setTranslatable(FALSE) - ->setRevisionable(FALSE) - ->setReadOnly(TRUE) - ->setDisplayConfigurable('view', TRUE); - } - } - } -} - /** * Implements hook_entity_operation(). */ @@ -184,6 +135,10 @@ function recurring_events_theme() { 'template' => 'eventseries', ]; + $theme['eventseries_add_list'] = [ + 'variables' => ['content' => NULL], + ]; + return $theme; } @@ -221,6 +176,30 @@ function template_preprocess_eventseries(array &$variables) { } } +/** + * Prepares variables for list of available eventseries type templates. + * + * Default template: eventseries-add-list.html.twig. + * + * @param array $variables + * An associative array containing: + * - content: An array of eventseries types. + */ +function template_preprocess_eventseries_add_list(array &$variables) { + $variables['types'] = []; + if (!empty($variables['content'])) { + foreach ($variables['content'] as $type) { + $variables['types'][$type->id()] = [ + 'type' => $type->id(), + 'add_link' => Link::fromTextAndUrl($type->label(), new Url('entity.eventseries.add_form', ['eventseries_type' => $type->id()])), + 'description' => [ + '#markup' => $type->getDescription(), + ], + ]; + } + } +} + /** * Implements hook_ENTITY_TYPE_presave(). */ @@ -253,18 +232,240 @@ function recurring_events_eventseries_insert(EntityInterface $entity) { if (empty($instance->eventseries_id->value)) { $instance->set('eventseries_id', $entity->id()); $instance->setNewRevision(FALSE); + + // Configure the field inheritances for this instance. + $entity_type = $instance->getEntityTypeId(); + $bundle = $instance->bundle(); + $inherited_field_ids = \Drupal::entityQuery('field_inheritance') + ->condition('sourceEntityType', 'eventseries') + ->condition('destinationEntityType', $entity_type) + ->condition('destinationEntityBundle', $bundle) + ->execute(); + + if (!empty($inherited_field_ids)) { + $state_key = $entity_type . ':' . $instance->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(); + $state_values[$name] = [ + 'entity' => $instance->getEventSeries()->id(), + ]; + } + } + $state->set($state_key, $state_values); + } + $instance->save(); } } } } +/** + * Implements hook_ENTITY_TYPE_insert(). + */ +function recurring_events_eventseries_type_insert(EntityInterface $entity) { + // Event series types are tied to event instance types, and optionally + // registrant types. Therefore, we need to create equivalent instance and + // registrant types every time an event series type is created. + $series_type_label = $entity->label(); + $series_type_description = $entity->getDescription(); + $series_type_id = $entity->id(); + + $instance_types = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->load($series_type_id); + if (empty($instance_types)) { + $instance_type = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->create([ + 'id' => $series_type_id, + 'label' => $series_type_label, + 'description' => $series_type_description, + ]); + $instance_type->save(); + + $instance_title = \Drupal::entityTypeManager()->getStorage('field_inheritance')->create([ + 'id' => 'title', + 'label' => 'Title', + 'type' => 'inherit', + 'sourceEntityType' => 'eventseries', + 'sourceEntityBundle' => $series_type_id, + 'sourceField' => 'title', + 'destinationEntityType' => 'eventinstance', + 'destinationEntityBundle' => $series_type_id, + 'plugin' => 'default_inheritance', + ]); + $instance_title->save(); + + $instance_description = \Drupal::entityTypeManager()->getStorage('field_inheritance')->create([ + 'id' => 'description', + 'label' => 'Description', + 'type' => 'append', + 'sourceEntityType' => 'eventseries', + 'sourceEntityBundle' => $series_type_id, + 'sourceField' => 'body', + 'destinationEntityType' => 'eventinstance', + 'destinationEntityBundle' => $series_type_id, + 'destinationField' => 'body', + 'plugin' => 'default_inheritance', + ]); + $instance_description->save(); + } + + if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) { + $registrant_types = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($series_type_id); + if (empty($registrant_types)) { + $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->create([ + 'id' => $series_type_id, + 'label' => $series_type_label, + 'description' => $series_type_description, + ]); + $registrant_type->save(); + } + } + + \Drupal::cache('menu')->invalidateAll(); + \Drupal::service('plugin.manager.menu.link')->rebuild(); +} + +/** + * Implements hook_ENTITY_TYPE_delete(). + */ +function recurring_events_eventseries_type_delete(EntityInterface $entity) { + // Event series types are tied to event instance types, and optionally + // registrant types. Therefore, we need to delete equivalent instance and + // registrant types every time an event series type is deleted. We also must + // delete all inheritances that use these types as either the source or the + // destination. + $query = \Drupal::entityQuery('field_inheritance'); + $and_destination = $query->andConditionGroup() + ->condition('destinationEntityType', 'eventseries') + ->condition('destinationEntityBundle', $entity->id()); + $and_source = $query->andConditionGroup() + ->condition('sourceEntityType', 'eventseries') + ->condition('sourceEntityBundle', $entity->id()); + $or = $query->orConditionGroup() + ->condition($and_destination) + ->condition($and_source); + $query->condition($or); + $inherited_field_ids = $query->execute(); + + if (!empty($inherited_field_ids)) { + $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids); + foreach ($inherited_fields as $field) { + $field->delete(); + } + } + + $instance_type = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->load($entity->id()); + if (!empty($instance_type)) { + $query = \Drupal::entityQuery('field_inheritance'); + $and_destination = $query->andConditionGroup() + ->condition('destinationEntityType', 'eventinstance') + ->condition('destinationEntityBundle', $instance_type->id()); + $and_source = $query->andConditionGroup() + ->condition('sourceEntityType', 'eventinstance') + ->condition('sourceEntityBundle', $instance_type->id()); + $or = $query->orConditionGroup() + ->condition($and_destination) + ->condition($and_source); + $query->condition($or); + $inherited_field_ids = $query->execute(); + + if (!empty($inherited_field_ids)) { + $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids); + foreach ($inherited_fields as $field) { + $field->delete(); + } + } + $instance_type->delete(); + } + + if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) { + $registrant_type = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($entity->id()); + if (!empty($registrant_type)) { + $query = \Drupal::entityQuery('field_inheritance'); + $and_destination = $query->andConditionGroup() + ->condition('destinationEntityType', 'registrant') + ->condition('destinationEntityBundle', $registrant_type->id()); + $and_source = $query->andConditionGroup() + ->condition('sourceEntityType', 'registrant') + ->condition('sourceEntityBundle', $registrant_type->id()); + $or = $query->orConditionGroup() + ->condition($and_destination) + ->condition($and_source); + $query->condition($or); + $inherited_field_ids = $query->execute(); + + if (!empty($inherited_field_ids)) { + $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids); + foreach ($inherited_fields as $field) { + $field->delete(); + } + } + $registrant_type->delete(); + } + } +} + +/** + * Implements hook_entity_operation_alter(). + */ +function recurring_events_entity_operation_alter(array &$operations, EntityInterface $entity) { + if ($entity->getEntityTypeId() == 'eventinstance_type') { + if (!empty($operations['delete'])) { + unset($operations['delete']); + } + } +} + +/** + * Implements hook_form_alter(). + */ +function recurring_events_form_alter(&$form, FormStateInterface $form_state, $form_id) { + $form_object = $form_state->getFormObject(); + if (!empty($form_object) && $form_object instanceof EntityForm) { + $entity = $form_state->getFormObject()->getEntity(); + if (!empty($entity) && $entity instanceof FieldableEntityInterface && strpos($form['#id'], 'delete') === FALSE) { + $entity_type = $entity->getEntityTypeId(); + $bundle = $entity->bundle(); + if ($entity_type == 'eventinstance') { + $series = $entity->getEventSeries(); + $inherited_field_ids = \Drupal::entityQuery('field_inheritance') + ->condition('destinationEntityType', $entity_type) + ->condition('destinationEntityBundle', $bundle) + ->execute(); + + if (!empty($inherited_field_ids)) { + $state_key = $entity->getEntityTypeId() . ':' . $entity->uuid(); + $state = \Drupal::keyValue('field_inheritance'); + $state_values = $state->get($state_key); + + $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple($inherited_field_ids); + if (!isset($state_values['enabled'])) { + $form['field_inheritance']['field_inheritance_enable']['#default_value'] = TRUE; + } + foreach ($inherited_fields as $field) { + if (!isset($state_values[$field->idWithoutTypeAndBundle()]) && !isset($state_values[$field->idWithoutTypeAndBundle()]['skip'])) { + $form['field_inheritance']['fields']['field_inheritance_' . $field->idWithoutTypeAndBundle()]['field_inheritance_field_entity_' . $field->idWithoutTypeAndBundle()]['#default_value'] = $series; + } + } + } + } + } + } +} + /** * Implements hook_form_FORM_ID_alter(). */ function recurring_events_form_content_moderation_entity_moderation_form_alter(&$form, FormStateInterface $form_state) { $entity = $form_state->get('entity'); - if ($entity->getEntityTypeId() === 'eventseries') { + if ($entity instanceof EventInterface && $entity->getEntityTypeId() === 'eventseries') { $original = \Drupal::entityTypeManager()->getStorage('eventseries')->load($entity->id()); $creation_service = \Drupal::service('recurring_events.event_creation_service'); if ($creation_service->checkForOriginalRecurConfigChanges($entity, $original)) { @@ -391,12 +592,12 @@ function recurring_events_recurring_events_event_instances_pre_create_alter(arra $end = $dates['end_date']->getTimestamp(); for ($x = 0; $x < (count($include) - 1); $x++) { - $include_start = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $include[$x]['value'] . 'T00:00:00'); - $include_start = $include_start->getTimestamp(); + $included_start = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $include[$x]['value'] . 'T00:00:00'); + $included_start = $included_start->getTimestamp(); $included_end = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $include[$x]['end_value'] . 'T23:59:59'); $included_end = $included_end->getTimestamp(); - if ($start >= $include_start && $start <= $included_end && $end >= $included_start && $end <= $included_end) { + if ($start >= $included_start && $start <= $included_end && $end >= $included_start && $end <= $included_end) { // This event is in the inclusion range, so move on to the next one. break; } @@ -419,7 +620,7 @@ function recurring_events_recurring_events_event_instances_pre_create_alter(arra function recurring_events_allowed_values_function(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) { $values = ['custom' => t('Custom Event')]; $fields = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions('eventseries'); - foreach ($fields as $field_name => $field) { + foreach ($fields as $field) { $field_definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field->getType()); $class = new \ReflectionClass($field_definition['class']); if ($class->implementsInterface('\Drupal\recurring_events\RecurringEventsFieldTypeInterface')) { @@ -443,3 +644,35 @@ function recurring_events_recurring_events_recur_field_types_alter(&$fields) { } } } + +/** + * Implements hook_theme_suggestions_HOOK(). + */ +function recurring_events_theme_suggestions_eventseries(array $variables) { + $suggestions = []; + $entity = $variables['elements']['#eventseries']; + $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_'); + + $suggestions[] = 'eventseries__' . $sanitized_view_mode; + $suggestions[] = 'eventseries__' . $entity->bundle(); + $suggestions[] = 'eventseries__' . $entity->bundle() . '__' . $sanitized_view_mode; + $suggestions[] = 'eventseries__' . $entity->id(); + $suggestions[] = 'eventseries__' . $entity->id() . '__' . $sanitized_view_mode; + return $suggestions; +} + +/** + * Implements hook_theme_suggestions_HOOK(). + */ +function recurring_events_theme_suggestions_eventinstance(array $variables) { + $suggestions = []; + $entity = $variables['elements']['#eventinstance']; + $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_'); + + $suggestions[] = 'eventinstance__' . $sanitized_view_mode; + $suggestions[] = 'eventinstance__' . $entity->bundle(); + $suggestions[] = 'eventinstance__' . $entity->bundle() . '__' . $sanitized_view_mode; + $suggestions[] = 'eventinstance__' . $entity->id(); + $suggestions[] = 'eventinstance__' . $entity->id() . '__' . $sanitized_view_mode; + return $suggestions; +} diff --git a/recurring_events.permissions.yml b/recurring_events.permissions.yml index 922f473387ad302f45665b8ac9c0ecb8c0a2b7c6..76e212749bea2864d75e1bc0e1ba3dfa9496db93 100644 --- a/recurring_events.permissions.yml +++ b/recurring_events.permissions.yml @@ -77,4 +77,16 @@ access eventseries overview: # Event Instance Administration. access eventinstance overview: title: 'Access the eventinstance overview page' - description: 'View the table view of eventinstance' \ No newline at end of file + description: 'View the table view of eventinstance' + +# Event Series Types Administration. +administer eventseries types: + title: 'Administer eventseries types' + description: 'Manage types of eventseries.' + restrict access: true + +# Event Instance Types Administration. +administer eventinstance types: + title: 'Administer eventinstance types' + description: 'Manage types of eventinstance.' + restrict access: true diff --git a/recurring_events.routing.yml b/recurring_events.routing.yml index 3333a2503d1c88c449c2f56be74153a0076fb8b8..e23c6d1f61c374d1bbef0bccebb34c049a9e46d3 100644 --- a/recurring_events.routing.yml +++ b/recurring_events.routing.yml @@ -14,10 +14,23 @@ entity.eventseries.canonical: # Add an EventSeries. entity.eventseries.add_form: - path: '/events/add' + path: '/events/add/{eventseries_type}' defaults: _entity_form: eventseries.add - _title: 'Add Event' + _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::addPageTitle' + requirements: + _entity_create_access: 'eventseries' + options: + parameters: + eventseries_type: + type: entity:eventseries_type + +# Add an EventSeries. +entity.eventseries.add_page: + path: '/events/add' + defaults: + _title: 'Add event' + _controller: '\Drupal\recurring_events\Controller\EventSeriesController::addPage' requirements: _entity_create_access: 'eventseries' @@ -26,7 +39,7 @@ entity.eventseries.edit_form: path: '/events/series/{eventseries}/edit' defaults: _entity_form: eventseries.edit - _title: 'Edit Event Series' + _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::editPageTitle' requirements: _entity_access: 'eventseries.edit' eventseries: \d+ @@ -40,7 +53,7 @@ entity.eventseries.delete_form: path: '/events/series/{eventseries}/delete' defaults: _entity_form: eventseries.delete - _title: 'Delete Event' + _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::deletePageTitle' requirements: _entity_access: 'eventseries.delete' eventseries: \d+ @@ -54,7 +67,7 @@ entity.eventseries.clone_form: path: '/events/series/{eventseries}/clone' defaults: _entity_form: eventseries.clone - _title: 'Clone Event Series' + _title_callback: '\Drupal\recurring_events\Controller\EventSeriesController::clonePageTitle' requirements: _entity_access: 'eventseries.clone' eventseries: \d+ @@ -187,6 +200,8 @@ entity.eventseries.admin_collection: requirements: # Checks for permission directly. _permission: 'access eventseries overview' + options: + _admin_route: TRUE # Event Series admin table list route. entity.eventinstance.admin_collection: @@ -196,4 +211,28 @@ entity.eventinstance.admin_collection: _title: 'Event Instances' requirements: # Checks for permission directly. - _permission: 'access eventinstance overview' \ No newline at end of file + _permission: 'access eventinstance overview' + options: + _admin_route: TRUE + +# Event Series types route. +entity.eventseries_type.collection: + path: '/admin/structure/events/series/types' + defaults: + _entity_list: 'eventseries_type' + _title: 'Event Series types' + requirements: + _permission: 'administer eventseries types' + options: + _admin_route: TRUE + +# Event Instance types route. +entity.eventinstance_type.collection: + path: '/admin/structure/events/instance/types' + defaults: + _entity_list: 'eventinstance_type' + _title: 'Event Instance types' + requirements: + _permission: 'administer eventinstance types' + options: + _admin_route: TRUE diff --git a/recurring_events.services.yml b/recurring_events.services.yml index 7f36cbbac181ab108207793fa8504d46c7766e96..41b953f28323dec97a740195de625ee97094886d 100644 --- a/recurring_events.services.yml +++ b/recurring_events.services.yml @@ -1,7 +1,4 @@ services: recurring_events.event_creation_service: class: Drupal\recurring_events\EventCreationService - arguments: ['@string_translation', '@database', '@logger.factory', '@messenger', '@plugin.manager.field.field_type', '@entity_field.manager'] - plugin.manager.field_inheritance: - class: Drupal\recurring_events\FieldInheritancePluginManager - parent: default_plugin_manager + arguments: ['@string_translation', '@database', '@logger.factory', '@messenger', '@plugin.manager.field.field_type', '@entity_field.manager', '@module_handler', '@entity_type.manager'] diff --git a/recurring_events.tokens.inc b/recurring_events.tokens.inc index 3008e86540817e044c88838d613f0b4ef7b88925..95dcb9350d829c7fa4aabef871585da81b7a2a95 100644 --- a/recurring_events.tokens.inc +++ b/recurring_events.tokens.inc @@ -81,7 +81,7 @@ function recurring_events_tokens($type, $tokens, array $data, array $options, Bu if ($type == 'eventinstance' && !empty($data['eventinstance'])) { $event_instance = $data['eventinstance']; $date_format = \Drupal::config('recurring_events.eventinstance.config')->get('date_format'); - $timezone = new \DateTimeZone(drupal_get_user_timezone()); + $timezone = new \DateTimeZone(date_default_timezone_get()); foreach ($tokens as $name => $original) { switch ($name) { case 'title': diff --git a/recurring_events.views.inc b/recurring_events.views.inc index f64c0b95dfa95f4c180c4470454a227c36da0ecc..a7d37d7fd0a70214756843ad3e3394029e232215 100644 --- a/recurring_events.views.inc +++ b/recurring_events.views.inc @@ -29,30 +29,22 @@ function recurring_events_views_data_alter(array &$data) { ], ]; - // Create a views field for each of the inherited fields. - $inherited_fields = \Drupal::entityTypeManager()->getStorage('field_inheritance')->loadMultiple(); - $set = FALSE; - if (!empty($inherited_fields)) { - foreach ($inherited_fields as $field) { - if ($field->id() == 'title') { - $data['eventinstance_field_data']['table']['base']['defaults']['field'] = 'title'; - $set = TRUE; - } - $data['eventinstance_field_data'][$field->id()] = [ - 'title' => $field->label(), - 'field' => [ - 'title' => $field->label(), - 'help' => t('The inherited @field field', [ - '@field' => $field->label(), - ]), - 'id' => 'inherited_field', - 'field_name' => $field->id(), - ], - ]; - } - } + // Set the default field for a view based on eventinstances. + $data['eventinstance_field_data']['table']['base']['defaults']['field'] = 'id'; - if (!$set) { - $data['eventinstance_field_data']['table']['base']['defaults']['field'] = 'id'; - } + // @todo Remove these declarations when + // https://www.drupal.org/project/drupal/issues/2489476 is resolved. + $data['eventinstance_field_data']['date__value']['filter']['id'] = 'datetime'; + $data['eventinstance_field_data']['date__value']['filter']['field_name'] = 'date'; + $data['eventinstance_field_data']['date__value']['sort']['id'] = 'datetime'; + $data['eventinstance_field_data']['date__value']['sort']['field_name'] = 'date'; + $data['eventinstance_field_data']['date__value']['argument']['id'] = 'datetime'; + $data['eventinstance_field_data']['date__value']['argument']['field_name'] = 'date'; + + $data['eventinstance_field_data']['date__end_value']['filter']['id'] = 'datetime'; + $data['eventinstance_field_data']['date__end_value']['filter']['field_name'] = 'date'; + $data['eventinstance_field_data']['date__end_value']['sort']['id'] = 'datetime'; + $data['eventinstance_field_data']['date__end_value']['sort']['field_name'] = 'date'; + $data['eventinstance_field_data']['date__end_value']['argument']['id'] = 'datetime'; + $data['eventinstance_field_data']['date__end_value']['argument']['field_name'] = 'date'; } diff --git a/src/Annotation/FieldInheritance.php b/src/Annotation/FieldInheritance.php deleted file mode 100644 index bfaa78fbe138c6924897a354bde718522926ab62..0000000000000000000000000000000000000000 --- a/src/Annotation/FieldInheritance.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Annotation; - -use Drupal\Component\Annotation\Plugin; - -/** - * Defines a field inheritance plugin annotation object. - * - * @Annotation - */ -class FieldInheritance extends Plugin { - - /** - * The plugin ID. - * - * @var string - */ - public $id; - - /** - * The name of the form plugin. - * - * @var \Drupal\Core\Annotation\Translation - * - * @ingroup plugin_translatable - */ - public $name; - - /** - * An array of field types the inheritance plugin supports. - * - * @var array - */ - public $types = []; - -} diff --git a/src/Controller/EventInstanceController.php b/src/Controller/EventInstanceController.php index 45bcdb0c86f925c336fbbba740e254597dc113e6..14965a98ba19311b185abc8ea16e9c4d7e6886c7 100644 --- a/src/Controller/EventInstanceController.php +++ b/src/Controller/EventInstanceController.php @@ -96,9 +96,17 @@ class EventInstanceController extends ControllerBase implements ContainerInjecti * The title of the page. */ public function getTitle(EventInterface $eventinstance) { - $title = $eventinstance->title->value; + $title = ''; + $value = $eventinstance->get('title')->getValue(); + if (!empty($value[0]['value'])) { + $title = $value[0]['value']; + } + if ($eventinstance->hasTranslation($this->langCode)) { - $title = $eventinstance->getTranslation($this->langCode)->title->value; + $value = $eventinstance->getTranslation($this->langCode)->get('title')->getValue(); + if (!empty($value[0]['value'])) { + $title = $value[0]['value']; + } } return $title; } diff --git a/src/Controller/EventSeriesController.php b/src/Controller/EventSeriesController.php index 1b495b185809d6b23fcc15ec918c0b985e1802de..75a95fe76645122502532e1be58b2f781b5ec189 100644 --- a/src/Controller/EventSeriesController.php +++ b/src/Controller/EventSeriesController.php @@ -12,6 +12,7 @@ use Drupal\recurring_events\EventInterface; use Drupal\Component\Utility\Xss; use Drupal\Core\Url; use Drupal\Core\Link; +use Drupal\recurring_events\Entity\EventSeriesTypeInterface; /** * The EventSeriesController class. @@ -80,6 +81,124 @@ class EventSeriesController extends ControllerBase implements ContainerInjection return $this->systemManager->getBlockContents(); } + /** + * Displays add content links for available event series types. + * + * Redirects to events/add/[type] if only one type is available. + * + * @return array|\Symfony\Component\HttpFoundation\RedirectResponse + * A render array for a list of the node types that can be added; however, + * if there is only one node type defined for the site, the function + * will return a RedirectResponse to the node add page for that one node + * type. + */ + public function addPage() { + $build = [ + '#theme' => 'eventseries_add_list', + '#cache' => [ + 'tags' => $this->entityTypeManager()->getDefinition('eventseries_type')->getListCacheTags(), + ], + ]; + + $content = []; + + // Only use eventseries types the user has access to. + foreach ($this->entityTypeManager()->getStorage('eventseries_type')->loadMultiple() as $type) { + $access = $this->entityTypeManager()->getAccessControlHandler('eventseries')->createAccess($type->id(), NULL, [], TRUE); + if ($access->isAllowed()) { + $content[$type->id()] = $type; + } + $this->renderer->addCacheableDependency($build, $access); + } + + // Bypass the node/add listing if only one content type is available. + if (count($content) == 1) { + $type = array_shift($content); + return $this->redirect('entity.eventseries.add_form', ['eventseries_type' => $type->id()]); + } + + $build['#content'] = $content; + + return $build; + } + + /** + * Create a new event. + * + * @param \Drupal\recurring_events\Entity\EventSeriesTypeInterface $eventseries_type + * The eventseries type. + */ + public function add(EventSeriesTypeInterface $eventseries_type) { + $eventseries = $this->entityTypeManager()->getStorage('eventseries')->create([ + 'type' => $eventseries_type->id(), + ]); + + $form = $this->entityFormBuilder()->getForm($eventseries); + + return $form; + } + + /** + * The _title_callback for the entity.eventseries.add_form route. + * + * @param \Drupal\recurring_events\Entity\EventSeriesTypeInterface $eventseries_type + * The eventseries type. + * + * @return string + * The page title. + */ + public function addPageTitle(EventSeriesTypeInterface $eventseries_type) { + return $this->t('Create %name Event', ['%name' => $eventseries_type->label()]); + } + + /** + * The _title_callback for the entity.eventseries.edit_form route. + * + * @param \Drupal\recurring_events\EventInterface $eventseries + * The eventseries type. + * + * @return string + * The page title. + */ + public function editPageTitle(EventInterface $eventseries) { + return $this->t('Edit %type Event %title', [ + '%type' => $eventseries->bundle(), + '%title' => $eventseries->label(), + ]); + } + + /** + * The _title_callback for the entity.eventseries.delete_form route. + * + * @param \Drupal\recurring_events\EventInterface $eventseries + * The eventseries type. + * + * @return string + * The page title. + */ + public function deletePageTitle(EventInterface $eventseries) { + return $this->t('Delete %type Event %title', [ + '%type' => $eventseries->bundle(), + '%title' => $eventseries->label(), + ]); + } + + /** + * The _title_callback for the entity.eventseries.clone_form route. + * + * @param \Drupal\recurring_events\EventInterface $eventseries + * The eventseries type. + * + * @return string + * The page title. + */ + public function clonePageTitle(EventInterface $eventseries) { + return $this->t('Clone %type Event %title', [ + '%type' => $eventseries->bundle(), + '%title' => $eventseries->label(), + ]); + } + /** * Displays an eventseries revision. * diff --git a/src/Entity/EventInstance.php b/src/Entity/EventInstance.php index 2b93988e92512df862d25fc3e586c6ac01714afa..095cb3f482f1f7df601903133a93ba739bdae306 100644 --- a/src/Entity/EventInstance.php +++ b/src/Entity/EventInstance.php @@ -96,13 +96,15 @@ use Drupal\user\UserInterface; * translatable = TRUE, * admin_permission = "administer eventinstance entity", * fieldable = TRUE, + * bundle_entity_type = "eventinstance_type", * entity_keys = { * "id" = "id", * "revision" = "vid", * "published" = "status", * "langcode" = "langcode", * "uuid" = "uuid", - * "label" = "title" + * "label" = "title", + * "bundle" = "type", * }, * revision_metadata_keys = { * "revision_user" = "revision_uid", @@ -122,7 +124,7 @@ use Drupal\user\UserInterface; * "revision_delete" = "/events/{eventinstance}/revisions/{eventinstance_revision}/delete", * "translation_revert" = "/events/{eventinstance}/revisions/{eventinstance_revision}/revert/{langcode}", * }, - * field_ui_base_route = "eventinstance.settings", + * field_ui_base_route = "entity.eventinstance_type.edit_form", * ) * * The 'links' above are defined by their path. For core to find the @@ -203,6 +205,13 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface } } + /** + * {@inheritdoc} + */ + public function getType() { + return $this->bundle(); + } + /** * {@inheritdoc} */ @@ -270,21 +279,6 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface return $this; } - /** - * {@inheritdoc} - */ - public function getRevisionAuthor() { - return $this->getRevisionUser(); - } - - /** - * {@inheritdoc} - */ - public function setRevisionAuthorId($uid) { - $this->setRevisionUserId($uid); - return $this; - } - /** * {@inheritdoc} * @@ -318,6 +312,7 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface 'match_operator' => 'CONTAINS', 'size' => '60', 'placeholder' => '', + 'match_limit' => 10, ], ]) ->setDisplayConfigurable('form', TRUE); @@ -328,6 +323,12 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface ->setDescription(t('The UUID of the event entity.')) ->setReadOnly(TRUE); + $fields['type'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Type')) + ->setDescription(t('The eventinstance type.')) + ->setSetting('target_type', 'eventinstance_type') + ->setReadOnly(TRUE); + $fields['body'] = BaseFieldDefinition::create('text_long') ->setLabel(t('Body')) ->setTranslatable(TRUE) @@ -388,7 +389,7 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface 'settings' => [ 'display_label' => TRUE, ], - 'weight' => 120, + 'weight' => 12, ]) ->setDisplayConfigurable('form', TRUE); diff --git a/src/Entity/EventInstanceType.php b/src/Entity/EventInstanceType.php new file mode 100644 index 0000000000000000000000000000000000000000..3167b860d29a0f5b4ca639d055c553c80611140f --- /dev/null +++ b/src/Entity/EventInstanceType.php @@ -0,0 +1,80 @@ +<?php + +namespace Drupal\recurring_events\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityBundleBase; + +/** + * Defines the Event instance type entity. + * + * @ConfigEntityType( + * id = "eventinstance_type", + * label = @Translation("Event instance type"), + * handlers = { + * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", + * "list_builder" = "Drupal\recurring_events\EventInstanceTypeListBuilder", + * "form" = { + * "edit" = "Drupal\recurring_events\Form\EventInstanceTypeForm", + * }, + * "route_provider" = { + * "html" = "Drupal\recurring_events\EventInstanceTypeHtmlRouteProvider", + * }, + * }, + * config_prefix = "eventinstance_type", + * bundle_of = "eventinstance", + * admin_permission = "administer eventinstance entity", + * entity_keys = { + * "id" = "id", + * "label" = "label", + * "uuid" = "uuid" + * }, + * links = { + * "canonical" = "/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}", + * "edit-form" = "/admin/structure/events/instance/types/eventinstance_type/{eventinstance_type}/edit", + * "collection" = "/admin/structure/events/instance/types/eventinstance_type" + * }, + * config_export = { + * "label", + * "id", + * "description", + * } + * ) + */ +class EventInstanceType extends ConfigEntityBundleBase implements EventInstanceTypeInterface { + + /** + * The Event instance type ID. + * + * @var string + */ + protected $id; + + /** + * The Event instance type label. + * + * @var string + */ + protected $label; + + /** + * A brief description of this eventinstance type. + * + * @var string + */ + protected $description; + + /** + * {@inheritdoc} + */ + public function id() { + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->description; + } + +} diff --git a/src/Entity/EventInstanceTypeInterface.php b/src/Entity/EventInstanceTypeInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..fdfabb02594397b99a946716e57bf92f5148fbc8 --- /dev/null +++ b/src/Entity/EventInstanceTypeInterface.php @@ -0,0 +1,20 @@ +<?php + +namespace Drupal\recurring_events\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityInterface; + +/** + * Provides an interface for defining Event instance type entities. + */ +interface EventInstanceTypeInterface extends ConfigEntityInterface { + + /** + * Gets the description. + * + * @return string + * The description of this eventinstance type. + */ + public function getDescription(); + +} diff --git a/src/Entity/EventSeries.php b/src/Entity/EventSeries.php index c1573172de32d88dc3d1a637062ca20c9558cf32..024b78e858ffc35fe3f866d43b8d792580faffa9 100644 --- a/src/Entity/EventSeries.php +++ b/src/Entity/EventSeries.php @@ -96,13 +96,15 @@ use Drupal\user\UserInterface; * translatable = TRUE, * admin_permission = "administer eventseries entity", * fieldable = TRUE, + * bundle_entity_type = "eventseries_type", * entity_keys = { * "id" = "id", * "revision" = "vid", * "published" = "status", * "langcode" = "langcode", * "label" = "title", - * "uuid" = "uuid" + * "uuid" = "uuid", + * "bundle" = "type", * }, * revision_metadata_keys = { * "revision_user" = "revision_uid", @@ -111,6 +113,8 @@ use Drupal\user\UserInterface; * }, * links = { * "canonical" = "/events/series/{eventseries}", + * "add-page" = "/events/add", + * "add-form" = "/events/add/{eventseries_type}", * "edit-form" = "/events/series/{eventseries}/edit", * "delete-form" = "/events/series/{eventseries}/delete", * "collection" = "/events/series", @@ -122,7 +126,7 @@ use Drupal\user\UserInterface; * "revision_delete" = "/events/series/{eventseries}/revisions/{eventseries_revision}/delete", * "translation_revert" = "/events/series/{eventseries}/revisions/{eventseries_revision}/revert/{langcode}", * }, - * field_ui_base_route = "eventseries.settings", + * field_ui_base_route = "entity.eventseries_type.edit_form", * ) * * The 'links' above are defined by their path. For core to find the @@ -202,6 +206,13 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { } } + /** + * {@inheritdoc} + */ + public function getType() { + return $this->bundle(); + } + /** * {@inheritdoc} */ @@ -269,21 +280,6 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { return $this; } - /** - * {@inheritdoc} - */ - public function getRevisionAuthor() { - return $this->getRevisionUser(); - } - - /** - * {@inheritdoc} - */ - public function setRevisionAuthorId($uid) { - $this->setRevisionUserId($uid); - return $this; - } - /** * {@inheritdoc} * @@ -311,11 +307,12 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setTranslatable(TRUE) ->setDisplayOptions('form', [ 'type' => 'entity_reference_autocomplete', - 'weight' => 5, + 'weight' => 11, 'settings' => [ 'match_operator' => 'CONTAINS', 'size' => '60', 'placeholder' => '', + 'match_limit' => 10, ], ]) ->setDisplayConfigurable('form', TRUE); @@ -325,6 +322,12 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setDescription(t('The UUID of the event entity.')) ->setReadOnly(TRUE); + $fields['type'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Type')) + ->setDescription(t('The eventseries type.')) + ->setSetting('target_type', 'eventseries_type') + ->setReadOnly(TRUE); + // Title field for the event. $fields['title'] = BaseFieldDefinition::create('string') ->setLabel(t('Title')) @@ -336,11 +339,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ]) ->setDisplayOptions('form', [ 'type' => 'string_textfield', - 'weight' => -6, + 'weight' => 0, ]) ->setDisplayOptions('view', [ 'label' => 'above', - 'weight' => 10, + 'weight' => 0, ]) ->setDisplayConfigurable('form', TRUE) ->setDisplayConfigurable('view', TRUE) @@ -356,11 +359,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setDisplayConfigurable('view', TRUE) ->setDisplayOptions('form', [ 'type' => 'text_textarea', - 'weight' => -4, + 'weight' => 1, ]) ->setDisplayOptions('view', [ 'label' => 'above', - 'weight' => 10, + 'weight' => 1, ]) ->setDisplayConfigurable('form', TRUE); @@ -376,11 +379,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setSetting('allowed_values_function', 'recurring_events_allowed_values_function') ->setDisplayOptions('form', [ 'type' => 'options_buttons', - 'weight' => 0, + 'weight' => 2, ]) ->setDisplayOptions('view', [ 'label' => 'above', - 'weight' => 10, + 'weight' => 2, ]); $fields['consecutive_recurring_date'] = BaseFieldDefinition::create('consecutive_recurring_date') @@ -394,7 +397,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setRequired(FALSE) ->setDisplayOptions('form', [ 'type' => 'consecutive_recurring_date', - 'weight' => 1, + 'weight' => 3, ]); $fields['daily_recurring_date'] = BaseFieldDefinition::create('daily_recurring_date') @@ -408,7 +411,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setRequired(FALSE) ->setDisplayOptions('form', [ 'type' => 'daily_recurring_date', - 'weight' => 2, + 'weight' => 4, ]); $fields['weekly_recurring_date'] = BaseFieldDefinition::create('weekly_recurring_date') @@ -422,7 +425,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setRequired(FALSE) ->setDisplayOptions('form', [ 'type' => 'weekly_recurring_date', - 'weight' => 3, + 'weight' => 5, ]); $fields['monthly_recurring_date'] = BaseFieldDefinition::create('monthly_recurring_date') @@ -436,7 +439,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setRequired(FALSE) ->setDisplayOptions('form', [ 'type' => 'monthly_recurring_date', - 'weight' => 4, + 'weight' => 6, ]); $fields['custom_date'] = BaseFieldDefinition::create('daterange') @@ -450,8 +453,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setRequired(FALSE) ->setDisplayOptions('form', [ 'type' => 'daterange_default', - 'label' => 'above', - 'weight' => 5, + 'weight' => 7, ]); $fields['excluded_dates'] = BaseFieldDefinition::create('daterange') @@ -466,8 +468,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setSetting('datetime_type', 'date') ->setDisplayOptions('form', [ 'type' => 'daterange_default', - 'label' => 'above', - 'weight' => 6, + 'weight' => 8, 'settings' => [ 'format_type' => 'html_date', 'datetime_type' => 'date', @@ -486,8 +487,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setSetting('datetime_type', 'date') ->setDisplayOptions('form', [ 'type' => 'daterange_default', - 'label' => 'above', - 'weight' => 6, + 'weight' => 9, 'settings' => [ 'format_type' => 'html_date', 'datetime_type' => 'date', @@ -503,7 +503,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { ->setDisplayOptions('view', [ 'type' => 'recurring_events_eventinstance_date', 'label' => 'above', - 'weight' => 10, + 'weight' => 3, 'settings' => [ 'link' => TRUE, 'date_format' => 'F jS, Y h:iA', @@ -533,7 +533,7 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { 'settings' => [ 'display_label' => TRUE, ], - 'weight' => 120, + 'weight' => 12, ]) ->setDisplayConfigurable('form', TRUE); @@ -601,8 +601,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the consecutive start date. */ public function getConsecutiveStartDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('consecutive_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('consecutive_recurring_date')->start_date)) { + return $this->get('consecutive_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -612,8 +615,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the consecutive end date. */ public function getConsecutiveEndDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('consecutive_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('consecutive_recurring_date')->end_date)) { + return $this->get('consecutive_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -683,8 +689,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the daily start date. */ public function getDailyStartDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('daily_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('daily_recurring_date')->start_date)) { + return $this->get('daily_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -694,8 +703,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the daily end date. */ public function getDailyEndDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('daily_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('daily_recurring_date')->end_date)) { + return $this->get('daily_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -725,8 +737,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the weekly start date. */ public function getWeeklyStartDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('weekly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('weekly_recurring_date')->start_date)) { + return $this->get('weekly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -736,8 +751,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the weekly end date. */ public function getWeeklyEndDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('weekly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('weekly_recurring_date')->end_date)) { + return $this->get('weekly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -815,8 +833,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the monthly start date. */ public function getMonthlyStartDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('monthly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('monthly_recurring_date')->start_date)) { + return $this->get('monthly_recurring_date')->start_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** @@ -826,8 +847,11 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface { * The date object for the monthly end date. */ public function getMonthlyEndDate() { - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - return $this->get('monthly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); + if (!empty($this->get('monthly_recurring_date')->end_date)) { + return $this->get('monthly_recurring_date')->end_date->setTimezone($user_timezone)->setTime(0, 0, 0); + } + return NULL; } /** diff --git a/src/Entity/EventSeriesType.php b/src/Entity/EventSeriesType.php new file mode 100644 index 0000000000000000000000000000000000000000..e64f948a74ad5687063b0561325a6b5beafe43d8 --- /dev/null +++ b/src/Entity/EventSeriesType.php @@ -0,0 +1,84 @@ +<?php + +namespace Drupal\recurring_events\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityBundleBase; + +/** + * Defines the Event series type entity. + * + * @ConfigEntityType( + * id = "eventseries_type", + * label = @Translation("Event series type"), + * handlers = { + * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", + * "list_builder" = "Drupal\recurring_events\EventSeriesTypeListBuilder", + * "form" = { + * "add" = "Drupal\recurring_events\Form\EventSeriesTypeForm", + * "edit" = "Drupal\recurring_events\Form\EventSeriesTypeForm", + * "delete" = "Drupal\recurring_events\Form\EventSeriesTypeDeleteForm" + * }, + * "route_provider" = { + * "html" = "Drupal\recurring_events\EventSeriesTypeHtmlRouteProvider", + * }, + * }, + * config_prefix = "eventseries_type", + * bundle_of = "eventseries", + * admin_permission = "administer eventseries entity", + * entity_keys = { + * "id" = "id", + * "label" = "label", + * "uuid" = "uuid" + * }, + * links = { + * "delete-form" = "/admin/structure/events/series/types/eventseries_type/{eventseries_type}/delete", + * "edit-form" = "/admin/structure/events/series/types/eventseries_type/{eventseries_type}/edit", + * "canonical" = "/admin/structure/events/series/types/eventseries_type/{eventseries_type}", + * "add-form" = "/admin/structure/events/series/types/eventseries_type/add", + * "collection" = "/admin/structure/events/series/types/eventseries_type" + * }, + * config_export = { + * "label", + * "id", + * "description", + * } + * ) + */ +class EventSeriesType extends ConfigEntityBundleBase implements EventSeriesTypeInterface { + + /** + * The Event series type ID. + * + * @var string + */ + protected $id; + + /** + * The Event series type label. + * + * @var string + */ + protected $label; + + /** + * A brief description of this eventseries type. + * + * @var string + */ + protected $description; + + /** + * {@inheritdoc} + */ + public function id() { + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->description; + } + +} diff --git a/src/Entity/EventSeriesTypeInterface.php b/src/Entity/EventSeriesTypeInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..2777ca56a72d5ef89f2b62cc5d595c18443fc1e6 --- /dev/null +++ b/src/Entity/EventSeriesTypeInterface.php @@ -0,0 +1,20 @@ +<?php + +namespace Drupal\recurring_events\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityInterface; + +/** + * Provides an interface for defining Event series type entities. + */ +interface EventSeriesTypeInterface extends ConfigEntityInterface { + + /** + * Gets the description. + * + * @return string + * The description of this eventseries type. + */ + public function getDescription(); + +} diff --git a/src/Entity/FieldInheritance.php b/src/Entity/FieldInheritance.php deleted file mode 100644 index 6e94ca6ba167f365e95cf4145c30bc95a085e6ac..0000000000000000000000000000000000000000 --- a/src/Entity/FieldInheritance.php +++ /dev/null @@ -1,153 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Entity; - -use Drupal\Core\Config\Entity\ConfigEntityBase; - -/** - * Defines the Field inheritance entity. - * - * @ConfigEntityType( - * id = "field_inheritance", - * label = @Translation("Field inheritance"), - * handlers = { - * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", - * "list_builder" = "Drupal\recurring_events\FieldInheritanceListBuilder", - * "form" = { - * "add" = "Drupal\recurring_events\Form\FieldInheritanceForm", - * "edit" = "Drupal\recurring_events\Form\FieldInheritanceForm", - * "delete" = "Drupal\recurring_events\Form\FieldInheritanceDeleteForm" - * }, - * "route_provider" = { - * "html" = "Drupal\recurring_events\FieldInheritanceHtmlRouteProvider", - * }, - * }, - * config_prefix = "field_inheritance", - * admin_permission = "administer site configuration", - * entity_keys = { - * "id" = "id", - * "label" = "label", - * "uuid" = "uuid" - * }, - * links = { - * "canonical" = "/admin/structure/events/instance/settings/field_inheritance/{field_inheritance}", - * "add-form" = "/admin/structure/events/instance/settings/field_inheritance/add", - * "edit-form" = "/admin/structure/events/instance/settings/field_inheritance/{field_inheritance}/edit", - * "delete-form" = "/admin/structure/events/instance/settings/field_inheritance/{field_inheritance}/delete", - * "collection" = "/admin/structure/events/instance/settings/field_inheritance" - * }, - * config_export = { - * "id", - * "label", - * "type", - * "sourceField", - * "entityField", - * "plugin" - * } - * ) - */ -class FieldInheritance extends ConfigEntityBase implements FieldInheritanceInterface { - - /** - * The field inheritance ID. - * - * @var string - */ - protected $id; - - /** - * The field inheritance label. - * - * @var string - */ - protected $label; - - /** - * The field inheritance type. - * - * @var string - */ - protected $type; - - /** - * The field inheritance source field. - * - * @var string - */ - protected $sourceField; - - /** - * The field inheritance entity field. - * - * @var string - */ - protected $entityField; - - /** - * The field inheritance plugin. - * - * @var string - */ - protected $plugin; - - /** - * {@inheritdoc} - */ - public function type() { - return isset($this->type) ? $this->type : NULL; - } - - /** - * {@inheritdoc} - */ - public function sourceField() { - return isset($this->sourceField) ? $this->sourceField : NULL; - } - - /** - * {@inheritdoc} - */ - public function entityField() { - return isset($this->entityField) ? $this->entityField : NULL; - } - - /** - * {@inheritdoc} - */ - public function plugin() { - return isset($this->plugin) ? $this->plugin : NULL; - } - - /** - * {@inheritdoc} - */ - public function setType($type) { - $this->type = $type; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setSourceField($source_field) { - $this->sourceField = $source_field; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setEntityField($entity_field) { - $this->entityField = $entity_field; - return $this; - } - - /** - * {@inheritdoc} - */ - public function setPlugin($plugin) { - $this->plugin = $plugin; - return $this; - } - -} diff --git a/src/Entity/FieldInheritanceInterface.php b/src/Entity/FieldInheritanceInterface.php deleted file mode 100644 index 6d15b4365c72535babed869a77f46448ec6f9557..0000000000000000000000000000000000000000 --- a/src/Entity/FieldInheritanceInterface.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Entity; - -use Drupal\Core\Config\Entity\ConfigEntityInterface; - -/** - * Provides an interface for defining Field inheritance entities. - */ -interface FieldInheritanceInterface extends ConfigEntityInterface { - - /** - * Get the inheritance type. - * - * @return string - * The inheritance type. - */ - public function type(); - - /** - * Get the inheritance source field. - * - * @return string - * The inheritance source field. - */ - public function sourceField(); - - /** - * Get the inheritance entity field. - * - * @return string - * The inheritance entity field. - */ - public function entityField(); - - /** - * Get the inheritance plugin. - * - * @return string - * The inheritance plugin. - */ - public function plugin(); - - /** - * Set the inheritance type. - * - * @var string $type - * The inheritance type. - * - * @return $this - */ - public function setType($type); - - /** - * Set the inheritance source field. - * - * @var string $source_field - * The inheritance source field. - * - * @return $this - */ - public function setSourceField($source_field); - - /** - * Set the inheritance entity field. - * - * @var string $entity_field - * The inheritance entity field. - * - * @return $this - */ - public function setEntityField($entity_field); - - /** - * Set the inheritance plugin. - * - * @var string $plugin - * The inheritance plugin. - * - * @return $this - */ - public function setPlugin($plugin); - -} diff --git a/src/EntityReferenceFieldInheritanceFactory.php b/src/EntityReferenceFieldInheritanceFactory.php deleted file mode 100644 index b335ed8432a42ecb2c3d25b4120abf547fe1707e..0000000000000000000000000000000000000000 --- a/src/EntityReferenceFieldInheritanceFactory.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - -namespace Drupal\recurring_events; - -use Drupal\Core\Field\EntityReferenceFieldItemList; -use Drupal\Core\TypedData\ComputedItemListTrait; -use Drupal\Core\Field\BaseFieldDefinition; -use Drupal\Core\TypedData\TypedDataInterface; - -/** - * The EntityReferenceFieldInheritanceFactory class. - * - * Note: This class exists separately to the FieldInheritanceFactor because - * when inheriting data from an entity_reference field we end up with type hints - * failing during calls to EntityReferenceFormatterBase::getEntitiesToView(). - */ -class EntityReferenceFieldInheritanceFactory extends EntityReferenceFieldItemList { - - use ComputedItemListTrait; - - /** - * Constructs a TypedData object given its definition and context. - * - * @param \Drupal\Core\Field\BaseFieldDefinition $definition - * The data definition. - * @param string $name - * (optional) The name of the created property, or NULL if it is the root - * of a typed data tree. Defaults to NULL. - * @param \Drupal\Core\TypedData\TypedDataInterface $parent - * (optional) The parent object of the data property, or NULL if it is the - * root of a typed data tree. Defaults to NULL. - * - * @see \Drupal\Core\TypedData\TypedDataManager::create() - */ - public function __construct(BaseFieldDefinition $definition, $name = NULL, TypedDataInterface $parent = NULL) { - parent::__construct($definition, $name, $parent); - - if ($this->getSetting('plugin') === NULL) { - throw new \InvalidArgumentException("The definition's 'plugin' key has to specify the plugin to use to inherit data."); - } - - if ($this->getSetting('method') === NULL) { - throw new \InvalidArgumentException("The definition's 'method' key has to specify the method to use to inherit data. Valid options are inherit, prepend, replace, and append."); - } - - if ($this->getSetting('source field') === NULL) { - throw new \InvalidArgumentException("The definition's 'source field' key has to specify the field from which to inherit data."); - } - } - - /** - * Compute the field property from state. - */ - protected function computeValue() { - $entity = $this->getEntity(); - $manager = $this->getManager(); - $configuration = $this->getSettings() + ['entity' => $entity]; - $plugin = $manager->createInstance($this->getSetting('plugin'), $configuration); - $values = $plugin->computeValue(); - if (!empty($values)) { - foreach ($values as $key => $value) { - $this->list[$key] = $this->createItem($key, $value); - } - } - else { - $this->applyDefaultValue(); - } - } - - /** - * Returns the FieldInheritancePluginManager plugin manager. - * - * @return \Drupal\recurring_events\FieldInheritancePluginManager - * The FieldInheritancePluginManager plugin manager. - */ - protected function getManager() { - return \Drupal::service('plugin.manager.field_inheritance'); - } - -} diff --git a/src/EventCreationService.php b/src/EventCreationService.php index 9a74d6e27bb684a1ccca7e911deae4780995bdcb..66d9b258dabc611aca7dbdf54c04ca403a93e1a2 100644 --- a/src/EventCreationService.php +++ b/src/EventCreationService.php @@ -12,12 +12,17 @@ use Drupal\Core\Messenger\Messenger; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal\Core\Entity\EntityFieldManager; use Drupal\Core\Field\FieldTypePluginManager; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\Extension\ModuleHandler; +use Drupal\Core\Entity\EntityTypeManagerInterface; /** * EventCreationService class. */ class EventCreationService { + use StringTranslationTrait; + /** * The translation interface. * @@ -60,6 +65,20 @@ class EventCreationService { */ protected $entityFieldManager; + /** + * The module handler service. + * + * @var \Drupal\Core\Extension\ModuleHandler + */ + protected $moduleHandler; + + /** + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + /** * Class constructor. * @@ -75,14 +94,20 @@ class EventCreationService { * The field type plugin manager. * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager * The entity field manager. + * @param \Drupal\Core\Extension\ModuleHandler $module_handler + * The module handler service. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager service. */ - public function __construct(TranslationInterface $translation, Connection $database, LoggerChannelFactoryInterface $logger, Messenger $messenger, FieldTypePluginManager $field_type_plugin_manager, EntityFieldManager $entity_field_manager) { + public function __construct(TranslationInterface $translation, Connection $database, LoggerChannelFactoryInterface $logger, Messenger $messenger, FieldTypePluginManager $field_type_plugin_manager, EntityFieldManager $entity_field_manager, ModuleHandler $module_handler, EntityTypeManagerInterface $entity_type_manager) { $this->translation = $translation; $this->database = $database; $this->loggerFactory = $logger->get('recurring_events'); $this->messenger = $messenger; $this->fieldTypePluginManager = $field_type_plugin_manager; $this->entityFieldManager = $entity_field_manager; + $this->moduleHandler = $module_handler; + $this->entityTypeManager = $entity_type_manager; } /** @@ -95,7 +120,9 @@ class EventCreationService { $container->get('logger.factory'), $container->get('messenger'), $container->get('plugin.manager.field.field_type'), - $container->get('entity_field.manager') + $container->get('entity_field.manager'), + $container->get('module_handler'), + $container->get('entity_type.manager') ); } @@ -157,7 +184,7 @@ class EventCreationService { $config += $field_class::convertEntityConfigToArray($event); } - \Drupal::moduleHandler()->alter('recurring_events_entity_config_array', $config); + $this->moduleHandler->alter('recurring_events_entity_config_array', $config); return $config; } @@ -174,7 +201,7 @@ class EventCreationService { public function convertFormConfigToArray(FormStateInterface $form_state) { $config = []; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $user_input = $form_state->getUserInput(); @@ -224,7 +251,7 @@ class EventCreationService { $config += $field_class::convertFormConfigToArray($form_state); } - \Drupal::moduleHandler()->alter('recurring_events_form_config_array', $config); + $this->moduleHandler->alter('recurring_events_form_config_array', $config); return $config; } @@ -296,7 +323,7 @@ class EventCreationService { } } - foreach ($form_config['custom_dates'] as $dates) { + foreach ($form_config['custom_dates'] as $date) { if (!empty($date['start_date']) && !empty($date['end_date'])) { $overridden_start_ends[] = $date['start_date']->format('Y-m-d h:ia') . ' - ' . $date['end_date']->format('Y-m-d h:ia'); } @@ -316,7 +343,7 @@ class EventCreationService { } } - \Drupal::moduleHandler()->alter('recurring_events_diff_array', $diff); + $this->moduleHandler->alter('recurring_events_diff_array', $diff); return $diff; } @@ -339,21 +366,21 @@ class EventCreationService { $create_instances = $this->checkForOriginalRecurConfigChanges($event, $original); if ($create_instances) { // Allow other modules to react prior to the deletion of all instances. - \Drupal::moduleHandler()->invokeAll('recurring_events_save_pre_instances_deletion', [$event, $original]); + $this->moduleHandler->invokeAll('recurring_events_save_pre_instances_deletion', [$event, $original]); // Find all the instances and delete them. $instances = $event->event_instances->referencedEntities(); if (!empty($instances)) { - foreach ($instances as $index => $instance) { + foreach ($instances as $instance) { // Allow other modules to react prior to deleting a specific // instance after a date configuration change. - \Drupal::moduleHandler()->invokeAll('recurring_events_save_pre_instance_deletion', [$event, $instance]); + $this->moduleHandler->invokeAll('recurring_events_save_pre_instance_deletion', [$event, $instance]); $instance->delete(); // Allow other modules to react after deleting a specific instance // after a date configuration change. - \Drupal::moduleHandler()->invokeAll('recurring_events_save_post_instance_deletion', [$event, $instance]); + $this->moduleHandler->invokeAll('recurring_events_save_post_instance_deletion', [$event, $instance]); } $this->messenger->addStatus($this->translation->translate('A total of %count existing event instances were removed', [ '%count' => count($instances), @@ -361,7 +388,7 @@ class EventCreationService { } // Allow other modules to react after the deletion of all instances. - \Drupal::moduleHandler()->invokeAll('recurring_events_save_post_instances_deletion', [$event, $original]); + $this->moduleHandler->invokeAll('recurring_events_save_post_instances_deletion', [$event, $original]); } } @@ -381,9 +408,6 @@ class EventCreationService { $form_data = $this->convertEntityConfigToArray($event); $event_instances = []; - $timezone = new \DateTimeZone(drupal_get_user_timezone()); - $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); - if (!empty($form_data['type'])) { if ($form_data['type'] === 'custom') { if (!empty($form_data['custom_dates'])) { @@ -398,7 +422,7 @@ class EventCreationService { // Allow modules to alter the array of event instances before they // get created. - \Drupal::moduleHandler()->alter('recurring_events_event_instances_pre_create', $events_to_create, $event); + $this->moduleHandler->alter('recurring_events_event_instances_pre_create', $events_to_create, $event); if (!empty($events_to_create)) { foreach ($events_to_create as $custom_event) { @@ -414,7 +438,7 @@ class EventCreationService { // Allow modules to alter the array of event instances before they // get created. - \Drupal::moduleHandler()->alter('recurring_events_event_instances_pre_create', $events_to_create, $event); + $this->moduleHandler->alter('recurring_events_event_instances_pre_create', $events_to_create, $event); if (!empty($events_to_create)) { foreach ($events_to_create as $event_to_create) { @@ -451,14 +475,12 @@ class EventCreationService { 'value' => $start_date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT), 'end_value' => $end_date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT), ], + 'type' => $event->getType(), ]; - \Drupal::moduleHandler()->alter('recurring_events_event_instance', $data); - - $entity = \Drupal::entityTypeManager() - ->getStorage('eventinstance') - ->create($data); + $this->moduleHandler->alter('recurring_events_event_instance', $data); + $entity = $this->entityTypeManager->getStorage('eventinstance')->create($data); $entity->save(); return $entity; @@ -532,7 +554,7 @@ class EventCreationService { // hook. $recur_fields = []; $fields = $this->entityFieldManager->getBaseFieldDefinitions('eventseries'); - foreach ($fields as $field_name => $field) { + foreach ($fields as $field) { $field_definition = $this->fieldTypePluginManager->getDefinition($field->getType()); $class = new \ReflectionClass($field_definition['class']); if ($class->implementsInterface('\Drupal\recurring_events\RecurringEventsFieldTypeInterface')) { @@ -540,9 +562,9 @@ class EventCreationService { } } - $recur_fields['custom'] = t('Custom Event'); + $recur_fields['custom'] = $this->t('Custom Event'); if ($allow_alter) { - \Drupal::moduleHandler()->alter('recurring_events_recur_field_types', $recur_fields); + $this->moduleHandler->alter('recurring_events_recur_field_types', $recur_fields); } return $recur_fields; } diff --git a/src/EventInstanceAccessControlHandler.php b/src/EventInstanceAccessControlHandler.php index 1a2bf5b8679b3f3cb784c7a49b6e1e075258b66d..c1b42ab0c5a4c66a2747e7333dc0878e890437b3 100644 --- a/src/EventInstanceAccessControlHandler.php +++ b/src/EventInstanceAccessControlHandler.php @@ -31,13 +31,13 @@ class EventInstanceAccessControlHandler extends EntityAccessControlHandler { case 'edit': if ($account->id() !== $entity->getOwnerId()) { - return AccessResult::allowedIfHasPermission($account, 'edit eventinstance entities'); + return AccessResult::allowedIfHasPermission($account, 'edit eventinstance entity'); } return AccessResult::allowedIfHasPermission($account, 'edit own eventinstance entity'); case 'delete': if ($account->id() !== $entity->getOwnerId()) { - return AccessResult::allowedIfHasPermission($account, 'delete eventinstance entities'); + return AccessResult::allowedIfHasPermission($account, 'delete eventinstance entity'); } return AccessResult::allowedIfHasPermission($account, 'delete own eventinstance entity'); diff --git a/src/EventInstanceListBuilder.php b/src/EventInstanceListBuilder.php index 75a47bada34e90cbcd184d0a291ef07c2817c23d..8d75f8fba0465ecebc81e929eb1b876fb8a9ea52 100644 --- a/src/EventInstanceListBuilder.php +++ b/src/EventInstanceListBuilder.php @@ -122,7 +122,7 @@ class EventInstanceListBuilder extends EntityListBuilder { '#url' => $entity->getEventSeries()->toUrl(), ]; $config = $this->config->get('recurring_events.eventinstance.config'); - $timezone = new \DateTimeZone(drupal_get_user_timezone()); + $timezone = new \DateTimeZone(date_default_timezone_get()); $entity->date->start_date->setTimezone($timezone); $row['date'] = $entity->date->start_date->format($config->get('date_format')); $row['author']['data'] = [ diff --git a/src/FieldInheritanceHtmlRouteProvider.php b/src/EventInstanceTypeHtmlRouteProvider.php similarity index 72% rename from src/FieldInheritanceHtmlRouteProvider.php rename to src/EventInstanceTypeHtmlRouteProvider.php index 52dd17146dda740ad59c8a7e8201c5fa69a9b24a..1d42c64ef37188b2c2c4a418a016efd841df3c8a 100644 --- a/src/FieldInheritanceHtmlRouteProvider.php +++ b/src/EventInstanceTypeHtmlRouteProvider.php @@ -6,20 +6,18 @@ use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider; /** - * Provides routes for Field inheritance entities. + * Provides routes for Event instance type entities. * * @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider * @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider */ -class FieldInheritanceHtmlRouteProvider extends AdminHtmlRouteProvider { +class EventInstanceTypeHtmlRouteProvider extends AdminHtmlRouteProvider { /** * {@inheritdoc} */ public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); - - // Provide your custom entity routes here. return $collection; } diff --git a/src/EventInstanceTypeListBuilder.php b/src/EventInstanceTypeListBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..dfa968cb2b154b7251f5ed57ffa524b3a1d3f297 --- /dev/null +++ b/src/EventInstanceTypeListBuilder.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\recurring_events; + +use Drupal\Core\Config\Entity\ConfigEntityListBuilder; +use Drupal\Core\Entity\EntityInterface; + +/** + * Provides a listing of Event instance type entities. + */ +class EventInstanceTypeListBuilder 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 getDefaultOperations(EntityInterface $entity) { + $operations = parent::getDefaultOperations($entity); + // Place the edit operation after the operations added by field_ui.module + // which have the weights 15, 20, 25. + if (isset($operations['edit'])) { + $operations['edit']['weight'] = 30; + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $entity->label(); + $row['id'] = $entity->id(); + // You probably want a few more properties here... + return $row + parent::buildRow($entity); + } + +} diff --git a/src/EventInterface.php b/src/EventInterface.php index 6644e0c5c860aba7c11f6ef6cc5323a182b9a784..73df63b123f3386e6717ef4a162d3e306ac45529 100644 --- a/src/EventInterface.php +++ b/src/EventInterface.php @@ -41,29 +41,4 @@ interface EventInterface extends ContentEntityInterface, EntityChangedInterface, */ public function setRevisionCreationTime($timestamp); - /** - * Gets the event revision author. - * - * @return \Drupal\user\UserInterface - * The user entity for the revision author. - * - * @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use - * \Drupal\Core\Entity\RevisionLogInterface::getRevisionUser() instead. - */ - public function getRevisionAuthor(); - - /** - * Sets the event revision author. - * - * @param int $uid - * The user ID of the revision author. - * - * @return \Drupal\recurring_events\EventInterface - * The called event entity. - * - * @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use - * \Drupal\Core\Entity\RevisionLogInterface::setRevisionUserId() instead. - */ - public function setRevisionAuthorId($uid); - } diff --git a/src/EventSeriesAccessControlHandler.php b/src/EventSeriesAccessControlHandler.php index 67d607f947402694f89f462581848d9c104ed3ce..b06f86d4a86f796be2932529a54e5d6189dbeb0f 100644 --- a/src/EventSeriesAccessControlHandler.php +++ b/src/EventSeriesAccessControlHandler.php @@ -31,13 +31,13 @@ class EventSeriesAccessControlHandler extends EntityAccessControlHandler { case 'edit': if ($account->id() !== $entity->getOwnerId()) { - return AccessResult::allowedIfHasPermission($account, 'edit eventseries entities'); + return AccessResult::allowedIfHasPermission($account, 'edit eventseries entity'); } return AccessResult::allowedIfHasPermission($account, 'edit own eventseries entity'); case 'delete': if ($account->id() !== $entity->getOwnerId()) { - return AccessResult::allowedIfHasPermission($account, 'delete eventseries entities'); + return AccessResult::allowedIfHasPermission($account, 'delete eventseries entity'); } return AccessResult::allowedIfHasPermission($account, 'delete own eventseries entity'); diff --git a/src/EventSeriesListBuilder.php b/src/EventSeriesListBuilder.php index 4aa561fc5b6732cc9b6b6303c3f6447c6c1ce4eb..38ed5f3bf5b0d3d0a8719ba83ccdf7d428bb54ea 100644 --- a/src/EventSeriesListBuilder.php +++ b/src/EventSeriesListBuilder.php @@ -125,7 +125,7 @@ class EventSeriesListBuilder extends EntityListBuilder { $row['type'] = $entity->recur_type->value; $row['instances'] = $entity->getInstanceCount(); $row['starts'] = $this->t('None'); - $timezone = new \DateTimeZone(drupal_get_user_timezone()); + $timezone = new \DateTimeZone(date_default_timezone_get()); if (!empty($entity->getSeriesStart())) { $config = $this->config->get('recurring_events.eventseries.config'); $start_date = $entity->getSeriesStart(); diff --git a/src/EventSeriesTypeHtmlRouteProvider.php b/src/EventSeriesTypeHtmlRouteProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..f2cf604d0c54bc00d033e33d0c25747986b5529f --- /dev/null +++ b/src/EventSeriesTypeHtmlRouteProvider.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\recurring_events; + +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider; + +/** + * Provides routes for Event series type entities. + * + * @see Drupal\Core\Entity\Routing\AdminHtmlRouteProvider + * @see Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider + */ +class EventSeriesTypeHtmlRouteProvider extends AdminHtmlRouteProvider { + + /** + * {@inheritdoc} + */ + public function getRoutes(EntityTypeInterface $entity_type) { + $collection = parent::getRoutes($entity_type); + return $collection; + } + +} diff --git a/src/EventSeriesTypeListBuilder.php b/src/EventSeriesTypeListBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..82d44493384dd5ccce5178987723237c7c63054c --- /dev/null +++ b/src/EventSeriesTypeListBuilder.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\recurring_events; + +use Drupal\Core\Config\Entity\ConfigEntityListBuilder; +use Drupal\Core\Entity\EntityInterface; + +/** + * Provides a listing of Event series type entities. + */ +class EventSeriesTypeListBuilder extends ConfigEntityListBuilder { + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Event series type'); + $header['id'] = $this->t('Machine name'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOperations(EntityInterface $entity) { + $operations = parent::getDefaultOperations($entity); + // Place the edit operation after the operations added by field_ui.module + // which have the weights 15, 20, 25. + if (isset($operations['edit'])) { + $operations['edit']['weight'] = 30; + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $entity->label(); + $row['id'] = $entity->id(); + // You probably want a few more properties here... + return $row + parent::buildRow($entity); + } + +} diff --git a/src/ExcludedDatesHtmlRouteProvider.php b/src/ExcludedDatesHtmlRouteProvider.php index edc38c0c08abe5b694d86f1e1b0e5d0f5d59227e..2699611302237721fd141a891e4e518f8655bf2a 100644 --- a/src/ExcludedDatesHtmlRouteProvider.php +++ b/src/ExcludedDatesHtmlRouteProvider.php @@ -4,7 +4,6 @@ namespace Drupal\recurring_events; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider; -use Symfony\Component\Routing\Route; /** * Provides routes for Excluded dates entities. @@ -19,9 +18,6 @@ class ExcludedDatesHtmlRouteProvider extends AdminHtmlRouteProvider { */ public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); - - // Provide your custom entity routes here. - return $collection; } diff --git a/src/FieldInheritanceFactory.php b/src/FieldInheritanceFactory.php deleted file mode 100644 index c34be3a38b0baa6911ddbd4e13b3388ba265f884..0000000000000000000000000000000000000000 --- a/src/FieldInheritanceFactory.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php - -namespace Drupal\recurring_events; - -use Drupal\Core\Field\FieldItemList; -use Drupal\Core\TypedData\ComputedItemListTrait; -use Drupal\Core\Field\BaseFieldDefinition; -use Drupal\Core\TypedData\TypedDataInterface; - -/** - * The FieldInheritanceFactory class. - */ -class FieldInheritanceFactory extends FieldItemList { - - use ComputedItemListTrait; - - /** - * Constructs a FieldInheritanceFactory object. - * - * @param \Drupal\Core\Field\BaseFieldDefinition $definition - * The data definition. - * @param string $name - * (optional) The name of the created property, or NULL if it is the root - * of a typed data tree. Defaults to NULL. - * @param \Drupal\Core\TypedData\TypedDataInterface $parent - * (optional) The parent object of the data property, or NULL if it is the - * root of a typed data tree. Defaults to NULL. - * - * @see \Drupal\Core\TypedData\TypedDataManager::create() - */ - public function __construct(BaseFieldDefinition $definition, $name = NULL, TypedDataInterface $parent = NULL) { - parent::__construct($definition, $name, $parent); - - if ($this->getSetting('plugin') === NULL) { - throw new \InvalidArgumentException("The definition's 'plugin' key has to specify the plugin to use to inherit data."); - } - - if ($this->getSetting('method') === NULL) { - throw new \InvalidArgumentException("The definition's 'method' key has to specify the method to use to inherit data. Valid options are inherit, prepend, replace, and append."); - } - - if ($this->getSetting('source field') === NULL) { - throw new \InvalidArgumentException("The definition's 'source field' key has to specify the field from which to inherit data."); - } - } - - /** - * Compute the field property from state. - */ - protected function computeValue() { - $entity = $this->getEntity(); - $manager = $this->getManager(); - $configuration = $this->getSettings() + ['entity' => $entity]; - $plugin = $manager->createInstance($this->getSetting('plugin'), $configuration); - $values = $plugin->computeValue(); - if (!empty($values)) { - foreach ($values as $key => $value) { - $this->list[$key] = $this->createItem($key, $value); - } - } - else { - $this->applyDefaultValue(); - } - } - - /** - * Returns the FieldInheritancePluginManager plugin manager. - * - * @return \Drupal\recurring_events\FieldInheritancePluginManager - * The FieldInheritancePluginManager plugin manager. - */ - protected function getManager() { - return \Drupal::service('plugin.manager.field_inheritance'); - } - -} diff --git a/src/FieldInheritanceListBuilder.php b/src/FieldInheritanceListBuilder.php deleted file mode 100644 index e2e029bca4293ff0d3d1aa5405f7801176f82e80..0000000000000000000000000000000000000000 --- a/src/FieldInheritanceListBuilder.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -namespace Drupal\recurring_events; - -use Drupal\Core\Config\Entity\ConfigEntityListBuilder; -use Drupal\Core\Entity\EntityInterface; - -/** - * Provides a listing of Field inheritance entities. - */ -class FieldInheritanceListBuilder extends ConfigEntityListBuilder { - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = $this->t('Field inheritance'); - $header['id'] = $this->t('Machine name'); - $header['type'] = $this->t('Type'); - $header['source_field'] = $this->t('Source Field'); - $header['entity_field'] = $this->t('Entity Field'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = $entity->label(); - $row['id'] = $entity->id(); - $row['type'] = $entity->type(); - $row['source_field'] = $entity->sourceField(); - $row['entity_field'] = $entity->entityField() ?: $this->t('N/A'); - return $row + parent::buildRow($entity); - } - -} diff --git a/src/FieldInheritancePluginInterface.php b/src/FieldInheritancePluginInterface.php deleted file mode 100644 index 278a1ec4db54e06a98b14e4c85229a7450e042a1..0000000000000000000000000000000000000000 --- a/src/FieldInheritancePluginInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -namespace Drupal\recurring_events; - -/** - * FieldInheritancePluginInterface interface definition. - */ -interface FieldInheritancePluginInterface { - - /** - * Compute the value of the field. - */ - public function computeValue(); - -} diff --git a/src/FieldInheritancePluginManager.php b/src/FieldInheritancePluginManager.php deleted file mode 100644 index 6ab747982a15a777d13db59530e0f029c53602d3..0000000000000000000000000000000000000000 --- a/src/FieldInheritancePluginManager.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -namespace Drupal\recurring_events; - -use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Plugin\DefaultPluginManager; - -/** - * Provides a FieldInheritance plugin manager. - * - * @see \Drupal\recurring_events\Annotation\FieldInheritance - * @see \Drupal\recurring_events\FieldInheritancePluginInterface - * @see plugin_api - */ -class FieldInheritancePluginManager extends DefaultPluginManager { - - /** - * Constructs a FieldInheritancePluginManager object. - * - * @param \Traversable $namespaces - * An object that implements \Traversable which contains the root paths - * keyed by the corresponding namespace to look for plugin implementations. - * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend - * Cache backend instance to use. - * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler - * The module handler to invoke the alter hook with. - */ - public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { - parent::__construct( - 'Plugin/FieldInheritance', - $namespaces, - $module_handler, - 'Drupal\recurring_events\FieldInheritancePluginInterface', - 'Drupal\recurring_events\Annotation\FieldInheritance' - ); - $this->alterInfo('field_inheritance_info'); - $this->setCacheBackend($cache_backend, 'field_inheritance_info_plugins'); - } - -} diff --git a/src/Form/EventInstanceDeleteForm.php b/src/Form/EventInstanceDeleteForm.php index 33854d614a089d566593b99192492eaa69d49617..20d500f49bb409d990088f188f9749d3f7640331 100644 --- a/src/Form/EventInstanceDeleteForm.php +++ b/src/Form/EventInstanceDeleteForm.php @@ -5,7 +5,7 @@ namespace Drupal\recurring_events\Form; use Drupal\Core\Entity\ContentEntityDeleteForm; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Url; use Drupal\Core\Messenger\Messenger; use Drupal\Core\Datetime\DateFormatter; @@ -41,15 +41,15 @@ class EventInstanceDeleteForm extends ContentEntityDeleteForm { /** * Construct a EventInstanceDeleteForm. * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager service. + * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository + * The entity repository service. * @param \Drupal\Core\Messenger\Messenger $messenger * The messenger service. * @param \Drupal\Core\Datetime\DateFormatter $date_formatter * The date formatter service. */ - public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger, DateFormatter $date_formatter) { - parent::__construct($entity_manager); + public function __construct(EntityRepositoryInterface $entity_repository, Messenger $messenger, DateFormatter $date_formatter) { + parent::__construct($entity_repository); $this->messenger = $messenger; $this->dateFormatter = $date_formatter; } @@ -59,7 +59,7 @@ class EventInstanceDeleteForm extends ContentEntityDeleteForm { */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), + $container->get('entity.repository'), $container->get('messenger'), $container->get('date.formatter') ); @@ -75,7 +75,7 @@ class EventInstanceDeleteForm extends ContentEntityDeleteForm { return $this ->t('Are you sure you want to delete the @language translation of the @entity-type %label?', [ '@language' => $entity->language()->getName(), - '@entity-type' => $this->getEntity()->getEntityType()->getLowercaseLabel(), + '@entity-type' => $this->getEntity()->getEntityType()->getSingularLabel(), '%label' => $this->entity->getEventSeries()->title->value, ]); } diff --git a/src/Form/EventInstanceForm.php b/src/Form/EventInstanceForm.php index 4be8c39fb92f6bbef5a98a24fa0ce12ef89d15a5..f084247ccc63d4173a91e878eb3aa13732960a48 100644 --- a/src/Form/EventInstanceForm.php +++ b/src/Form/EventInstanceForm.php @@ -5,8 +5,10 @@ namespace Drupal\recurring_events\Form; use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Messenger\Messenger; +use Drupal\Core\Session\AccountProxyInterface; +use Drupal\Component\Datetime\TimeInterface; /** * Form controller for the eventinstance entity edit forms. @@ -22,27 +24,49 @@ class EventInstanceForm extends ContentEntityForm { */ protected $messenger; + /** + * The current user. + * + * @var \Drupal\Core\Session\AccountProxyInterface + */ + protected $currentUser; + + /** + * The time service. + * + * @var \Drupal\Component\Datetime\TimeInterface + */ + protected $time; + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), - $container->get('messenger') + $container->get('entity.repository'), + $container->get('messenger'), + $container->get('current_user'), + $container->get('datetime.time') ); } /** * Construct an EventInstanceForm. * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager service. + * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository + * The entity repository service. * @param \Drupal\Core\Messenger\Messenger $messenger * The messenger service. + * @param \Drupal\Core\Session\AccountProxyInterface $current_user + * The current user. + * @param \Drupal\Component\Datetime\TimeInterface $time + * The time service. */ - public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger) { + public function __construct(EntityRepositoryInterface $entity_repository, Messenger $messenger, AccountProxyInterface $current_user, TimeInterface $time) { $this->messenger = $messenger; - parent::__construct($entity_manager); + $this->currentUser = $current_user; + $this->time = $time; + parent::__construct($entity_repository); } /** @@ -96,8 +120,8 @@ class EventInstanceForm extends ContentEntityForm { $entity->setNewRevision(); // If a new revision is created, save the current user as revision author. - $entity->setRevisionCreationTime(REQUEST_TIME); - $entity->setRevisionUserId(\Drupal::currentUser()->id()); + $entity->setRevisionCreationTime($this->time->getRequestTime()); + $entity->setRevisionUserId($this->currentUser->id()); } else { $entity->setNewRevision(FALSE); @@ -106,12 +130,12 @@ class EventInstanceForm extends ContentEntityForm { parent::save($form, $form_state); if ($entity->isDefaultTranslation()) { - $message = t('Event instance of %label has been saved.', [ + $message = $this->t('Event instance of %label has been saved.', [ '%label' => $entity->getEventSeries()->title->value, ]); } else { - $message = t('@language translation of the Event Instance %label has been saved.', [ + $message = $this->t('@language translation of the Event Instance %label has been saved.', [ '@language' => $entity->language()->getName(), '%label' => $entity->getUntranslated()->getEventSeries()->title->value, ]); diff --git a/src/Form/EventInstanceRevisionDeleteForm.php b/src/Form/EventInstanceRevisionDeleteForm.php index b67b92ad2cafba73102aa18edd441b78095d4796..4fcb048f4175b068886b1725675b8ca3c7f9394c 100644 --- a/src/Form/EventInstanceRevisionDeleteForm.php +++ b/src/Form/EventInstanceRevisionDeleteForm.php @@ -10,6 +10,7 @@ use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Messenger\Messenger; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Provides a form for deleting a eventinstance revision. @@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger; */ class EventInstanceRevisionDeleteForm extends ConfirmFormBase { + use StringTranslationTrait; + /** * The eventinstance revision. * @@ -96,7 +99,7 @@ class EventInstanceRevisionDeleteForm extends ConfirmFormBase { * {@inheritdoc} */ public function getQuestion() { - return t('Are you sure you want to delete the revision from %revision-date?', [ + return $this->t('Are you sure you want to delete the revision from %revision-date?', [ '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()), ]); } @@ -112,7 +115,7 @@ class EventInstanceRevisionDeleteForm extends ConfirmFormBase { * {@inheritdoc} */ public function getConfirmText() { - return t('Delete'); + return $this->t('Delete'); } /** @@ -132,7 +135,7 @@ class EventInstanceRevisionDeleteForm extends ConfirmFormBase { $this->eventInstanceStorage->deleteRevision($this->revision->getRevisionId()); $this->logger('content')->notice('eventinstance: deleted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]); - $this->messenger->addMessage(t('Revision from %revision-date of eventinstance %title has been deleted.', [ + $this->messenger->addMessage($this->t('Revision from %revision-date of eventinstance %title has been deleted.', [ '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()), '%title' => $this->revision->label(), ])); diff --git a/src/Form/EventInstanceRevisionRevertForm.php b/src/Form/EventInstanceRevisionRevertForm.php index 1122e360a28911716ddcf8dd0b784e15e41d5d10..53a65df94b3bff1f26986a9a56d8022c1983e887 100644 --- a/src/Form/EventInstanceRevisionRevertForm.php +++ b/src/Form/EventInstanceRevisionRevertForm.php @@ -10,6 +10,7 @@ use Drupal\Core\Url; use Drupal\recurring_events\EventInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Messenger\Messenger; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Provides a form for reverting an eventinstance revision. @@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger; */ class EventInstanceRevisionRevertForm extends ConfirmFormBase { + use StringTranslationTrait; + /** * The eventinstance revision. * @@ -84,7 +87,7 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase { * {@inheritdoc} */ public function getQuestion() { - return t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); + return $this->t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); } /** @@ -98,7 +101,7 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase { * {@inheritdoc} */ public function getConfirmText() { - return t('Revert'); + return $this->t('Revert'); } /** @@ -127,11 +130,11 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase { $original_revision_timestamp = $this->revision->getRevisionCreationTime(); $this->revision = $this->prepareRevertedRevision($this->revision, $form_state); - $this->revision->revision_log = t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]); + $this->revision->revision_log = $this->t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]); $this->revision->save(); $this->logger('content')->notice('eventinstance: reverted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]); - $this->messenger->addMessage(t('eventinstance %title has been reverted to the revision from %revision-date.', [ + $this->messenger->addMessage($this->t('eventinstance %title has been reverted to the revision from %revision-date.', [ '%title' => $this->revision->label(), '%revision-date' => $this->dateFormatter->format($original_revision_timestamp), ])); @@ -155,7 +158,7 @@ class EventInstanceRevisionRevertForm extends ConfirmFormBase { protected function prepareRevertedRevision(EventInterface $revision, FormStateInterface $form_state) { $revision->setNewRevision(); $revision->isDefaultRevision(TRUE); - $revision->setRevisionCreationTime(REQUEST_TIME); + $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime()); return $revision; } diff --git a/src/Form/EventInstanceRevisionRevertTranslationForm.php b/src/Form/EventInstanceRevisionRevertTranslationForm.php index 1bb8be93060ad4450db88e54427badb657be1f74..10f02f6e37af89d86f866867609df1bd3f622d8f 100644 --- a/src/Form/EventInstanceRevisionRevertTranslationForm.php +++ b/src/Form/EventInstanceRevisionRevertTranslationForm.php @@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\recurring_events\EventInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Provides form to revert an eventinstance revision for a single translation. @@ -16,6 +17,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class EventInstanceRevisionRevertTranslationForm extends EventInstanceRevisionRevertForm { + use StringTranslationTrait; + /** * The language to be reverted. * @@ -67,7 +70,7 @@ class EventInstanceRevisionRevertTranslationForm extends EventInstanceRevisionRe * {@inheritdoc} */ public function getQuestion() { - return t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); + return $this->t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); } /** @@ -106,7 +109,7 @@ class EventInstanceRevisionRevertTranslationForm extends EventInstanceRevisionRe $latest_revision_translation->setNewRevision(); $latest_revision_translation->isDefaultRevision(TRUE); - $revision->setRevisionCreationTime(REQUEST_TIME); + $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime()); return $latest_revision_translation; } diff --git a/src/Form/EventInstanceSettingsForm.php b/src/Form/EventInstanceSettingsForm.php index b4572ca3c9a1b5a400abc3f6c4aa42d437b738da..db8c0ae934c6f358c9b446dce7514841bb969047 100644 --- a/src/Form/EventInstanceSettingsForm.php +++ b/src/Form/EventInstanceSettingsForm.php @@ -60,7 +60,7 @@ class EventInstanceSettingsForm extends ConfigFormBase { * Form definition array. */ public function buildForm(array $form, FormStateInterface $form_state) { - $config = $this->config('recurring_events.eventseries.config'); + $config = $this->config('recurring_events.eventinstance.config'); $php_date_url = Url::fromUri('https://secure.php.net/manual/en/function.date.php'); $php_date_link = Link::fromTextAndUrl($this->t('PHP date/time format'), $php_date_url); diff --git a/src/Form/EventInstanceTypeForm.php b/src/Form/EventInstanceTypeForm.php new file mode 100644 index 0000000000000000000000000000000000000000..0c9d369df868a0d615b6f6cea73b026e29cab692 --- /dev/null +++ b/src/Form/EventInstanceTypeForm.php @@ -0,0 +1,97 @@ +<?php + +namespace Drupal\recurring_events\Form; + +use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\Messenger; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Class EventInstanceTypeForm. + */ +class EventInstanceTypeForm extends EntityForm { + + /** + * The messenger service. + * + * @var \Drupal\Core\Messenger\Messenger + */ + protected $messenger; + + /** + * Constructs a new EventSeriesTypeForm. + * + * @param \Drupal\Core\Messenger\Messenger $messenger + * The messenger service. + */ + public function __construct(Messenger $messenger) { + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('messenger') + ); + } + + /** + * {@inheritdoc} + */ + public function form(array $form, FormStateInterface $form_state) { + $form = parent::form($form, $form_state); + + $eventinstance_type = $this->entity; + $form['label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $eventinstance_type->label(), + '#description' => $this->t("Label for the Event instance type."), + '#required' => TRUE, + ]; + + $form['id'] = [ + '#type' => 'machine_name', + '#default_value' => $eventinstance_type->id(), + '#machine_name' => [ + 'exists' => '\Drupal\recurring_events\Entity\EventInstanceType::load', + ], + '#disabled' => !$eventinstance_type->isNew(), + ]; + + $form['description'] = [ + '#title' => $this->t('Description'), + '#type' => 'textarea', + '#default_value' => $eventinstance_type->getDescription(), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function save(array $form, FormStateInterface $form_state) { + $eventinstance_type = $this->entity; + $status = $eventinstance_type->save(); + + switch ($status) { + case SAVED_NEW: + $this->messenger->addMessage($this->t('Created the %label event instance type.', [ + '%label' => $eventinstance_type->label(), + ])); + break; + + default: + $this->messenger->addMessage($this->t('Saved the %label event instance type.', [ + '%label' => $eventinstance_type->label(), + ])); + } + $form_state->setRedirectUrl($eventinstance_type->toUrl('collection')); + } + +} diff --git a/src/Form/EventSeriesDeleteForm.php b/src/Form/EventSeriesDeleteForm.php index 131250baf9671822f1285e177107b0cd9077de0e..46d7ca4f216b9d1a29693b5b1dab644507b658d2 100644 --- a/src/Form/EventSeriesDeleteForm.php +++ b/src/Form/EventSeriesDeleteForm.php @@ -5,7 +5,7 @@ namespace Drupal\recurring_events\Form; use Drupal\Core\Entity\ContentEntityDeleteForm; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Url; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Messenger\Messenger; @@ -44,13 +44,14 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm { * * @var \Drupal\Core\Render\Renderer */ + protected $renderer; /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), + $container->get('entity.repository'), $container->get('messenger'), $container->get('renderer'), $container->get('config.factory') @@ -60,8 +61,8 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm { /** * Construct an EventSeriesDeleteForm. * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager service. + * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository + * The entity repository service. * @param \Drupal\Core\Messenger\Messenger $messenger * The messenger service. * @param \Drupal\Core\Render\Renderer $renderer @@ -69,11 +70,11 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm { * @param \Drupal\Core\Config\ConfigFactory $config * The config factory service. */ - public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger, Renderer $renderer, ConfigFactory $config) { + public function __construct(EntityRepositoryInterface $entity_repository, Messenger $messenger, Renderer $renderer, ConfigFactory $config) { $this->messenger = $messenger; $this->renderer = $renderer; $this->config = $config; - parent::__construct($entity_manager); + parent::__construct($entity_repository); } /** @@ -87,7 +88,7 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm { return $this ->t('Are you sure you want to delete the @language translation of the @entity-type %label?', [ '@language' => $entity->language()->getName(), - '@entity-type' => $this->getEntity()->getEntityType()->getLowercaseLabel(), + '@entity-type' => $this->getEntity()->getEntityType()->getSingularLabel(), '%label' => $this->getEntity()->title->value, ]); } @@ -110,7 +111,7 @@ class EventSeriesDeleteForm extends ContentEntityDeleteForm { ]; $options = []; - $timezone = new \DateTimeZone(drupal_get_user_timezone()); + $timezone = new \DateTimeZone(date_default_timezone_get()); foreach ($instances as $instance) { $date = $instance->date->start_date; $date->setTimezone($timezone); diff --git a/src/Form/EventSeriesForm.php b/src/Form/EventSeriesForm.php index 6e4767b08f8a1f615e0299aa3f651cb2c9e45290..a7900541c676227d40390654e0cdc030ff447bd9 100644 --- a/src/Form/EventSeriesForm.php +++ b/src/Form/EventSeriesForm.php @@ -5,7 +5,6 @@ namespace Drupal\recurring_events\Form; use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityManagerInterface; use Drupal\recurring_events\EventCreationService; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Messenger\Messenger; @@ -13,6 +12,12 @@ use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Entity\EntityFieldManager; use Drupal\Core\Field\FieldTypePluginManager; use Drupal\recurring_events\Plugin\Field\FieldWidget\ConsecutiveRecurringDateWidget; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; +use Drupal\Component\Datetime\TimeInterface; +use Drupal\Core\Session\AccountProxyInterface; +use Drupal\Core\Config\ConfigFactory; +use Drupal\Core\Extension\ModuleHandler; /** * Form controller for the eventseries entity create form. @@ -70,6 +75,34 @@ class EventSeriesForm extends ContentEntityForm { */ protected $fieldTypePluginManager; + /** + * The current user. + * + * @var \Drupal\Core\Session\AccountProxyInterface + */ + protected $currentUser; + + /** + * The time service. + * + * @var \Drupal\Component\Datetime\TimeInterface + */ + protected $time; + + /** + * The module handler service. + * + * @var \Drupal\Core\Extension\ModuleHandler + */ + protected $moduleHandler; + + /** + * The configuration factory. + * + * @var \Drupal\Core\Config\ConfigFactory + */ + protected $configFactory; + /** * {@inheritdoc} */ @@ -77,11 +110,16 @@ class EventSeriesForm extends ContentEntityForm { return new static( $container->get('recurring_events.event_creation_service'), $container->get('entity_type.manager')->getStorage('eventseries'), - $container->get('entity.manager'), $container->get('messenger'), $container->get('date.formatter'), $container->get('entity_field.manager'), - $container->get('plugin.manager.field.field_type') + $container->get('plugin.manager.field.field_type'), + $container->get('entity.repository'), + $container->get('entity_type.bundle.info'), + $container->get('datetime.time'), + $container->get('current_user'), + $container->get('module_handler'), + $container->get('config.factory') ); } @@ -92,8 +130,6 @@ class EventSeriesForm extends ContentEntityForm { * The event creation service. * @param \Drupal\Core\Entity\EntityStorageInterface $storage * The storage interface. - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager service. * @param \Drupal\Core\Messenger\Messenger $messenger * The messenger service. * @param \Drupal\Core\Datetime\DateFormatter $date_formatter @@ -102,15 +138,31 @@ class EventSeriesForm extends ContentEntityForm { * The entity field manager. * @param \Drupal\Core\Field\FieldTypePluginManager $field_type_plugin_manager * The field type plugin manager. + * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository + * The entity repository interface. + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info + * The entity type bundle info interface. + * @param \Drupal\Component\Datetime\TimeInterface $time + * The time interface. + * @param \Drupal\Core\Session\AccountProxyInterface $current_user + * The current user. + * @param \Drupal\Core\Extension\ModuleHandler $module_handler + * The module handler service. + * @param \Drupal\Core\Config\ConfigFactory $config_factory + * The config factory. */ - public function __construct(EventCreationService $creation_service, EntityStorageInterface $storage, EntityManagerInterface $entity_manager, Messenger $messenger, DateFormatter $date_formatter, EntityFieldManager $entity_field_manager, FieldTypePluginManager $field_type_plugin_manager) { + public function __construct(EventCreationService $creation_service, EntityStorageInterface $storage, Messenger $messenger, DateFormatter $date_formatter, EntityFieldManager $entity_field_manager, FieldTypePluginManager $field_type_plugin_manager, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, AccountProxyInterface $current_user = NULL, ModuleHandler $module_handler = NULL, ConfigFactory $config_factory = NULL) { $this->creationService = $creation_service; $this->storage = $storage; $this->messenger = $messenger; $this->dateFormatter = $date_formatter; $this->entityFieldManager = $entity_field_manager; $this->fieldTypePluginManager = $field_type_plugin_manager; - parent::__construct($entity_manager); + $this->time = $time; + $this->currentUser = $current_user; + $this->moduleHandler = $module_handler; + $this->configFactory = $config_factory; + parent::__construct($entity_repository, $entity_type_bundle_info, $time); } /** @@ -119,13 +171,13 @@ class EventSeriesForm extends ContentEntityForm { public function buildForm(array $form, FormStateInterface $form_state) { $form = parent::buildForm($form, $form_state); - $config = \Drupal::config('recurring_events.eventseries.config'); - - $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form'); + $config = $this->configFactory->get('recurring_events.eventseries.config'); /* @var $entity \Drupal\recurring_events\Entity\EventSeries */ $entity = $this->entity; + $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form'); + $form['custom_date']['#states'] = [ 'visible' => [ ':input[name="recur_type"]' => ['value' => 'custom'], @@ -137,7 +189,7 @@ class EventSeriesForm extends ContentEntityForm { // necessary fields from the entity form. $recur_fields = $this->creationService->getRecurFieldTypes(FALSE); $all_recur_fields = $recur_fields; - \Drupal::moduleHandler()->alter('recurring_events_recur_field_types', $recur_fields); + $this->moduleHandler->alter('recurring_events_recur_field_types', $recur_fields); $form['recur_type']['widget']['#options'] = $recur_fields; @@ -220,7 +272,7 @@ class EventSeriesForm extends ContentEntityForm { '#title' => $this->t('Status'), '#attributes' => ['class' => ['entity-meta__header']], '#tree' => TRUE, - '#access' => \Drupal::currentUser()->hasPermission('administer eventseries'), + '#access' => $this->currentUser->hasPermission('administer eventseries'), ]; $form['meta']['published'] = [ '#type' => 'item', @@ -254,8 +306,7 @@ class EventSeriesForm extends ContentEntityForm { /* @var $entity \Drupal\recurring_events\Entity\EventSeries */ $entity = $this->entity; - - $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form'); + $editing = ($form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form'); $trigger = $form_state->getTriggeringElement(); $ignored_triggers = [ @@ -277,24 +328,19 @@ class EventSeriesForm extends ContentEntityForm { */ public function save(array $form, FormStateInterface $form_state) { $entity = $this->getEntity(); - $original = NULL; // Save as a new revision if requested to do so. if (!$form_state->isValueEmpty('revision') && $form_state->getValue('revision') != FALSE) { $entity->setNewRevision(); // If a new revision is created, save the current user as revision author. - $entity->setRevisionCreationTime(REQUEST_TIME); - $entity->setRevisionUserId(\Drupal::currentUser()->id()); + $entity->setRevisionCreationTime($this->time->getRequestTime()); + $entity->setRevisionUserId($this->currentUser->id()); } else { $entity->setNewRevision(FALSE); } - if (!$entity->isNew()) { - $original = $this->storage->loadUnchanged($entity->id()); - } - if ($entity->isDefaultTranslation()) { $this->messenger->addStatus($this->t('Successfully saved the %name event series', [ '%name' => $entity->title->value, diff --git a/src/Form/EventSeriesRevisionDeleteForm.php b/src/Form/EventSeriesRevisionDeleteForm.php index 8f33e84364520cd309d1a000f31034b919e78da2..ed515e5380495707f7306d29cced86d556d7bd96 100644 --- a/src/Form/EventSeriesRevisionDeleteForm.php +++ b/src/Form/EventSeriesRevisionDeleteForm.php @@ -10,6 +10,7 @@ use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Messenger\Messenger; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Provides a form for deleting an eventseries revision. @@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger; */ class EventSeriesRevisionDeleteForm extends ConfirmFormBase { + use StringTranslationTrait; + /** * The eventseries revision. * @@ -96,7 +99,7 @@ class EventSeriesRevisionDeleteForm extends ConfirmFormBase { * {@inheritdoc} */ public function getQuestion() { - return t('Are you sure you want to delete the revision from %revision-date?', [ + return $this->t('Are you sure you want to delete the revision from %revision-date?', [ '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()), ]); } @@ -112,7 +115,7 @@ class EventSeriesRevisionDeleteForm extends ConfirmFormBase { * {@inheritdoc} */ public function getConfirmText() { - return t('Delete'); + return $this->t('Delete'); } /** @@ -132,7 +135,7 @@ class EventSeriesRevisionDeleteForm extends ConfirmFormBase { $this->eventSeriesStorage->deleteRevision($this->revision->getRevisionId()); $this->logger('content')->notice('eventseries: deleted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]); - $this->messenger->addMessage(t('Revision from %revision-date of eventseries %title has been deleted.', [ + $this->messenger->addMessage($this->t('Revision from %revision-date of eventseries %title has been deleted.', [ '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime()), '%title' => $this->revision->label(), ])); diff --git a/src/Form/EventSeriesRevisionRevertForm.php b/src/Form/EventSeriesRevisionRevertForm.php index e09bb4f4578859945fb2fc7dbbe55b792823bf50..5c2412c58ff12ff092d438bb0f010fa16e7db496 100644 --- a/src/Form/EventSeriesRevisionRevertForm.php +++ b/src/Form/EventSeriesRevisionRevertForm.php @@ -10,6 +10,7 @@ use Drupal\Core\Url; use Drupal\recurring_events\EventInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Messenger\Messenger; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Provides a form for reverting an eventseries revision. @@ -18,6 +19,8 @@ use Drupal\Core\Messenger\Messenger; */ class EventSeriesRevisionRevertForm extends ConfirmFormBase { + use StringTranslationTrait; + /** * The eventseries revision. * @@ -84,7 +87,7 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase { * {@inheritdoc} */ public function getQuestion() { - return t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); + return $this->t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); } /** @@ -98,7 +101,7 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase { * {@inheritdoc} */ public function getConfirmText() { - return t('Revert'); + return $this->t('Revert'); } /** @@ -127,11 +130,11 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase { $original_revision_timestamp = $this->revision->getRevisionCreationTime(); $this->revision = $this->prepareRevertedRevision($this->revision, $form_state); - $this->revision->revision_log = t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]); + $this->revision->revision_log = $this->t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]); $this->revision->save(); $this->logger('content')->notice('eventseries: reverted %title revision %revision.', ['%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]); - $this->messenger->addMessage(t('eventseries %title has been reverted to the revision from %revision-date.', [ + $this->messenger->addMessage($this->t('eventseries %title has been reverted to the revision from %revision-date.', [ '%title' => $this->revision->label(), '%revision-date' => $this->dateFormatter->format($original_revision_timestamp), ])); @@ -155,7 +158,7 @@ class EventSeriesRevisionRevertForm extends ConfirmFormBase { protected function prepareRevertedRevision(EventInterface $revision, FormStateInterface $form_state) { $revision->setNewRevision(); $revision->isDefaultRevision(TRUE); - $revision->setRevisionCreationTime(REQUEST_TIME); + $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime()); return $revision; } diff --git a/src/Form/EventSeriesRevisionRevertTranslationForm.php b/src/Form/EventSeriesRevisionRevertTranslationForm.php index 17a15ac2c98bfea6fd9086d67ffafa2cceeaaf52..448b3c681de8bc7573ead0331e5454200bf56fb7 100644 --- a/src/Form/EventSeriesRevisionRevertTranslationForm.php +++ b/src/Form/EventSeriesRevisionRevertTranslationForm.php @@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\recurring_events\EventInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Component\Datetime\TimeInterface; /** * Provides form to revert an eventseries revision for a single translation. @@ -30,6 +31,13 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert */ protected $languageManager; + /** + * The time service. + * + * @var \Drupal\Component\Datetime\TimeInterface + */ + protected $time; + /** * Constructs a new EventSeriesRevisionRevertTranslationForm. * @@ -39,10 +47,13 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert * The date formatter service. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. + * @param \Drupal\Component\Datetime\TimeInterface $time + * The time service. */ - public function __construct(EntityStorageInterface $entity_storage, DateFormatterInterface $date_formatter, LanguageManagerInterface $language_manager) { + public function __construct(EntityStorageInterface $entity_storage, DateFormatterInterface $date_formatter, LanguageManagerInterface $language_manager, TimeInterface $time) { parent::__construct($entity_storage, $date_formatter); $this->languageManager = $language_manager; + $this->time = $time; } /** @@ -52,7 +63,8 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert return new static( $container->get('entity.manager')->getStorage('eventseries'), $container->get('date.formatter'), - $container->get('language_manager') + $container->get('language_manager'), + $container->get('datetime.time') ); } @@ -67,7 +79,7 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert * {@inheritdoc} */ public function getQuestion() { - return t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); + return $this->t('Are you sure you want to revert @language translation to the revision from %revision-date?', ['@language' => $this->languageManager->getLanguageName($this->langcode), '%revision-date' => $this->dateFormatter->format($this->revision->getRevisionCreationTime())]); } /** @@ -106,7 +118,7 @@ class EventSeriesRevisionRevertTranslationForm extends EventSeriesRevisionRevert $latest_revision_translation->setNewRevision(); $latest_revision_translation->isDefaultRevision(TRUE); - $revision->setRevisionCreationTime(REQUEST_TIME); + $revision->setRevisionCreationTime($this->time->getRequestTime()); return $latest_revision_translation; } diff --git a/src/Form/EventSeriesSettingsForm.php b/src/Form/EventSeriesSettingsForm.php index 4e7762ac4546b2dc87d82e6875b64297d3001468..3e26270c4ef6c879e80b882066d19714837c1063 100644 --- a/src/Form/EventSeriesSettingsForm.php +++ b/src/Form/EventSeriesSettingsForm.php @@ -6,6 +6,8 @@ use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; use Drupal\Core\Link; +use Drupal\recurring_events\EventCreationService; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Class EventSeriesSettingsForm. @@ -14,6 +16,32 @@ use Drupal\Core\Link; */ class EventSeriesSettingsForm extends ConfigFormBase { + /** + * The event creation service. + * + * @var \Drupal\recurring_events\EventCreationService + */ + protected $creationService; + + /** + * Constructs a new EventSeriesSettingsForm. + * + * @param \Drupal\recurring_events\EventCreationService $creation_service + * The event creation service. + */ + public function __construct(EventCreationService $creation_service) { + $this->creationService = $creation_service; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('recurring_events.event_creation_service') + ); + } + /** * Returns a unique string identifying the form. * @@ -128,13 +156,13 @@ class EventSeriesSettingsForm extends ConfigFormBase { ]; $days = [ - 'monday' => t('Monday'), - 'tuesday' => t('Tuesday'), - 'wednesday' => t('Wednesday'), - 'thursday' => t('Thursday'), - 'friday' => t('Friday'), - 'saturday' => t('Saturday'), - 'sunday' => t('Sunday'), + 'monday' => $this->t('Monday'), + 'tuesday' => $this->t('Tuesday'), + 'wednesday' => $this->t('Wednesday'), + 'thursday' => $this->t('Thursday'), + 'friday' => $this->t('Friday'), + 'saturday' => $this->t('Saturday'), + 'sunday' => $this->t('Sunday'), ]; $form['creation']['days'] = [ @@ -164,7 +192,7 @@ class EventSeriesSettingsForm extends ConfigFormBase { '#default_value' => $config->get('includes'), ]; - $fields = \Drupal::service('recurring_events.event_creation_service')->getRecurFieldTypes(FALSE); + $fields = $this->creationService->getRecurFieldTypes(FALSE); $form['creation']['enabled_fields'] = [ '#type' => 'checkboxes', diff --git a/src/Form/EventSeriesTypeDeleteForm.php b/src/Form/EventSeriesTypeDeleteForm.php new file mode 100644 index 0000000000000000000000000000000000000000..66dab774e9e7b55f0284ea6a773beff30ffc5c3b --- /dev/null +++ b/src/Form/EventSeriesTypeDeleteForm.php @@ -0,0 +1,105 @@ +<?php + +namespace Drupal\recurring_events\Form; + +use Drupal\Core\Entity\EntityConfirmFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Url; +use Drupal\Core\Messenger\Messenger; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Builds the form to delete Event series type entities. + */ +class EventSeriesTypeDeleteForm extends EntityConfirmFormBase { + + /** + * The messenger service. + * + * @var \Drupal\Core\Messenger\Messenger + */ + protected $messenger; + + /** + * Construct a EventSeriesTypeDeleteForm. + * + * @param \Drupal\Core\Messenger\Messenger $messenger + * The messenger service. + */ + public function __construct(Messenger $messenger) { + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('messenger') + ); + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + $descriptions = []; + $instance_type = \Drupal::entityTypeManager()->getStorage('eventinstance_type')->load($this->entity->id()); + + if (!empty($instance_type)) { + $descriptions[] = $this->t('Deleting this event series type will also delete the corresponding event instance type.'); + } + + if (\Drupal::moduleHandler()->moduleExists('recurring_events_registration')) { + $registrant_types = \Drupal::entityTypeManager()->getStorage('registrant_type')->load($this->entity->id()); + if (!empty($registrant_types)) { + $descriptions[] = $this->t('Deleting this event series type will also delete the corresponding registrant type.'); + } + } + + return implode("\r\n", $descriptions); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return new Url('entity.eventseries_type.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('Succesfully deleted @type: @label.', + [ + '@type' => $this->entity->bundle(), + '@label' => $this->entity->label(), + ] + ) + ); + + \Drupal::cache('menu')->invalidateAll(); + \Drupal::service('plugin.manager.menu.link')->rebuild(); + + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/src/Form/EventSeriesTypeForm.php b/src/Form/EventSeriesTypeForm.php new file mode 100644 index 0000000000000000000000000000000000000000..93d1e2d9f87b74bb29c60a65909a06cee0a007fc --- /dev/null +++ b/src/Form/EventSeriesTypeForm.php @@ -0,0 +1,98 @@ +<?php + +namespace Drupal\recurring_events\Form; + +use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\Messenger; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Class EventSeriesTypeForm. + */ +class EventSeriesTypeForm extends EntityForm { + + /** + * The messenger service. + * + * @var \Drupal\Core\Messenger\Messenger + */ + protected $messenger; + + /** + * Constructs a new EventSeriesTypeForm. + * + * @param \Drupal\Core\Messenger\Messenger $messenger + * The messenger service. + */ + public function __construct(Messenger $messenger) { + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('messenger') + ); + } + + /** + * {@inheritdoc} + */ + public function form(array $form, FormStateInterface $form_state) { + $form = parent::form($form, $form_state); + + $eventseries_type = $this->entity; + $form['label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $eventseries_type->label(), + '#description' => $this->t("Label for the Event series type."), + '#required' => TRUE, + ]; + + $form['id'] = [ + '#type' => 'machine_name', + '#default_value' => $eventseries_type->id(), + '#machine_name' => [ + 'exists' => '\Drupal\recurring_events\Entity\EventSeriesType::load', + ], + '#disabled' => !$eventseries_type->isNew(), + ]; + + $form['description'] = [ + '#title' => $this->t('Description'), + '#type' => 'textarea', + '#default_value' => $eventseries_type->getDescription(), + '#description' => $this->t('This text will be displayed on the <em>Add event</em> page.'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function save(array $form, FormStateInterface $form_state) { + $eventseries_type = $this->entity; + $status = $eventseries_type->save(); + + switch ($status) { + case SAVED_NEW: + $this->messenger->addMessage($this->t('Created the %label event series type.', [ + '%label' => $eventseries_type->label(), + ])); + break; + + default: + $this->messenger->addMessage($this->t('Saved the %label event series type.', [ + '%label' => $eventseries_type->label(), + ])); + } + $form_state->setRedirectUrl($eventseries_type->toUrl('collection')); + } + +} diff --git a/src/Form/FieldInheritanceDeleteForm.php b/src/Form/FieldInheritanceDeleteForm.php deleted file mode 100644 index 1f140fee8655a2f8c10d13bb7dd88a8a6555f195..0000000000000000000000000000000000000000 --- a/src/Form/FieldInheritanceDeleteForm.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Form; - -use Drupal\Core\Entity\EntityConfirmFormBase; -use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Url; -use Drupal\Core\Messenger\Messenger; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityFieldManager; - -/** - * Builds the form to delete Field inheritance entities. - */ -class FieldInheritanceDeleteForm extends EntityConfirmFormBase { - - /** - * The messenger service. - * - * @var \Drupal\Core\Messenger\Messenger - */ - protected $messenger; - - /** - * The entity field manager service. - * - * @var \Drupal\Core\Entity\EntityFieldManager - */ - protected $entityFieldManager; - - /** - * Construct an EventSeriesDeleteForm. - * - * @param \Drupal\Core\Messenger\Messenger $messenger - * The messenger service. - * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager - * The entity field manager service. - */ - public function __construct(Messenger $messenger, EntityFieldManager $entity_field_manager) { - $this->messenger = $messenger; - $this->entityFieldManager = $entity_field_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('messenger'), - $container->get('entity_field.manager') - ); - } - - /** - * {@inheritdoc} - */ - public function getQuestion() { - return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]); - } - - /** - * {@inheritdoc} - */ - public function getCancelUrl() { - return new Url('entity.field_inheritance.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('content @type: deleted @label.', [ - '@type' => $this->entity->bundle(), - '@label' => $this->entity->label(), - ]) - ); - - $this->entityFieldManager->clearCachedFieldDefinitions(); - $form_state->setRedirectUrl($this->getCancelUrl()); - } - -} diff --git a/src/Form/FieldInheritanceForm.php b/src/Form/FieldInheritanceForm.php deleted file mode 100644 index b5d7fa16e48709ad015e805bed236e28eefe33fa..0000000000000000000000000000000000000000 --- a/src/Form/FieldInheritanceForm.php +++ /dev/null @@ -1,230 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Form; - -use Drupal\Core\Entity\EntityForm; -use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Messenger\Messenger; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\EntityFieldManager; -use Drupal\recurring_events\FieldInheritancePluginManager; - -/** - * Class FieldInheritanceForm. - */ -class FieldInheritanceForm extends EntityForm { - - /** - * The messenger service. - * - * @var \Drupal\Core\Messenger\Messenger - */ - protected $messenger; - - /** - * The entity field manager service. - * - * @var \Drupal\Core\Entity\EntityFieldManager - */ - protected $entityFieldManager; - - /** - * The field inheritance plugin manager. - * - * @var \Drupal\recurring_events\FieldInheritancePluginManager - */ - protected $fieldInheritance; - - /** - * Construct an FieldInheritanceForm. - * - * @param \Drupal\Core\Messenger\Messenger $messenger - * The messenger service. - * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager - * The entity field manager service. - * @param \Drupal\recurring_events\FieldInheritancePluginManager $field_inheritance - * The field inheritance plugin manager. - */ - public function __construct(Messenger $messenger, EntityFieldManager $entity_field_manager, FieldInheritancePluginManager $field_inheritance) { - $this->messenger = $messenger; - $this->entityFieldManager = $entity_field_manager; - $this->fieldInheritance = $field_inheritance; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('messenger'), - $container->get('entity_field.manager'), - $container->get('plugin.manager.field_inheritance') - ); - } - - /** - * {@inheritdoc} - */ - public function form(array $form, FormStateInterface $form_state) { - $form = parent::form($form, $form_state); - - $field_inheritance = $this->entity; - $form['label'] = [ - '#type' => 'textfield', - '#title' => $this->t('Label'), - '#maxlength' => 255, - '#default_value' => $field_inheritance->label(), - '#description' => $this->t("Label for the Field inheritance."), - '#required' => TRUE, - ]; - - $form['id'] = [ - '#type' => 'machine_name', - '#default_value' => $field_inheritance->id(), - '#machine_name' => [ - 'exists' => '\Drupal\recurring_events\Entity\FieldInheritance::load', - ], - '#disabled' => !$field_inheritance->isNew(), - ]; - - $help = [ - $this->t('<b>Inherit</b> - Pull field data directly from the series.'), - $this->t('<b>Prepend</b> - Place instance data above series data.'), - $this->t('<b>Append</b> - Place instance data below series data.'), - $this->t('<b>Fallback</b> - Show instance data, if set, otherwise show series data.'), - ]; - - $form['type'] = [ - '#type' => 'select', - '#title' => $this->t('Inheritance Strategy'), - '#description' => $this->t('Select the method/strategy used to inherit data.'), - '#options' => [ - 'inherit' => $this->t('Inherit'), - 'prepend' => $this->t('Prepend'), - 'append' => $this->t('Append'), - 'fallback' => $this->t('Fallback'), - ], - '#required' => TRUE, - '#default_value' => $field_inheritance->type() ?: 'inherit', - ]; - $form['information'] = [ - '#type' => 'markup', - '#prefix' => '<p>', - '#markup' => implode('</p><p>', $help), - '#suffix' => '</p>', - ]; - - $series_fields = array_keys($this->entityFieldManager->getFieldDefinitions('eventseries', 'eventseries')); - $series_fields = array_combine($series_fields, $series_fields); - - $form['sourceField'] = [ - '#type' => 'select', - '#title' => $this->t('Source/Series Field'), - '#description' => $this->t('Select the field on the series from which to inherit data.'), - '#options' => $series_fields, - '#required' => TRUE, - '#default_value' => $field_inheritance->sourceField(), - ]; - - $instance_fields = array_keys($this->entityFieldManager->getFieldDefinitions('eventinstance', 'eventinstance')); - $instance_fields = array_combine($instance_fields, $instance_fields); - - // You should never be able to use the inherited field as part of an - // inheritance as that creates an infinite loop. - if (!empty($field_inheritance->id()) && !empty($instance_fields[$field_inheritance->id()])) { - unset($instance_fields[$field_inheritance->id()]); - } - - $form['entityField'] = [ - '#type' => 'select', - '#title' => $this->t('Entity/Instance Field'), - '#description' => $this->t('Select the field on the instance to use during inheritance.'), - '#options' => $instance_fields, - '#states' => [ - 'visible' => [ - 'select[name="type"]' => ['!value' => 'inherit'], - ], - 'required' => [ - 'select[name="type"]' => ['!value' => 'inherit'], - ], - ], - '#default_value' => $field_inheritance->entityField(), - ]; - - $plugins = array_keys($this->fieldInheritance->getDefinitions()); - $plugins = array_combine($plugins, $plugins); - - $form['plugin'] = [ - '#type' => 'select', - '#title' => $this->t('Inheritance Plugin'), - '#description' => $this->t('Select the plugin used to perform the inheritance.'), - '#options' => $plugins, - '#required' => TRUE, - '#default_value' => $field_inheritance->plugin(), - ]; - - return $form; - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, FormStateInterface $form_state) { - parent::validateForm($form, $form_state); - $values = $form_state->getValues(); - - if (!empty($values['sourceField']) && !empty($values['entityField'])) { - $series_definitions = $this->entityFieldManager->getFieldDefinitions('eventseries', 'eventseries'); - $instance_definitions = $this->entityFieldManager->getFieldDefinitions('eventinstance', 'eventinstance'); - - if ($series_definitions[$values['sourceField']]->getType() !== $instance_definitions[$values['entityField']]->getType()) { - $message = $this->t('Source and entity field definition types must be the same to inherit data. Source - @source_name type: @source_type. Entity - @entity_name type: @entity_type', [ - '@source_name' => $values['sourceField'], - '@source_type' => $series_definitions[$values['sourceField']]->getType(), - '@entity_name' => $values['entityField'], - '@entity_type' => $instance_definitions[$values['entityField']]->getType(), - ]); - $form_state->setErrorByName('sourceField', $message); - $form_state->setErrorByName('entityField', $message); - } - - $plugin_definition = $this->fieldInheritance->getDefinition($values['plugin']); - $field_types = $plugin_definition['types']; - - if (!in_array($series_definitions[$values['sourceField']]->getType(), $field_types)) { - $message = $this->t('The selected plugin @plugin does not support @source_type fields. The supported field types are: @field_types', [ - '@plugin' => $values['plugin'], - '@source_type' => $series_definitions[$values['sourceField']]->getType(), - '@field_types' => implode(',', $field_types), - ]); - $form_state->setErrorByName('sourceField', $message); - $form_state->setErrorByName('plugin', $message); - } - - } - } - - /** - * {@inheritdoc} - */ - public function save(array $form, FormStateInterface $form_state) { - $field_inheritance = $this->entity; - $status = $field_inheritance->save(); - - switch ($status) { - case SAVED_NEW: - $this->messenger->addMessage($this->t('Created the %label Field inheritance.', [ - '%label' => $field_inheritance->label(), - ])); - break; - - default: - $this->messenger->addMessage($this->t('Saved the %label Field inheritance.', [ - '%label' => $field_inheritance->label(), - ])); - } - $this->entityFieldManager->clearCachedFieldDefinitions(); - $form_state->setRedirectUrl($field_inheritance->toUrl('collection')); - } - -} diff --git a/src/IncludedDatesHtmlRouteProvider.php b/src/IncludedDatesHtmlRouteProvider.php index 6fe244930c006464a403442b921f41be653267ad..b7bebda5863dca844bcbadf792b8c67084076f4a 100644 --- a/src/IncludedDatesHtmlRouteProvider.php +++ b/src/IncludedDatesHtmlRouteProvider.php @@ -4,7 +4,6 @@ namespace Drupal\recurring_events; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider; -use Symfony\Component\Routing\Route; /** * Provides routes for Included dates entities. @@ -19,9 +18,6 @@ class IncludedDatesHtmlRouteProvider extends AdminHtmlRouteProvider { */ public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); - - // Provide your custom entity routes here. - return $collection; } diff --git a/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php b/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php index ace9c0f5ef6b89b20e3c5936a1f9d417cfc940c2..9d1103ee23dc9da29b688df5c24386e321a78115 100644 --- a/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php +++ b/src/Plugin/Field/FieldFormatter/EventInstanceDateFormatter.php @@ -9,6 +9,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Url; use Drupal\Core\Link; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'recurring events eventinstance date' formatter. @@ -24,6 +25,8 @@ use Drupal\Core\Link; */ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { + use StringTranslationTrait; + /** * {@inheritdoc} */ @@ -40,7 +43,7 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { */ public function settingsForm(array $form, FormStateInterface $form_state) { $elements['link'] = [ - '#title' => t('Link date to the referenced entity'), + '#title' => $this->t('Link date to the referenced entity'), '#type' => 'checkbox', '#default_value' => $this->getSetting('link'), ]; @@ -50,7 +53,7 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { $elements['date_format'] = [ '#type' => 'textfield', - '#title' => t('Date Format @link', [ + '#title' => $this->t('Date Format @link', [ '@link' => $php_date_link->toString(), ]), '#required' => TRUE, @@ -58,9 +61,9 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { ]; $elements['separator'] = [ - '#title' => t('Separator'), + '#title' => $this->t('Separator'), '#type' => 'textfield', - '#description' => t('Enter the separator to use between start and end dates.'), + '#description' => $this->t('Enter the separator to use between start and end dates.'), '#default_value' => $this->getSetting('separator'), ]; @@ -72,11 +75,11 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { */ public function settingsSummary() { $summary = []; - $summary[] = $this->getSetting('link') ? t('Link to the referenced entity') : t('No link'); - $summary[] = t('Format: %format', [ + $summary[] = $this->getSetting('link') ? $this->t('Link to the referenced entity') : $this->t('No link'); + $summary[] = $this->t('Format: %format', [ '%format' => $this->getSetting('date_format'), ]); - $summary[] = t('Separator: %separator', [ + $summary[] = $this->t('Separator: %separator', [ '%separator' => $this->getSetting('separator'), ]); return $summary; @@ -98,7 +101,7 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) { $date_string = ''; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); if (!empty($entity->date->start_date) && !empty($entity->date->end_date)) { /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */ $start_date = $entity->date->start_date; @@ -152,6 +155,15 @@ class EventInstanceDateFormatter extends EntityReferenceFormatterBase { $elements[$delta]['#cache']['tags'] = $entity->getCacheTags(); } + usort($elements, function ($a, $b) { + $a_date = $a['#options']['entity']->date->start_date->getTimestamp(); + $b_date = $b['#options']['entity']->date->start_date->getTimestamp(); + if ($a_date == $b_date) { + return 0; + } + return ($a_date < $b_date) ? -1 : 1; + }); + return $elements; } diff --git a/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php b/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php index 95bf5ef37fef4352d9115822a365a989eb680595..5b001517dd3c09d80ba05033dee3db16d7393492 100644 --- a/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php +++ b/src/Plugin/Field/FieldType/ConsecutiveRecurringDate.php @@ -137,8 +137,7 @@ class ConsecutiveRecurringDate extends DateRangeItem implements RecurringEventsF public static function convertFormConfigToArray(FormStateInterface $form_state) { $config = []; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); $user_input = $form_state->getUserInput(); if (!empty($user_input['consecutive_recurring_date'][0]['value']['date']) @@ -239,7 +238,7 @@ class ConsecutiveRecurringDate extends DateRangeItem implements RecurringEventsF * {@inheritdoc} */ public static function calculateInstances(array $form_data) { - $dates = $events_to_create = []; + $events_to_create = []; $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $daily_dates = static::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date']); @@ -342,7 +341,7 @@ class ConsecutiveRecurringDate extends DateRangeItem implements RecurringEventsF $count = 0; $max_time = clone $date; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $time_parts = static::convertTimeTo24hourFormat($form_data['end_time']); diff --git a/src/Plugin/Field/FieldType/DailyRecurringDate.php b/src/Plugin/Field/FieldType/DailyRecurringDate.php index d59c68d26e3578063eb9b0c5523ef7cbb5ad2f49..5917817d55c4dbb4ac34cda7be6f5d22aa71f5ae 100644 --- a/src/Plugin/Field/FieldType/DailyRecurringDate.php +++ b/src/Plugin/Field/FieldType/DailyRecurringDate.php @@ -91,8 +91,7 @@ class DailyRecurringDate extends DateRangeItem implements RecurringEventsFieldTy public static function convertFormConfigToArray(FormStateInterface $form_state) { $config = []; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); $user_input = $form_state->getUserInput(); $time = $user_input['daily_recurring_date'][0]['time']; @@ -157,7 +156,7 @@ class DailyRecurringDate extends DateRangeItem implements RecurringEventsFieldTy * {@inheritdoc} */ public static function calculateInstances(array $form_data) { - $dates = $events_to_create = []; + $events_to_create = []; $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $daily_dates = static::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date']); diff --git a/src/Plugin/Field/FieldType/MonthlyRecurringDate.php b/src/Plugin/Field/FieldType/MonthlyRecurringDate.php index 21154441d854ea4004f803fec47f6d7f3363105e..e28759093241c7e729273a5fe35b9ee93272520a 100644 --- a/src/Plugin/Field/FieldType/MonthlyRecurringDate.php +++ b/src/Plugin/Field/FieldType/MonthlyRecurringDate.php @@ -115,8 +115,7 @@ class MonthlyRecurringDate extends WeeklyRecurringDate implements RecurringEvent public static function convertFormConfigToArray(FormStateInterface $form_state) { $config = []; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); $user_input = $form_state->getUserInput(); $time = $user_input['monthly_recurring_date'][0]['time']; diff --git a/src/Plugin/Field/FieldType/WeeklyRecurringDate.php b/src/Plugin/Field/FieldType/WeeklyRecurringDate.php index 28cc10494a484e40adadc078d957eb98f82df67d..ef29a5ff60a32a89b6426fd56f6e8f4c4a49c001 100644 --- a/src/Plugin/Field/FieldType/WeeklyRecurringDate.php +++ b/src/Plugin/Field/FieldType/WeeklyRecurringDate.php @@ -80,8 +80,7 @@ class WeeklyRecurringDate extends DailyRecurringDate implements RecurringEventsF public static function convertFormConfigToArray(FormStateInterface $form_state) { $config = []; - $user_timezone = new \DateTimeZone(drupal_get_user_timezone()); - $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); + $user_timezone = new \DateTimeZone(date_default_timezone_get()); $user_input = $form_state->getUserInput(); $time = $user_input['weekly_recurring_date'][0]['time']; diff --git a/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php index 0aee37ef6b45772b40854ae6226a92295e4bf334..6800388b5ee7e119c76e8272e12c806a153387f4 100644 --- a/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/ConsecutiveRecurringDateWidget.php @@ -11,6 +11,7 @@ use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\HtmlCommand; use Drupal\recurring_events\Plugin\Field\FieldType\ConsecutiveRecurringDate; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'consecutive recurring date' widget. @@ -26,6 +27,7 @@ use Drupal\recurring_events\Plugin\Field\FieldType\ConsecutiveRecurringDate; class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { use RecurringEventsFieldTrait; + use StringTranslationTrait; /** * {@inheritdoc} @@ -42,8 +44,9 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { ], ]; $element['#element_validate'][] = [$this, 'validateThreshold']; + $element['#element_validate'][] = [$this, 'validateForm']; - $element['value']['#title'] = t('Create Events Between'); + $element['value']['#title'] = $this->t('Create Events Between'); $element['value']['#weight'] = 1; $element['value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['value']['#date_date_element'] = 'date'; @@ -55,7 +58,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { 'wrapper' => 'eventseries-edit-form', ]; - $element['end_value']['#title'] = t('And'); + $element['end_value']['#title'] = $this->t('And'); $element['end_value']['#weight'] = 2; $element['end_value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['end_value']['#date_date_element'] = 'date'; @@ -73,7 +76,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $end_time = end($time_keys); $element['time'] = [ '#type' => 'select', - '#title' => t('First Event Starts At'), + '#title' => $this->t('First Event Starts At'), '#options' => $times, '#default_value' => $items[$delta]->time ?: $start_time, '#weight' => 3, @@ -86,7 +89,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['end_time'] = [ '#type' => 'select', - '#title' => t('Final Event Starts At'), + '#title' => $this->t('Final Event Starts At'), '#options' => $times, '#default_value' => $items[$delta]->end_time ?: $end_time, '#weight' => 4, @@ -101,7 +104,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['duration'] = [ '#type' => 'number', - '#title' => t('Event Duration'), + '#title' => $this->t('Event Duration'), '#default_value' => $items[$delta]->duration ?: 5, '#weight' => 5, '#ajax' => [ @@ -113,7 +116,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['duration_units'] = [ '#type' => 'select', - '#title' => t('Event Duration'), + '#title' => $this->t('Event Duration'), '#options' => $units, '#default_value' => $items[$delta]->duration_units ?: 'minute', '#weight' => 6, @@ -147,14 +150,14 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $element['buffer'] = [ '#type' => 'number', - '#title' => t('Event Buffer'), + '#title' => $this->t('Event Buffer'), '#default_value' => $items[$delta]->buffer ?: 0, '#weight' => 7, ]; $element['buffer_units'] = [ '#type' => 'select', - '#title' => t('Event Buffer'), + '#title' => $this->t('Event Buffer'), '#options' => $units, '#default_value' => $items[$delta]->buffer_units ?: 'minute', '#weight' => 8, @@ -197,7 +200,9 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { */ public function changeDuration(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $form_id = $form_state->getBuildInfo()['form_id'] == 'eventseries_edit_form' ? 'eventseries-edit-form' : 'eventseries-add-form'; + /* @var $entity \Drupal\recurring_events\Entity\EventSeries */ + $entity = $form_state->getformObject()->getEntity(); + $form_id = $form_state->getBuildInfo()['form_id'] == 'eventseries_' . $entity->bundle() . '_edit_form' ? 'eventseries-' . $entity->bundle() . '-edit-form' : 'eventseries-' . $entity->bundle() . '-add-form'; $response->addCommand(new HtmlCommand('#' . $form_id, $form)); return $response; } @@ -209,7 +214,7 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { $day_count = $time_count = $total = 0; $utc_timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE); $form_data = ConsecutiveRecurringDate::convertFormConfigToArray($form_state); - if (!empty($form_data['start_date']) && !empty($form_data['end_date'])) { + if (!empty($form_data['start_date']) && !empty($form_data['end_date']) && !empty($form_data['duration'])) { $day_count = ConsecutiveRecurringDate::findDailyDatesBetweenDates($form_data['start_date'], $form_data['end_date'], TRUE); $time_parts = static::convertTimeTo24hourFormat($form_data['time']); if (!empty($time_parts)) { @@ -251,4 +256,60 @@ class ConsecutiveRecurringDateWidget extends DateRangeDefaultWidget { } } + /** + * Element validate callback to ensure that widget values are valid. + * + * @param array $element + * An associative array containing the properties and children of the + * generic form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + */ + public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'consecutive_recurring_date') { + $values = $form_state->getValue('consecutive_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Consecutive Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['end_time'])) { + $form_state->setError($element['end_time'], $this->t('Please enter an end time')); + } + + if (empty($values['duration']) || $values['duration'] < 1) { + $form_state->setError($element['duration'], $this->t('Please enter a duration greater than 0')); + } + + if (empty($values['duration_units']) || !isset($complete_form['consecutive_recurring_date']['widget'][0]['duration_units']['#options'][$values['duration_units']])) { + $form_state->setError($element['duration_units'], $this->t('Please select a duration units value from the list')); + } + + if (!isset($values['buffer']) || $values['buffer'] === '' || $values['buffer'] < 0) { + $form_state->setError($element['buffer'], $this->t('Please enter a buffer greater than or equal to 0')); + } + + if (empty($values['buffer_units']) || !isset($complete_form['consecutive_recurring_date']['widget'][0]['buffer_units']['#options'][$values['buffer_units']])) { + $form_state->setError($element['buffer_units'], $this->t('Please select a buffer units value from the list')); + } + } + } + } + } diff --git a/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php index 69a9c0270f97afdfe38ea2acfd1d81bf29960ce5..3b9864b37bbae754fcf22da59fecf3d45fa43cee 100644 --- a/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/DailyRecurringDateWidget.php @@ -8,6 +8,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'daily recurring date' widget. @@ -23,6 +24,7 @@ use Drupal\recurring_events\Plugin\RecurringEventsFieldTrait; class DailyRecurringDateWidget extends DateRangeDefaultWidget { use RecurringEventsFieldTrait; + use StringTranslationTrait; /** * {@inheritdoc} @@ -36,15 +38,16 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { ':input[name="recur_type"]' => ['value' => 'daily_recurring_date'], ], ]; + $element['#element_validate'][] = [$this, 'validateForm']; - $element['value']['#title'] = t('Create Events Between'); + $element['value']['#title'] = $this->t('Create Events Between'); $element['value']['#weight'] = 1; $element['value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['value']['#date_date_element'] = 'date'; $element['value']['#date_time_format'] = ''; $element['value']['#date_time_element'] = 'none'; - $element['end_value']['#title'] = t('And'); + $element['end_value']['#title'] = $this->t('And'); $element['end_value']['#weight'] = 2; $element['end_value']['#date_date_format'] = DateTimeItemInterface::DATE_STORAGE_FORMAT; $element['end_value']['#date_date_element'] = 'date'; @@ -54,7 +57,7 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { $times = $this->getTimeOptions(); $element['time'] = [ '#type' => 'select', - '#title' => t('Event Start Time'), + '#title' => $this->t('Event Start Time'), '#options' => $times, '#default_value' => $items[$delta]->time ?: '', '#weight' => 3, @@ -63,7 +66,7 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { $durations = $this->getDurationOptions(); $element['duration'] = [ '#type' => 'select', - '#title' => t('Event Duration'), + '#title' => $this->t('Event Duration'), '#options' => $durations, '#default_value' => $items[$delta]->duration ?: '', '#weight' => 4, @@ -101,4 +104,44 @@ class DailyRecurringDateWidget extends DateRangeDefaultWidget { return $values; } + /** + * Element validate callback to ensure that widget values are valid. + * + * @param array $element + * An associative array containing the properties and children of the + * generic form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + */ + public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'daily_recurring_date') { + $values = $form_state->getValue('daily_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Daily Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['duration']) || !isset($complete_form['daily_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) { + $form_state->setError($element['duration'], $this->t('Please select a duration from the list')); + } + } + } + } + } diff --git a/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php index 22bef8aa73e7c47f8f400e2a0d2f62812a36bb6c..a97f2634dacd5c2a8f6a0887ae25d1fd02df6be2 100644 --- a/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/MonthlyRecurringDateWidget.php @@ -6,6 +6,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'monthly recurring date' widget. @@ -20,6 +21,8 @@ use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; */ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { + use StringTranslationTrait; + /** * {@inheritdoc} */ @@ -31,13 +34,14 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { ':input[name="recur_type"]' => ['value' => 'monthly_recurring_date'], ], ]; + $element['#element_validate'][] = [$this, 'validateForm']; $element['type'] = [ '#type' => 'radios', - '#title' => t('Event Recurrence Schedule'), + '#title' => $this->t('Event Recurrence Schedule'), '#options' => [ - 'weekday' => t('Recur on Day of Week'), - 'monthday' => t('Recur on Day of Month'), + 'weekday' => $this->t('Recur on Day of Week'), + 'monthday' => $this->t('Recur on Day of Month'), ], '#default_value' => $items[$delta]->type ?: '', '#weight' => 5, @@ -45,13 +49,13 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $element['day_occurrence'] = [ '#type' => 'checkboxes', - '#title' => t('Day Occurrence'), + '#title' => $this->t('Day Occurrence'), '#options' => [ - 'first' => t('First'), - 'second' => t('Second'), - 'third' => t('Third'), - 'fourth' => t('Fourth'), - 'last' => t('Last'), + 'first' => $this->t('First'), + 'second' => $this->t('Second'), + 'third' => $this->t('Third'), + 'fourth' => $this->t('Fourth'), + 'last' => $this->t('Last'), ], '#default_value' => $items[$delta]->day_occurrence ? explode(',', $items[$delta]->day_occurrence) : [], '#states' => [ @@ -65,7 +69,7 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $days = $this->getDayOptions(); $element['days'] = [ '#type' => 'checkboxes', - '#title' => t('Days of the Week'), + '#title' => $this->t('Days of the Week'), '#options' => $days, '#default_value' => $items[$delta]->days ? explode(',', $items[$delta]->days) : [], '#states' => [ @@ -79,7 +83,7 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $month_days = $this->getMonthDayOptions(); $element['day_of_month'] = [ '#type' => 'checkboxes', - '#title' => t('Days of the Month'), + '#title' => $this->t('Days of the Month'), '#options' => $month_days, '#default_value' => $items[$delta]->day_of_month ? explode(',', $items[$delta]->day_of_month) : [], '#states' => [ @@ -136,11 +140,82 @@ class MonthlyRecurringDateWidget extends WeeklyRecurringDateWidget { $date->modify('+1 day'); } - $days[-1] = t('Last'); + $days[-1] = $this->t('Last'); \Drupal::moduleHandler()->alter('recurring_events_month_days', $days); return $days; } + /** + * Element validate callback to ensure that widget values are valid. + * + * @param array $element + * An associative array containing the properties and children of the + * generic form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + */ + public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'monthly_recurring_date') { + $values = $form_state->getValue('monthly_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Monthly Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['duration']) || !isset($complete_form['monthly_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) { + $form_state->setError($element['duration'], $this->t('Please select a duration from the list')); + } + + if (empty($values['type']) || !isset($complete_form['monthly_recurring_date']['widget'][0]['type']['#options'][$values['type']])) { + $form_state->setError($element['type'], $this->t('Please select an event recurrence schedule type from the list')); + } + else { + switch ($values['type']) { + case 'weekday': + $filtered_day_occurrences = array_filter($values['day_occurrence'], function ($value) { + return !empty($value); + }); + if (empty($values['day_occurrence']) || empty($filtered_day_occurrences)) { + $form_state->setError($element['day_occurrence'], $this->t('Please select a day occurrence from the list')); + } + $filtered_days = array_filter($values['days'], function ($value) { + return !empty($value); + }); + if (empty($values['days']) || empty($filtered_days)) { + $form_state->setError($element['days'], $this->t('Please select week days from the list')); + } + break; + + case 'monthday': + $filtered_days = array_filter($values['day_of_month'], function ($value) { + return !empty($value); + }); + if (empty($values['day_of_month']) || empty($filtered_days)) { + $form_state->setError($element['day_of_month'], $this->t('Please select days of the month from the list')); + } + break; + } + } + } + } + } + } diff --git a/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php b/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php index 23dd15ffaee1a911bff6bf8d18785dfeb715f35a..f09b01c369eea30e98058c23143f9cdafced4d6b 100644 --- a/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php +++ b/src/Plugin/Field/FieldWidget/WeeklyRecurringDateWidget.php @@ -5,6 +5,7 @@ namespace Drupal\recurring_events\Plugin\Field\FieldWidget; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Datetime\DrupalDateTime; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Plugin implementation of the 'weekly recurring date' widget. @@ -19,6 +20,8 @@ use Drupal\Core\Datetime\DrupalDateTime; */ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget { + use StringTranslationTrait; + /** * {@inheritdoc} */ @@ -31,11 +34,12 @@ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget { ':input[name="recur_type"]' => ['value' => 'weekly_recurring_date'], ], ]; + $element['#element_validate'][] = [$this, 'validateForm']; $days = $this->getDayOptions(); $element['days'] = [ '#type' => 'checkboxes', - '#title' => t('Days of the Week'), + '#title' => $this->t('Days of the Week'), '#options' => $days, '#default_value' => $items[$delta]->days ? explode(',', $items[$delta]->days) : [], '#weight' => 5, @@ -99,4 +103,53 @@ class WeeklyRecurringDateWidget extends DailyRecurringDateWidget { return $days; } + /** + * Element validate callback to ensure that widget values are valid. + * + * @param array $element + * An associative array containing the properties and children of the + * generic form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + */ + public function validateForm(array &$element, FormStateInterface $form_state, array &$complete_form) { + $recur_type = $form_state->getValue('recur_type'); + if ($recur_type[0]['value'] === 'weekly_recurring_date') { + $values = $form_state->getValue('weekly_recurring_date'); + if (empty($values[0])) { + $form_state->setError($element, $this->t('Please configure the Weekly Recurring Date settings')); + } + if (!empty($values[0])) { + $values = $values[0]; + + if (empty($values['value'])) { + $form_state->setError($element['value'], $this->t('Please enter a start date')); + } + + if (empty($values['end_value'])) { + $form_state->setError($element['end_value'], $this->t('Please enter an end date')); + } + + if (empty($values['time'])) { + $form_state->setError($element['time'], $this->t('Please enter a start time')); + } + + if (empty($values['duration']) || !isset($complete_form['weekly_recurring_date']['widget'][0]['duration']['#options'][$values['duration']])) { + $form_state->setError($element['duration'], $this->t('Please select a duration from the list')); + } + + $filtered_days = array_filter($values['days'], function ($value) { + return !empty($value); + }); + + if (empty($values['days']) || empty($filtered_days)) { + $form_state->setError($element['days'], $this->t('Please select week days from the list')); + } + + } + } + } + } diff --git a/src/Plugin/FieldInheritance/BooleanFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/BooleanFieldInheritancePlugin.php deleted file mode 100644 index 772417c63162a8cced8294a2a8ae70f34174774e..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/BooleanFieldInheritancePlugin.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * Boolean Inheritance plugin. - * - * @FieldInheritance( - * id = "boolean_inheritance", - * name = @Translation("Boolean Field Inheritance"), - * types = { - * "boolean" - * } - * ) - */ -class BooleanFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/FieldInheritance/DateFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/DateFieldInheritancePlugin.php deleted file mode 100644 index 98ab60ceb857cf9977391f88f32a954e8c30762e..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/DateFieldInheritancePlugin.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * Date Inheritance plugin. - * - * @FieldInheritance( - * id = "date_inheritance", - * name = @Translation("Date Field Inheritance"), - * types = { - * "datetime", - * "daterange", - * } - * ) - */ -class DateFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/FieldInheritance/EmailFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/EmailFieldInheritancePlugin.php deleted file mode 100644 index be99bb30cccc2f3a22bf939556180bd9687bc56c..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/EmailFieldInheritancePlugin.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * Email Inheritance plugin. - * - * @FieldInheritance( - * id = "email_inheritance", - * name = @Translation("Email Field Inheritance"), - * types = { - * "email" - * } - * ) - */ -class EmailFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/FieldInheritance/EntityReferenceFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/EntityReferenceFieldInheritancePlugin.php deleted file mode 100644 index 6084798f1eb5a0587772ee246d1d1c3522ec4807..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/EntityReferenceFieldInheritancePlugin.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * Entity Reference Inheritance plugin. - * - * @FieldInheritance( - * id = "entity_reference_inheritance", - * name = @Translation("Entity Reference Field Inheritance"), - * types = { - * "entity_reference", - * "image", - * "file", - * "webform" - * } - * ) - */ -class EntityReferenceFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/FieldInheritance/FieldInheritancePluginBase.php b/src/Plugin/FieldInheritance/FieldInheritancePluginBase.php deleted file mode 100644 index 984276d16e74f3f61e8f1aa365ffc8e63b3b63cb..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/FieldInheritancePluginBase.php +++ /dev/null @@ -1,287 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\Component\Plugin\PluginBase; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\recurring_events\FieldInheritancePluginInterface; -use Drupal\Core\Language\LanguageManagerInterface; -use Drupal\Core\Plugin\ContainerFactoryPluginInterface; - -/** - * Abstract class FieldInheritancePluginBase. - */ -abstract class FieldInheritancePluginBase extends PluginBase implements FieldInheritancePluginInterface, ContainerFactoryPluginInterface { - - /** - * The entity. - * - * @var \Drupal\Core\Entity\EntityInterface - */ - protected $entity; - - /** - * The method used to inherit. - * - * @var string - */ - protected $method; - - /** - * The source field used to inherit. - * - * @var string - */ - protected $sourceField; - - /** - * The entity field used to inherit. - * - * @var string - */ - protected $entityField; - - /** - * The language manager service. - * - * @var \Drupal\Core\Language\LanguageManagerInterface - */ - protected $languageManager; - - /** - * The current language code. - * - * @var string - */ - protected $langCode; - - /** - * Constructs a FieldInheritancePluginBase object. - * - * @param array $configuration - * The plugin configuration. - * @param string $plugin_id - * The plugin ID. - * @param mixed $plugin_definition - * The plugin definition. - * @param Drupal\Core\Language\LanguageManagerInterface $language_manager - * The language manager service. - */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager) { - parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->entity = $configuration['entity']; - $this->method = $configuration['method']; - $this->sourceField = $configuration['source field']; - if (!empty($configuration['entity field'])) { - $this->entityField = $configuration['entity field']; - } - $this->languageManager = $language_manager; - $this->langCode = $this->languageManager->getCurrentLanguage()->getId(); - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('language_manager') - ); - } - - /** - * Get the configuration method. - */ - public function getMethod() { - return $this->method; - } - - /** - * Get the configuration source field. - */ - public function getSourceField() { - return $this->sourceField; - } - - /** - * Get the configuration entity field. - */ - public function getEntityField() { - return $this->entityField; - } - - /** - * {@inheritdoc} - */ - public function computeValue() { - $this->validateArguments(); - $method = $this->getMethod(); - - $value = ''; - switch ($method) { - case 'inherit': - $value = $this->inheritData(); - break; - - case 'prepend': - $value = $this->prependData(); - break; - - case 'append': - $value = $this->appendData(); - break; - - case 'fallback': - $value = $this->fallbackData(); - break; - } - return $value; - } - - /** - * Retrieve inherited data. - * - * @return string - * The inherited data. - */ - protected function inheritData() { - $series = $this->getEventSeries(); - if ($series === FALSE) { - return []; - } - return $series->{$this->getSourceField()}->getValue() ?? ''; - } - - /** - * Retrieve prepended data. - * - * @return string - * The prepended data. - */ - protected function prependData() { - $series = $this->getEventSeries(); - $instance = $this->getEventInstance(); - $values = []; - - if ($series === FALSE) { - return $values; - } - - if (!empty($instance->{$this->getEntityField()}->getValue())) { - $values = array_merge($values, $instance->{$this->getEntityField()}->getValue()); - } - if (!empty($series->{$this->getSourceField()}->getValue())) { - $values = array_merge($values, $series->{$this->getSourceField()}->getValue()); - } - return $values; - } - - /** - * Retrieve appended data. - * - * @return string - * The appended data. - */ - protected function appendData() { - $series = $this->getEventSeries(); - $instance = $this->getEventInstance(); - $values = []; - - if ($series === FALSE) { - return $values; - } - - if (!empty($series->{$this->getSourceField()}->getValue())) { - $values = array_merge($values, $series->{$this->getSourceField()}->getValue()); - } - if (!empty($instance->{$this->getEntityField()}->getValue())) { - $values = array_merge($values, $instance->{$this->getEntityField()}->getValue()); - } - return $values; - } - - /** - * Retrieve fallback data. - * - * @return string - * The fallback data. - */ - protected function fallbackData() { - $series = $this->getEventSeries(); - $instance = $this->getEventInstance(); - $values = []; - - if ($series === FALSE) { - return $values; - } - - if (!empty($instance->{$this->getEntityField()}->getValue())) { - $values = $instance->{$this->getEntityField()}->getValue(); - } - elseif (!empty($series->{$this->getSourceField()}->getValue())) { - $values = $series->{$this->getSourceField()}->getValue(); - } - return $values; - } - - /** - * Validate the configuration arguments of the plugin. - */ - protected function validateArguments() { - if (empty($this->getMethod())) { - throw new \InvalidArgumentException("The definition's 'method' key must be set to inherit data."); - } - - if (empty($this->getSourceField())) { - throw new \InvalidArgumentException("The definition's 'source field' key must be set to inherit data."); - } - - $method = $this->getMethod(); - $entity_field_methods = [ - 'prepend', - 'append', - 'fallback', - ]; - - if (array_search($method, $entity_field_methods)) { - if (empty($this->getEntityField())) { - throw new \InvalidArgumentException("The definition's 'entity field' key must be set to prepend, append, or fallback to series data."); - } - } - - return TRUE; - } - - /** - * Get the translated eventseries entity. - * - * @return Drupal\Core\Entity\EntityInterface|bool - * The translated eventseries entity, or FALSE. - */ - protected function getEventSeries() { - $series = $this->entity->getEventSeries(); - if (empty($series)) { - return FALSE; - } - if ($series->hasTranslation($this->langCode)) { - return $series->getTranslation($this->langCode); - } - return $series; - } - - /** - * Get the translated eventinstance entity. - * - * @return Drupal\Core\Entity\EntityInterface - * The translated eventinstance entity. - */ - protected function getEventInstance() { - if ($this->entity->hasTranslation($this->langCode)) { - return $this->entity->getTranslation($this->langCode); - } - return $this->entity; - } - -} diff --git a/src/Plugin/FieldInheritance/NumberFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/NumberFieldInheritancePlugin.php deleted file mode 100644 index 1457b90891ac972f202e9415c3c5f352202a9644..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/NumberFieldInheritancePlugin.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * Number Inheritance plugin. - * - * @FieldInheritance( - * id = "number_inheritance", - * name = @Translation("Number Field Inheritance"), - * types = { - * "decimal", - * "float", - * "integer", - * "list_float", - * "list_integer" - * } - * ) - */ -class NumberFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/FieldInheritance/StringFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/StringFieldInheritancePlugin.php deleted file mode 100644 index cd71519ebd21f98186a16e9a9b7261cf0385fea1..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/StringFieldInheritancePlugin.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * String Inheritance plugin. - * - * @FieldInheritance( - * id = "string_inheritance", - * name = @Translation("String Field Inheritance"), - * types = { - * "string", - * "string_long" - * } - * ) - */ -class StringFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/FieldInheritance/TextFieldInheritancePlugin.php b/src/Plugin/FieldInheritance/TextFieldInheritancePlugin.php deleted file mode 100644 index ff12b078a2ee03fe95f95c90eba1804461301b26..0000000000000000000000000000000000000000 --- a/src/Plugin/FieldInheritance/TextFieldInheritancePlugin.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\FieldInheritance; - -use Drupal\recurring_events\FieldInheritancePluginInterface; - -/** - * Text Inheritance plugin. - * - * @FieldInheritance( - * id = "text_inheritance", - * name = @Translation("Text Field Inheritance"), - * types = { - * "text", - * "text_long", - * "text_with_summary", - * "string", - * "string_long", - * "list_string" - * } - * ) - */ -class TextFieldInheritancePlugin extends FieldInheritancePluginBase implements FieldInheritancePluginInterface { -} diff --git a/src/Plugin/views/field/InheritedField.php b/src/Plugin/views/field/InheritedField.php deleted file mode 100644 index 00c7107a78785919b0e00c8d8fd16f4094d1976b..0000000000000000000000000000000000000000 --- a/src/Plugin/views/field/InheritedField.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace Drupal\recurring_events\Plugin\views\field; - -use Drupal\views\Plugin\views\field\EntityField; - -/** - * Field handler to show the inherited field data. - * - * @ingroup views_field_handlers - * - * @ViewsField("inherited_field") - */ -class InheritedField extends EntityField { - -} diff --git a/templates/eventseries-add-list.html.twig b/templates/eventseries-add-list.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..e2d7ad38cf2e93e4cc267502f86849b2c7b5285a --- /dev/null +++ b/templates/eventseries-add-list.html.twig @@ -0,0 +1,32 @@ +{# +/** + * @file + * Default theme implementation to list eventseries types available. + * + * This list is displayed on the Add events page. + * + * Available variables: + * - types: A list of eventseries types, each with the following properties: + * - add_link: Link to create an event of this type. + * - description: Description of this type of eventseries. + * + * @see template_preprocess_eventseries_add_list() + * + * @ingroup themeable + */ +#} +{% if types is not empty %} + <dl> + {% for type in types %} + <dt>{{ type.add_link }}</dt> + <dd>{{ type.description }}</dd> + {% endfor %} + </dl> +{% else %} + <p> + {% set create_content = path('eventseries_type.add') %} + {% trans %} + You have not created any event types yet. Go to the <a href="{{ create_content }}">eventseries type creation page</a> to add a new eventseries type. + {% endtrans %} + </p> +{% endif %} diff --git a/tests/src/Functional/LoadTest.php b/tests/src/Functional/LoadTest.php index db0f41edc534848e5fd25efe29500c884f7c92b2..2de25fa7344a4b0de6ee1012c2ac985d3663ac30 100644 --- a/tests/src/Functional/LoadTest.php +++ b/tests/src/Functional/LoadTest.php @@ -26,6 +26,13 @@ class LoadTest extends BrowserTestBase { */ protected $user; + /** + * Set the default theme to use. + * + * @var \string + */ + protected $defaultTheme = 'stark'; + /** * {@inheritdoc} */