Afform - move angular dependency mapper code to its own class
authorColeman Watts <coleman@civicrm.org>
Fri, 22 Jan 2021 18:19:53 +0000 (13:19 -0500)
committerColeman Watts <coleman@civicrm.org>
Sat, 30 Jan 2021 01:41:05 +0000 (20:41 -0500)
ext/afform/core/Civi/Afform/AngularDependencyMapper.php [new file with mode: 0644]
ext/afform/core/afform.php

diff --git a/ext/afform/core/Civi/Afform/AngularDependencyMapper.php b/ext/afform/core/Civi/Afform/AngularDependencyMapper.php
new file mode 100644 (file)
index 0000000..a893cae
--- /dev/null
@@ -0,0 +1,130 @@
+<?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       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Afform;
+
+/**
+ * Class AngularDependencyMapper
+ * @package Civi\Afform
+ */
+class AngularDependencyMapper {
+
+  /**
+   * Scan the list of Angular modules and inject automatic-requirements.
+   *
+   * TLDR: if an afform uses element "<other-el/>", and if another module defines
+   * `$angularModules['otherMod']['exports']['el'][0] === 'other-el'`, then
+   * the 'otherMod' is automatically required.
+   *
+   * @param \Civi\Core\Event\GenericHookEvent $e
+   * @see CRM_Utils_Hook::angularModules()
+   */
+  public static function autoReq($e) {
+    /** @var \CRM_Afform_AfformScanner $scanner */
+    $scanner = \Civi::service('afform_scanner');
+    $moduleEnvId = md5(\CRM_Core_Config_Runtime::getId() . implode(',', array_keys($e->angularModules)));
+    $depCache = \CRM_Utils_Cache::create([
+      'name' => 'afdep_' . substr($moduleEnvId, 0, 32 - 6),
+      'type' => ['*memory*', 'SqlGroup', 'ArrayCache'],
+      'withArray' => 'fast',
+      'prefetch' => TRUE,
+    ]);
+    $depCacheTtl = 2 * 60 * 60;
+
+    $revMap = self::reverseDeps($e->angularModules);
+
+    $formNames = array_keys($scanner->findFilePaths());
+    foreach ($formNames as $formName) {
+      $angModule = _afform_angular_module_name($formName, 'camel');
+      $cacheLine = $depCache->get($formName, NULL);
+
+      $jFile = $scanner->findFilePath($formName, 'aff.json');
+      $hFile = $scanner->findFilePath($formName, 'aff.html');
+
+      $jStat = stat($jFile);
+      $hStat = stat($hFile);
+
+      if ($cacheLine === NULL) {
+        $needsUpdate = TRUE;
+      }
+      elseif ($jStat !== FALSE && $jStat['size'] !== $cacheLine['js']) {
+        $needsUpdate = TRUE;
+      }
+      elseif ($jStat !== FALSE && $jStat['mtime'] > $cacheLine['jm']) {
+        $needsUpdate = TRUE;
+      }
+      elseif ($hStat !== FALSE && $hStat['size'] !== $cacheLine['hs']) {
+        $needsUpdate = TRUE;
+      }
+      elseif ($hStat !== FALSE && $hStat['mtime'] > $cacheLine['hm']) {
+        $needsUpdate = TRUE;
+      }
+      else {
+        $needsUpdate = FALSE;
+      }
+
+      if ($needsUpdate) {
+        $cacheLine = [
+          'js' => $jStat['size'] ?? NULL,
+          'jm' => $jStat['mtime'] ?? NULL,
+          'hs' => $hStat['size'] ?? NULL,
+          'hm' => $hStat['mtime'] ?? NULL,
+          'r' => array_values(array_unique(array_merge(
+            [\CRM_Afform_AfformScanner::DEFAULT_REQUIRES],
+            $e->angularModules[$angModule]['requires'] ?? [],
+            self::reverseDepsFind(file_get_contents($hFile), $revMap)
+          ))),
+        ];
+        $depCache->set($formName, $cacheLine, $depCacheTtl);
+      }
+
+      $e->angularModules[$angModule]['requires'] = $cacheLine['r'];
+    }
+  }
+
+  /**
+   * @param $angularModules
+   * @return array
+   *   'attr': array(string $attrName => string $angModuleName)
+   *   'el': array(string $elementName => string $angModuleName)
+   */
+  private static function reverseDeps($angularModules):array {
+    $revMap = ['attr' => [], 'el' => []];
+    foreach (array_keys($angularModules) as $module) {
+      if (!isset($angularModules[$module]['exports'])) {
+        continue;
+      }
+      foreach ($angularModules[$module]['exports'] as $symbolName => $symbolTypes) {
+        if (strpos($symbolTypes, 'A') !== FALSE) {
+          $revMap['attr'][$symbolName] = $module;
+        }
+        if (strpos($symbolTypes, 'E') !== FALSE) {
+          $revMap['el'][$symbolName] = $module;
+        }
+      }
+    }
+    return $revMap;
+  }
+
+  /**
+   * @param string $html
+   * @param array $revMap
+   *   The reverse-dependencies map from reverseDeps().
+   * @return array
+   */
+  private static function reverseDepsFind($html, $revMap):array {
+    $symbols = \Civi\Afform\Symbols::scan($html);
+    $elems = array_intersect_key($revMap['el'], $symbols->elements);
+    $attrs = array_intersect_key($revMap['attr'], $symbols->attributes);
+    return array_values(array_unique(array_merge($elems, $attrs)));
+  }
+
+}
index 39c03d99e09dfc26a72389b0a03618cef246fdce..ee53b25ec4f753c999c9ed3397756ee898dca694 100644 (file)
@@ -51,7 +51,7 @@ function afform_civicrm_config(&$config) {
 
   Civi::dispatcher()->addListener(Submit::EVENT_NAME, [Submit::class, 'processContacts'], 500);
   Civi::dispatcher()->addListener(Submit::EVENT_NAME, [Submit::class, 'processGenericEntity'], -1000);
-  Civi::dispatcher()->addListener('hook_civicrm_angularModules', '_afform_civicrm_angularModules_autoReq', -1000);
+  Civi::dispatcher()->addListener('hook_civicrm_angularModules', ['\Civi\Afform\AngularDependencyMapper', 'autoReq'], -1000);
   Civi::dispatcher()->addListener('hook_civicrm_alterAngular', ['\Civi\Afform\AfformMetadataInjector', 'preprocess']);
 }
 
@@ -229,119 +229,6 @@ function _afform_get_partials($moduleName, $module) {
   ];
 }
 
-/**
- * Scan the list of Angular modules and inject automatic-requirements.
- *
- * TLDR: if an afform uses element "<other-el/>", and if another module defines
- * `$angularModules['otherMod']['exports']['el'][0] === 'other-el'`, then
- * the 'otherMod' is automatically required.
- *
- * @param \Civi\Core\Event\GenericHookEvent $e
- * @see CRM_Utils_Hook::angularModules()
- */
-function _afform_civicrm_angularModules_autoReq($e) {
-  /** @var CRM_Afform_AfformScanner $scanner */
-  $scanner = Civi::service('afform_scanner');
-  $moduleEnvId = md5(\CRM_Core_Config_Runtime::getId() . implode(',', array_keys($e->angularModules)));
-  $depCache = CRM_Utils_Cache::create([
-    'name' => 'afdep_' . substr($moduleEnvId, 0, 32 - 6),
-    'type' => ['*memory*', 'SqlGroup', 'ArrayCache'],
-    'withArray' => 'fast',
-    'prefetch' => TRUE,
-  ]);
-  $depCacheTtl = 2 * 60 * 60;
-
-  $revMap = _afform_reverse_deps($e->angularModules);
-
-  $formNames = array_keys($scanner->findFilePaths());
-  foreach ($formNames as $formName) {
-    $angModule = _afform_angular_module_name($formName, 'camel');
-    $cacheLine = $depCache->get($formName, NULL);
-
-    $jFile = $scanner->findFilePath($formName, 'aff.json');
-    $hFile = $scanner->findFilePath($formName, 'aff.html');
-
-    $jStat = stat($jFile);
-    $hStat = stat($hFile);
-
-    if ($cacheLine === NULL) {
-      $needsUpdate = TRUE;
-    }
-    elseif ($jStat !== FALSE && $jStat['size'] !== $cacheLine['js']) {
-      $needsUpdate = TRUE;
-    }
-    elseif ($jStat !== FALSE && $jStat['mtime'] > $cacheLine['jm']) {
-      $needsUpdate = TRUE;
-    }
-    elseif ($hStat !== FALSE && $hStat['size'] !== $cacheLine['hs']) {
-      $needsUpdate = TRUE;
-    }
-    elseif ($hStat !== FALSE && $hStat['mtime'] > $cacheLine['hm']) {
-      $needsUpdate = TRUE;
-    }
-    else {
-      $needsUpdate = FALSE;
-    }
-
-    if ($needsUpdate) {
-      $cacheLine = [
-        'js' => $jStat['size'] ?? NULL,
-        'jm' => $jStat['mtime'] ?? NULL,
-        'hs' => $hStat['size'] ?? NULL,
-        'hm' => $hStat['mtime'] ?? NULL,
-        'r' => array_values(array_unique(array_merge(
-          [CRM_Afform_AfformScanner::DEFAULT_REQUIRES],
-          $e->angularModules[$angModule]['requires'] ?? [],
-          _afform_reverse_deps_find($formName, file_get_contents($hFile), $revMap)
-        ))),
-      ];
-      // print_r(['cache update:' . $formName => $cacheLine]);
-      $depCache->set($formName, $cacheLine, $depCacheTtl);
-    }
-
-    $e->angularModules[$angModule]['requires'] = $cacheLine['r'];
-  }
-}
-
-/**
- * @param $angularModules
- * @return array
- *   'attr': array(string $attrName => string $angModuleName)
- *   'el': array(string $elementName => string $angModuleName)
- */
-function _afform_reverse_deps($angularModules) {
-  $revMap = ['attr' => [], 'el' => []];
-  foreach (array_keys($angularModules) as $module) {
-    if (!isset($angularModules[$module]['exports'])) {
-      continue;
-    }
-    foreach ($angularModules[$module]['exports'] as $symbolName => $symbolTypes) {
-      if (strpos($symbolTypes, 'A') !== FALSE) {
-        $revMap['attr'][$symbolName] = $module;
-      }
-      if (strpos($symbolTypes, 'E') !== FALSE) {
-        $revMap['el'][$symbolName] = $module;
-      }
-    }
-  }
-  return $revMap;
-}
-
-/**
- * @param string $formName
- * @param string $html
- * @param array $revMap
- *   The reverse-dependencies map from _afform_reverse_deps().
- * @return array
- * @see _afform_reverse_deps()
- */
-function _afform_reverse_deps_find($formName, $html, $revMap) {
-  $symbols = \Civi\Afform\Symbols::scan($html);
-  $elems = array_intersect_key($revMap['el'], $symbols->elements);
-  $attrs = array_intersect_key($revMap['attr'], $symbols->attributes);
-  return array_values(array_unique(array_merge($elems, $attrs)));
-}
-
 /**
  * Implements hook_civicrm_alterSettingsFolders().
  *