dev/core#1460 - Implement first draft of DispatchPolicy
authorTim Otten <totten@civicrm.org>
Mon, 20 Apr 2020 21:10:30 +0000 (14:10 -0700)
committerTim Otten <totten@civicrm.org>
Tue, 21 Apr 2020 05:37:56 +0000 (22:37 -0700)
CRM/Upgrade/DispatchPolicy.php [new file with mode: 0644]

diff --git a/CRM/Upgrade/DispatchPolicy.php b/CRM/Upgrade/DispatchPolicy.php
new file mode 100644 (file)
index 0000000..9403bd2
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+class CRM_Upgrade_DispatchPolicy {
+
+  /**
+   * Determine the dispatch policy
+   *
+   * @param string $phase
+   *   Ex: 'upgrade.main' or 'upgrade.finish'.
+   * @return array
+   * @see \Civi\Core\CiviEventDispatcher::setDispatchPolicy()
+   */
+  public static function get($phase) {
+
+    // Should hooks dispatch while applying CiviCRM DB upgrades? The answer is
+    // mixed: it depends on the specific hook and the specific upgrade-step.
+    //
+    // Some example considerations:
+    // - If the "log_civicrm_*" tables and triggers are to be reconciled during
+    //   the upgrade, then one probably needs access to the list of tables and
+    //   triggers defined by extensions. These are provided by hooks.
+    // - If a hook fires while the DB has stale schema, and if the hook's logic
+    //   has a direct (SQL) or indirect (BAO/API) dependency on the schema, then
+    //   the hook is prone to fail. (Ex: CiviCRM 4.x and the migration from
+    //   civicrm_domain.config_backend to civicrm_setting.)
+    // - If *any* hook from an extension is called, then it may use classes
+    //   from the same extension, so the classloader / include-path / hook_config
+    //   should be operational.
+    // - If there is a general system flush at the end of the upgrade (to rebuild
+    //   important data-structures -- routing tables, container cache, metadata
+    //   cache, etc), then there's a huge number of hooks that should fire.
+    // - When hooks (or variations like "rules") are used to define business-logic,
+    //   they probably are not intended to fire during DB upgrade. Then again,
+    //   upgrade-logic is usually written with lower-level semantics that avoid firing hooks.
+    //
+    // Related discussions:
+    // - https://github.com/civicrm/civicrm-core/pull/13551
+    // - https://lab.civicrm.org/dev/core/issues/1449
+    // - https://lab.civicrm.org/dev/core/issues/1460
+
+    $strict = getenv('CIVICRM_UPGRADE_STRICT') || CRM_Utils_Constant::value('CIVICRM_UPGRADE_STRICT');
+    $policies = [];
+
+    // The "upgrade.main" policy applies during the planning and incremental revisions.
+    // It's more restrictive, preventing interference from unexpected callpaths.
+    $policies['upgrade.main'] = [
+      'hook_civicrm_config' => 'run',
+      '/^hook_civicrm_(pre|post)$/' => 'drop',
+      '/^hook_civicrm_/' => $strict ? 'warn-drop' : 'drop',
+      '/^civi\./' => 'run',
+      '/./' => $strict ? 'warn-drop' : 'drop',
+    ];
+
+    // The "upgrade.finish" policy applies at the end while performing the final clear/rebuild.
+    // It's more permissive, allowing more data-structures to rehydrate correctly.
+    $policies['upgrade.finish'] = [
+      '/^hook_civicrm_(pre|post)$/' => 'drop',
+      '/./' => 'run',
+    ];
+
+    // For comparison, "upgrade.old" is an estimation of the previous policy. It
+    // was applied at all times during the upgrade.
+    $policies['upgrade.old'] = [
+      'hook_civicrm_alterSettingsFolders' => 'run',
+      'hook_civicrm_alterSettingsMetaData' => 'run',
+      'hook_civicrm_triggerInfo' => 'run',
+      'hook_civicrm_alterLogTables' => 'run',
+      'hook_civicrm_container' => 'run',
+      'hook_civicrm_permission' => 'run',
+      'hook_civicrm_managed' => 'run',
+      'hook_civicrm_config' => 'run',
+      '/^hook_civicrm_(pre|post)$/' => 'drop',
+      '/^hook_civicrm_/' => 'drop',
+      '/^civi\./' => 'run',
+      '/./' => 'run',
+    ];
+
+    return $policies['upgrade.old'];
+    // return $policies[$phase];
+  }
+
+}