From b48c3da438894cd26d36456b9fa38e625ea0e66a Mon Sep 17 00:00:00 2001
From: Owen Bush <ojb@ukhhf.co.uk>
Date: Thu, 23 May 2019 14:02:39 -0600
Subject: [PATCH] Now create instances in a hook_entity_presave so it runs
 regardless of how the event is created. Also some cleanup to coding standards

---
 .../recurring_events_registration.module      |  3 +-
 recurring_events.api.php                      | 12 +--
 recurring_events.module                       | 82 +++++++++++++++++++
 src/Controller/EventInstanceController.php    |  2 +-
 src/Controller/EventSeriesController.php      |  2 +-
 src/Entity/EventInstance.php                  | 15 ++++
 src/Entity/EventSeries.php                    | 15 ++++
 src/EventCreationService.php                  | 59 +++++++------
 src/EventInstanceStorage.php                  |  1 -
 src/EventInstanceStorageInterface.php         |  1 -
 src/EventInstanceTranslationHandler.php       |  1 -
 src/EventSeriesStorage.php                    |  1 -
 src/EventSeriesStorageInterface.php           |  1 -
 src/EventSeriesTranslationHandler.php         |  1 -
 src/FieldInheritanceHtmlRouteProvider.php     |  2 -
 src/Form/EventSeriesForm.php                  |  2 -
 16 files changed, 156 insertions(+), 44 deletions(-)

diff --git a/modules/recurring_events_registration/recurring_events_registration.module b/modules/recurring_events_registration/recurring_events_registration.module
index aecfde22..48b196f4 100644
--- a/modules/recurring_events_registration/recurring_events_registration.module
+++ b/modules/recurring_events_registration/recurring_events_registration.module
@@ -13,7 +13,6 @@ use Drupal\Core\Entity\EntityInterface;
 use Drupal\recurring_events_registration\Entity\Registrant;
 use Drupal\recurring_events\Entity\EventSeries;
 use Drupal\recurring_events\Entity\EventInstance;
-use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -154,7 +153,7 @@ function recurring_events_registration_recurring_events_registration_notificatio
 /**
  * Implements hook_recurring_events_save_pre_instances_deletion().
  */
-function recurring_events_registration_recurring_events_save_pre_instances_deletion(EventSeries $event_series, FormStateInterface $form_state) {
+function recurring_events_registration_recurring_events_save_pre_instances_deletion(EventSeries $event_series) {
   $registration_creation_service = \Drupal::service('recurring_events_registration.creation_service');
   $registration_creation_service->setEventSeries($event_series);
 
diff --git a/recurring_events.api.php b/recurring_events.api.php
index 272f86d4..cc9bccd9 100644
--- a/recurring_events.api.php
+++ b/recurring_events.api.php
@@ -117,10 +117,10 @@ function hook_recurring_events_inheritance_class_alter(&$class, $field) {
  *
  * @param Drupal\recurring_events\Entity\EventSeries $event_series
  *   The eventseries being altered.
- * @param Drupal\Core\Form\FormStateInterface $form_state
- *   The form state of an updated event series entity.
+ * @param Drupal\recurring_events\Entity\EventSeries $original
+ *   The original, unaltered eventseries.
  */
-function hook_recurring_events_save_pre_instances_deletion(EventSeries $event_series, FormStateInterface $form_state) {
+function hook_recurring_events_save_pre_instances_deletion(EventSeries $event_series, EventSeries $original) {
 }
 
 /**
@@ -133,10 +133,10 @@ function hook_recurring_events_save_pre_instances_deletion(EventSeries $event_se
  *
  * @param Drupal\recurring_events\Entity\EventSeries $event_series
  *   The eventseries being altered.
- * @param Drupal\Core\Form\FormStateInterface $form_state
- *   The form state of an updated event series entity.
+ * @param Drupal\recurring_events\Entity\EventSeries $original
+ *   The original, unaltered eventseries.
  */
-function hook_recurring_events_save_post_instances_deletion(EventSeries $event_series, FormStateInterface $form_state) {
+function hook_recurring_events_save_post_instances_deletion(EventSeries $event_series, EventSeries $original) {
 }
 
 /**
diff --git a/recurring_events.module b/recurring_events.module
index 82094d5e..8524af3c 100644
--- a/recurring_events.module
+++ b/recurring_events.module
@@ -10,6 +10,7 @@ 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;
 
 /**
  * Implements hook_help().
@@ -146,3 +147,84 @@ function template_preprocess_eventseries(array &$variables) {
     $variables['content'][$key] = $variables['elements'][$key];
   }
 }
+
+/**
+ * Implements hook_ENTITY_TYPE_presave().
+ */
+function recurring_events_eventseries_presave(EntityInterface $entity) {
+  $original = $entity->original;
+  $creation_service = \Drupal::service('recurring_events.event_creation_service');
+
+  // If the eventseries is being published, or created for the first time then
+  // there may be date recurrence changes that need to be converted into new
+  // eventinstance entities.
+  if ($entity->isPublished() || $entity->isNew()) {
+    if ($entity->isDefaultTranslation()) {
+      $creation_service->saveEvent($entity, $original);
+    }
+  }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_insert().
+ */
+function recurring_events_eventseries_insert(EntityInterface $entity) {
+  // When we initially create the eventseries we actually create the instances
+  // before the eventseries gets saved for the first time, so we have no ID for
+  // the series at that point. Now that the eventseries is properly saved we can
+  // go and set the eventseries_id on the eventinstances.
+  $instances = $entity->event_instances->referencedEntities();
+  if (!empty($instances)) {
+    foreach ($instances as $instance) {
+      if (empty($instance->eventseries_id->value)) {
+        $instance->set('eventseries_id', $entity->id());
+        $instance->setNewRevision(FALSE);
+        $instance->save();
+      }
+    }
+  }
+}
+
+/**
+ * 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') {
+    $original = \Drupal::entityTypeManager()->getStorage('eventseries')->load($entity->id());
+    $creation_service = \Drupal::service('recurring_events.event_creation_service');
+    if ($creation_service->checkForOriginalRecurConfigChanges($entity, $original)) {
+      $diff_array = $creation_service->buildDiffArray($original, NULL, $entity);
+      if (!empty($diff_array)) {
+        $form['diff'] = [
+          '#type' => 'container',
+          '#weight' => -99,
+        ];
+
+        $form['diff']['diff_title'] = [
+          '#type' => '#markup',
+          '#prefix' => '<h2>',
+          '#markup' => t('Revision Date Changes'),
+          '#suffix' => '</h2>',
+        ];
+
+        $form['diff']['diff_message'] = [
+          '#type' => '#markup',
+          '#prefix' => '<p>',
+          '#markup' => t('Recurrence configuration has been changed in this revision, as a result if you choose to publish this revision all instances will be removed and recreated. This action cannot be undone.'),
+          '#suffix' => '</p>',
+        ];
+
+        $form['diff']['table'] = [
+          '#type' => 'table',
+          '#header' => [
+            t('Data'),
+            t('Stored'),
+            t('Overridden'),
+          ],
+          '#rows' => $diff_array,
+        ];
+      }
+    }
+  }
+}
diff --git a/src/Controller/EventInstanceController.php b/src/Controller/EventInstanceController.php
index 8d151fdf..45bcdb0c 100644
--- a/src/Controller/EventInstanceController.php
+++ b/src/Controller/EventInstanceController.php
@@ -191,7 +191,7 @@ class EventInstanceController extends ControllerBase implements ContainerInjecti
             '#type' => 'inline_template',
             '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}',
             '#context' => [
-              'date' => $link,
+              'date' => $link->toString(),
               'username' => $this->renderer->renderPlain($username),
               'message' => ['#markup' => $revision->getRevisionLogMessage(), '#allowed_tags' => Xss::getHtmlTagList()],
             ],
diff --git a/src/Controller/EventSeriesController.php b/src/Controller/EventSeriesController.php
index 6a23f202..1b495b18 100644
--- a/src/Controller/EventSeriesController.php
+++ b/src/Controller/EventSeriesController.php
@@ -168,7 +168,7 @@ class EventSeriesController extends ControllerBase implements ContainerInjection
             '#type' => 'inline_template',
             '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}',
             '#context' => [
-              'date' => $link,
+              'date' => $link->toString(),
               'username' => $this->renderer->renderPlain($username),
               'message' => ['#markup' => $revision->getRevisionLogMessage(), '#allowed_tags' => Xss::getHtmlTagList()],
             ],
diff --git a/src/Entity/EventInstance.php b/src/Entity/EventInstance.php
index 5c085037..b000dd9a 100644
--- a/src/Entity/EventInstance.php
+++ b/src/Entity/EventInstance.php
@@ -254,6 +254,21 @@ class EventInstance extends EditorialContentEntityBase implements EventInterface
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getRevisionCreationTime() {
+    return $this->revision_timestamp->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setRevisionCreationTime($timestamp) {
+    $this->revision_timestamp->value = $timestamp;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/src/Entity/EventSeries.php b/src/Entity/EventSeries.php
index e9ac8857..2b810deb 100644
--- a/src/Entity/EventSeries.php
+++ b/src/Entity/EventSeries.php
@@ -253,6 +253,21 @@ class EventSeries extends EditorialContentEntityBase implements EventInterface {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getRevisionCreationTime() {
+    return $this->revision_timestamp->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setRevisionCreationTime($timestamp) {
+    $this->revision_timestamp->value = $timestamp;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/src/EventCreationService.php b/src/EventCreationService.php
index 50356736..6d8061e4 100644
--- a/src/EventCreationService.php
+++ b/src/EventCreationService.php
@@ -280,16 +280,29 @@ class EventCreationService {
    * @param Drupal\recurring_events\Entity\EventSeries $event
    *   The stored event series entity.
    * @param Drupal\Core\Form\FormStateInterface $form_state
-   *   The form state of an updated event series entity.
+   *   (Optional) The form state of an updated event series entity.
+   * @param Drupal\recurring_events\Entity\EventSeries $edited
+   *   (Optional) The edited event series entity.
    *
    * @return array
    *   An array of differences.
    */
-  public function buildDiffArray(EventSeries $event, FormStateInterface $form_state) {
+  public function buildDiffArray(EventSeries $event, FormStateInterface $form_state = NULL, EventSeries $edited = NULL) {
     $diff = [];
 
     $entity_config = $this->convertEntityConfigToArray($event);
-    $form_config = $this->convertFormConfigToArray($form_state);
+    $form_config = [];
+
+    if (!is_null($form_state)) {
+      $form_config = $this->convertFormConfigToArray($form_state);
+    }
+    if (!is_null($edited)) {
+      $form_config = $this->convertEntityConfigToArray($edited);
+    }
+
+    if (empty($form_config)) {
+      return $diff;
+    }
 
     if ($entity_config['type'] !== $form_config['type']) {
       $diff['type'] = [
@@ -414,25 +427,25 @@ class EventCreationService {
    *
    * @param Drupal\recurring_events\Entity\EventSeries $event
    *   The stored event series entity.
-   * @param Drupal\Core\Form\FormStateInterface $form_state
-   *   The form state of an updated event series entity.
    * @param Drupal\recurring_events\Entity\EventSeries $original
    *   The original, unsaved event series entity.
    */
-  public function saveEvent(EventSeries $event, FormStateInterface $form_state, EventSeries $original = NULL) {
-    // We only need a revision if this is an existing entity.
+  public function saveEvent(EventSeries $event, EventSeries $original = NULL) {
+    $update_event_id = FALSE;
+
+    // If this is a brand new series, then we don't have an ID for it yet to
+    // save against the instances. So we need to defer that part 'til later. We
+    // also want to always create instances if this is a brand new series.
     if ($event->isNew()) {
       $create_instances = TRUE;
-      // We have to save the event series first so we can use the ID to store
-      // against the event instances we create.
-      $event->save();
+      $update_event_id = TRUE;
     }
     else {
       // If there are date differences, we need to clear out the instances.
-      $create_instances = $this->checkForFormRecurConfigChanges($original, $form_state);
+      $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, $form_state]);
+        \Drupal::moduleHandler()->invokeAll('recurring_events_save_pre_instances_deletion', [$event, $original]);
 
         // Find all the instances and delete them.
         $instances = $event->event_instances->referencedEntities();
@@ -454,13 +467,13 @@ class EventCreationService {
         }
 
         // Allow other modules to react after the deletion of all instances.
-        \Drupal::moduleHandler()->invokeAll('recurring_events_save_post_instances_deletion', [$event, $form_state]);
+        \Drupal::moduleHandler()->invokeAll('recurring_events_save_post_instances_deletion', [$event, $original]);
       }
     }
 
     // Only create instances if date changes have been made or the event is new.
     if ($create_instances) {
-      $this->createInstances($event, $form_state);
+      $this->createInstances($event);
     }
   }
 
@@ -469,11 +482,9 @@ class EventCreationService {
    *
    * @param Drupal\recurring_events\Entity\EventSeries $event
    *   The stored event series entity.
-   * @param Drupal\Core\Form\FormStateInterface $form_state
-   *   The form state of an updated event series entity.
    */
-  public function createInstances(EventSeries $event, FormStateInterface $form_state) {
-    $form_data = $this->convertFormConfigToArray($form_state);
+  public function createInstances(EventSeries $event) {
+    $form_data = $this->convertEntityConfigToArray($event);
     $event_instances = [];
 
     $timezone = new \DateTimeZone(drupal_get_user_timezone());
@@ -634,7 +645,7 @@ class EventCreationService {
 
     // If the start date is after the end date then we have an invalid range so
     // just return nothing.
-    if ($start > $end) {
+    if ($start->getTimestamp() > $end->getTimestamp()) {
       return $dates;
     }
 
@@ -646,7 +657,7 @@ class EventCreationService {
 
     // Loop through a week at a time, storing the date in the array to return
     // until the end date is surpassed.
-    while ($start <= $end) {
+    while ($start->getTimestamp() <= $end->getTimestamp()) {
       // If we do not clone here we end up modifying the value of start in
       // the array and get some funky dates returned.
       $dates[] = clone $start;
@@ -682,7 +693,7 @@ class EventCreationService {
 
     // If the start date is after the end date then we have an invalid range so
     // just return nothing.
-    if ($start > $end) {
+    if ($start->getTimestamp() > $end->getTimestamp()) {
       return $dates;
     }
 
@@ -718,7 +729,7 @@ class EventCreationService {
 
     // Loop through each month checking to see if the day of the month is a
     // valid day, until the end date has been surpassed.
-    while ($start <= $end) {
+    while ($start->getTimestamp() <= $end->getTimestamp()) {
       // If we do not clone here we end up modifying the value of start in
       // the array and get some funky dates returned.
       $dates[] = clone $start;
@@ -787,7 +798,7 @@ class EventCreationService {
 
     // If the start date is after the end date then we have an invalid range so
     // just return nothing.
-    if ($start > $end_date) {
+    if ($start->getTimestamp() > $end_date->getTimestamp()) {
       return $dates;
     }
 
@@ -802,7 +813,7 @@ class EventCreationService {
 
     // Loop through a week at a time, storing the date in the array to return
     // until the end date is surpassed.
-    while ($start <= $end_date) {
+    while ($start->getTimestamp() <= $end_date->getTimestamp()) {
       // If we do not clone here we end up modifying the value of start in
       // the array and get some funky dates returned.
       $dates[] = clone $start;
diff --git a/src/EventInstanceStorage.php b/src/EventInstanceStorage.php
index 37abf099..ed1ae7c3 100644
--- a/src/EventInstanceStorage.php
+++ b/src/EventInstanceStorage.php
@@ -5,7 +5,6 @@ namespace Drupal\recurring_events;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Language\LanguageInterface;
-use Drupal\recurring_events\EventInterface;
 
 /**
  * Defines the storage handler class for eventinstance entities.
diff --git a/src/EventInstanceStorageInterface.php b/src/EventInstanceStorageInterface.php
index 2a6e586e..021ca2c7 100644
--- a/src/EventInstanceStorageInterface.php
+++ b/src/EventInstanceStorageInterface.php
@@ -5,7 +5,6 @@ namespace Drupal\recurring_events;
 use Drupal\Core\Entity\ContentEntityStorageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Language\LanguageInterface;
-use Drupal\recurring_events\EventInterface;
 
 /**
  * Defines the storage handler class for eventinstance entities.
diff --git a/src/EventInstanceTranslationHandler.php b/src/EventInstanceTranslationHandler.php
index ce1f6810..6f3e8a4a 100644
--- a/src/EventInstanceTranslationHandler.php
+++ b/src/EventInstanceTranslationHandler.php
@@ -10,5 +10,4 @@ use Drupal\content_translation\ContentTranslationHandler;
 class EventInstanceTranslationHandler extends ContentTranslationHandler {
 
   // Override here the needed methods from ContentTranslationHandler.
-
 }
diff --git a/src/EventSeriesStorage.php b/src/EventSeriesStorage.php
index 76f60bb8..858a69e3 100644
--- a/src/EventSeriesStorage.php
+++ b/src/EventSeriesStorage.php
@@ -5,7 +5,6 @@ namespace Drupal\recurring_events;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Language\LanguageInterface;
-use Drupal\recurring_events\EventInterface;
 
 /**
  * Defines the storage handler class for eventseries entities.
diff --git a/src/EventSeriesStorageInterface.php b/src/EventSeriesStorageInterface.php
index 4d05919b..f4f1d568 100644
--- a/src/EventSeriesStorageInterface.php
+++ b/src/EventSeriesStorageInterface.php
@@ -5,7 +5,6 @@ namespace Drupal\recurring_events;
 use Drupal\Core\Entity\ContentEntityStorageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Language\LanguageInterface;
-use Drupal\recurring_events\EventInterface;
 
 /**
  * Defines the storage handler class for eventseries entities.
diff --git a/src/EventSeriesTranslationHandler.php b/src/EventSeriesTranslationHandler.php
index f2e1d817..c6aa7262 100644
--- a/src/EventSeriesTranslationHandler.php
+++ b/src/EventSeriesTranslationHandler.php
@@ -10,5 +10,4 @@ use Drupal\content_translation\ContentTranslationHandler;
 class EventSeriesTranslationHandler extends ContentTranslationHandler {
 
   // Override here the needed methods from ContentTranslationHandler.
-
 }
diff --git a/src/FieldInheritanceHtmlRouteProvider.php b/src/FieldInheritanceHtmlRouteProvider.php
index dd0fba9e..52dd1714 100644
--- a/src/FieldInheritanceHtmlRouteProvider.php
+++ b/src/FieldInheritanceHtmlRouteProvider.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 Field inheritance entities.
@@ -21,7 +20,6 @@ class FieldInheritanceHtmlRouteProvider extends AdminHtmlRouteProvider {
     $collection = parent::getRoutes($entity_type);
 
     // Provide your custom entity routes here.
-
     return $collection;
   }
 
diff --git a/src/Form/EventSeriesForm.php b/src/Form/EventSeriesForm.php
index 23701789..d1576439 100644
--- a/src/Form/EventSeriesForm.php
+++ b/src/Form/EventSeriesForm.php
@@ -231,13 +231,11 @@ class EventSeriesForm extends ContentEntityForm {
     }
 
     if ($entity->isDefaultTranslation()) {
-      $this->creationService->saveEvent($entity, $form_state, $original);
       $this->messenger->addStatus($this->t('Successfully saved the %name event series', [
         '%name' => $entity->title->value,
       ]));
     }
     else {
-
       $this->messenger->addStatus($this->t('@language translation of the @type %label has been saved.', [
         '@language' => $entity->language()->getName(),
         '@type' => 'Event ',
-- 
GitLab