dev/drupal#4 - Add Civi\Setup::getPendingAction() helper
authorTim Otten <totten@civicrm.org>
Wed, 26 Feb 2020 03:42:47 +0000 (19:42 -0800)
committerTim Otten <totten@civicrm.org>
Wed, 26 Feb 2020 04:26:02 +0000 (20:26 -0800)
Overview
--------

This exposes a new piece of information for downstream consumers of the `civicrm-setup` API.

It doesn't change any behaviors or expectations - it merely tracks an extra piece of info.

Before
------

The `Civi\Setup` interface does not give any reporting about what's going on.

After
-----

The `Civi\Setup` interface has a method, `getPendingAction()`, which reports the pending action.

Technical Details
-----------------

(1) The pending action is strictly singular - it would not be sensible, for example, to have the
`installFiles` and `uninstallFiles` actions running at the same time. Thus, the guards within
each function.

(2) The basic gist of the change - in each of the functions
(`{install,uninstall}{Files,Database}`), set the `pendingAction` at the start and unset
it at the end.  The change looks slightly bigger than it should - because it wraps the
existing code within the `try ...  finally ...` block.

(3) This facilitates dev/drupal#4 and https://github.com/civicrm/civicrm-drupal-8/pull/37
- there were some use-cases in which the auto-install behaviors of `civicrm_install()`
and `FlushDrupal8.civi-setup.php` would provoke each other (causing a sort of
installer-loop).  This change makes it possible to avoid the loop without changing the
contracts.

setup/src/Setup.php

index 682b0b712f6d337acb4ebd89c82d162be0b2e4ae..fb225ddb259376c7d5525316bc126849744dd558 100644 (file)
@@ -41,6 +41,11 @@ class Setup {
    */
   protected $log;
 
+  /**
+   * @var string|null
+   */
+  protected $pendingAction = NULL;
+
   // ----- Static initialization -----
 
   /**
@@ -189,8 +194,18 @@ class Setup {
    * @return \Civi\Setup\Event\InstallFilesEvent
    */
   public function installFiles() {
-    $event = new InstallFilesEvent($this->getModel());
-    return $this->getDispatcher()->dispatch('civi.setup.installFiles', $event);
+    if ($this->pendingAction !== NULL) {
+      throw new InitException(sprintf("Cannot begin action %s. Already executing %s.", __FUNCTION__, $this->pendingAction));
+    }
+    $this->pendingAction = __FUNCTION__;
+
+    try {
+      $event = new InstallFilesEvent($this->getModel());
+      return $this->getDispatcher()->dispatch('civi.setup.installFiles', $event);
+    }
+    finally {
+      $this->pendingAction = NULL;
+    }
   }
 
   /**
@@ -199,8 +214,18 @@ class Setup {
    * @return \Civi\Setup\Event\InstallDatabaseEvent
    */
   public function installDatabase() {
-    $event = new InstallDatabaseEvent($this->getModel());
-    return $this->getDispatcher()->dispatch('civi.setup.installDatabase', $event);
+    if ($this->pendingAction !== NULL) {
+      throw new InitException(sprintf("Cannot begin action %s. Already executing %s.", __FUNCTION__, $this->pendingAction));
+    }
+    $this->pendingAction = __FUNCTION__;
+
+    try {
+      $event = new InstallDatabaseEvent($this->getModel());
+      return $this->getDispatcher()->dispatch('civi.setup.installDatabase', $event);
+    }
+    finally {
+      $this->pendingAction = NULL;
+    }
   }
 
   /**
@@ -209,8 +234,18 @@ class Setup {
    * @return \Civi\Setup\Event\UninstallFilesEvent
    */
   public function uninstallFiles() {
-    $event = new UninstallFilesEvent($this->getModel());
-    return $this->getDispatcher()->dispatch('civi.setup.uninstallFiles', $event);
+    if ($this->pendingAction !== NULL) {
+      throw new InitException(sprintf("Cannot begin action %s. Already executing %s.", __FUNCTION__, $this->pendingAction));
+    }
+    $this->pendingAction = __FUNCTION__;
+
+    try {
+      $event = new UninstallFilesEvent($this->getModel());
+      return $this->getDispatcher()->dispatch('civi.setup.uninstallFiles', $event);
+    }
+    finally {
+      $this->pendingAction = NULL;
+    }
   }
 
   /**
@@ -219,8 +254,18 @@ class Setup {
    * @return \Civi\Setup\Event\UninstallDatabaseEvent
    */
   public function uninstallDatabase() {
-    $event = new UninstallDatabaseEvent($this->getModel());
-    return $this->getDispatcher()->dispatch('civi.setup.uninstallDatabase', $event);
+    if ($this->pendingAction !== NULL) {
+      throw new InitException(sprintf("Cannot begin action %s. Already executing %s.", __FUNCTION__, $this->pendingAction));
+    }
+    $this->pendingAction = __FUNCTION__;
+
+    try {
+      $event = new UninstallDatabaseEvent($this->getModel());
+      return $this->getDispatcher()->dispatch('civi.setup.uninstallDatabase', $event);
+    }
+    finally {
+      $this->pendingAction = NULL;
+    }
   }
 
   /**
@@ -256,4 +301,13 @@ class Setup {
     return $this->log;
   }
 
+  /**
+   * @return NULL|string
+   *   The name of a pending installation action, or NULL if none are active.
+   *   Ex: 'installDatabase', 'uninstallFiles'
+   */
+  public function getPendingAction() {
+    return $this->pendingAction;
+  }
+
 }