REF - Auto-generate links for CRM_Core_Page_Basic
authorcolemanw <coleman@civicrm.org>
Sat, 24 Jun 2023 15:46:42 +0000 (08:46 -0700)
committercolemanw <coleman@civicrm.org>
Sun, 25 Jun 2023 04:44:54 +0000 (00:44 -0400)
Instead of hard-coding an array of links in every page, we can auto-generate the list
based on the 'paths' metadata in the DAO. As a POC this converts one page (ACLs).
Future conversions are simply a matter of ensuring 'paths' is defined then deleting the
links function and $_links variable.

CRM/ACL/Page/ACL.php
CRM/Core/Action.php
CRM/Core/Page/Basic.php

index 4bffecf133f4e7a534a80bc38b3da70e70ffcd7e..da80cd79df0dddaa59dee5efb89c2de72406bad5 100644 (file)
@@ -18,13 +18,6 @@ class CRM_ACL_Page_ACL extends CRM_Core_Page_Basic {
 
   public $useLivePageJS = TRUE;
 
-  /**
-   * The action links that we need to display for the browse screen.
-   *
-   * @var array
-   */
-  public static $_links = NULL;
-
   /**
    * Get BAO Name.
    *
@@ -35,45 +28,6 @@ class CRM_ACL_Page_ACL extends CRM_Core_Page_Basic {
     return 'CRM_ACL_BAO_ACL';
   }
 
-  /**
-   * Get action Links.
-   *
-   * @return array
-   *   (reference) of action links
-   */
-  public function &links() {
-    if (!(self::$_links)) {
-      self::$_links = [
-        CRM_Core_Action::UPDATE => [
-          'name' => ts('Edit'),
-          'url' => 'civicrm/acl/edit',
-          'qs' => 'reset=1&action=update&id=%%id%%',
-          'title' => ts('Edit ACL'),
-        ],
-        CRM_Core_Action::DISABLE => [
-          'name' => ts('Disable'),
-          'ref' => 'crm-enable-disable',
-          'title' => ts('Disable ACL'),
-          'weight' => 40,
-        ],
-        CRM_Core_Action::ENABLE => [
-          'name' => ts('Enable'),
-          'ref' => 'crm-enable-disable',
-          'title' => ts('Enable ACL'),
-          'weight' => 30,
-        ],
-        CRM_Core_Action::DELETE => [
-          'name' => ts('Delete'),
-          'url' => 'civicrm/acl/delete',
-          'qs' => 'reset=1&action=delete&id=%%id%%',
-          'title' => ts('Delete ACL'),
-          'weight' => 100,
-        ],
-      ];
-    }
-    return self::$_links;
-  }
-
   /**
    * Run the page.
    *
index d23bd256a455e9e3aacdd1699ecd0c4e32a5e599..284f7b7de0cd477b5b4aadd3d59d4030ca448bd0 100644 (file)
@@ -79,12 +79,96 @@ class CRM_Core_Action {
     'reopen' => self::REOPEN,
   ];
 
-  /**
-   * The flipped version of the names array, initialized when used
-   *
-   * @var array
-   */
-  public static $_description;
+  private static function getInfo(): array {
+    Civi::$statics[__CLASS__ . 'Info'] = Civi::$statics[__CLASS__ . 'Info'] ?? [
+      self::ADD => [
+        'name' => 'add',
+        'label' => ts('Add'),
+        'weight' => 0,
+      ],
+      self::UPDATE => [
+        'name' => 'update',
+        'label' => ts('Edit'),
+        'weight' => -10,
+      ],
+      self::VIEW => [
+        'name' => 'view',
+        'label' => ts('View'),
+        'weight' => -20,
+      ],
+      self::DELETE => [
+        'name' => 'delete',
+        'label' => ts('Delete'),
+        'weight' => 100,
+      ],
+      self::BROWSE => [
+        'name' => 'browse',
+        'label' => ts('Browse'),
+        'weight' => 0,
+      ],
+      self::ENABLE => [
+        'name' => 'enable',
+        'label' => ts('Enable'),
+        'weight' => 40,
+      ],
+      self::DISABLE => [
+        'name' => 'disable',
+        'label' => ts('Disable'),
+        'weight' => 40,
+      ],
+      self::EXPORT => [
+        'name' => 'export',
+        'label' => ts('Export'),
+        'weight' => 0,
+      ],
+      self::PREVIEW => [
+        'name' => 'preview',
+        'label' => ts('Preview'),
+        'weight' => 0,
+      ],
+      self::MAP => [
+        'name' => 'map',
+        'label' => ts('Map'),
+        'weight' => 0,
+      ],
+      self::COPY => [
+        'name' => 'copy',
+        'label' => ts('Copy'),
+        'weight' => 20,
+      ],
+      self::PROFILE => [
+        'name' => 'profile',
+        'label' => ts('Profile'),
+        'weight' => 0,
+      ],
+      self::RENEW => [
+        'name' => 'renew',
+        'label' => ts('Renew'),
+        'weight' => 10,
+      ],
+      self::DETACH => [
+        'name' => 'detach',
+        'label' => ts('Detach'),
+        'weight' => 0,
+      ],
+      self::REVERT => [
+        'name' => 'revert',
+        'label' => ts('Revert'),
+        'weight' => 0,
+      ],
+      self::CLOSE => [
+        'name' => 'close',
+        'label' => ts('Close'),
+        'weight' => 0,
+      ],
+      self::REOPEN => [
+        'name' => 'reopen',
+        'label' => ts('Reopen'),
+        'weight' => 0,
+      ],
+    ];
+    return Civi::$statics[__CLASS__ . 'Info'];
+  }
 
   /**
    * Called by the request object to translate a string into a mask.
@@ -129,35 +213,31 @@ class CRM_Core_Action {
   }
 
   /**
-   * Given a string determine the bitmask for this specific string.
+   * Given a string lookup the bitmask for the action name.
+   * e.g. "add" returns self::ADD.
    *
-   * @param string $item
-   *   The input action to process.
+   * @param string $name
    *
    * @return int
-   *   the action mask corresponding to the input string
    */
-  public static function mapItem($item) {
-    $mask = self::$_names[trim($item)] ?? NULL;
-    return $mask ? $mask : 0;
+  public static function mapItem($name) {
+    foreach (self::getInfo() as $mask => $info) {
+      if ($info['name'] === $name) {
+        return $mask;
+      }
+    }
+    return self::NONE;
   }
 
   /**
-   *
-   * Given an action mask, find the corresponding description
+   * Given an action mask, get the name which describes it,
+   * e.g. self::ADD returns 'add'.
    *
    * @param int $mask
-   *   The action mask.
-   *
    * @return string
-   *   the corresponding action description
    */
   public static function description($mask) {
-    if (!isset(self::$_description)) {
-      self::$_description = array_flip(self::$_names);
-    }
-
-    return CRM_Utils_Array::value($mask, self::$_description, 'NO DESCRIPTION SET');
+    return self::getInfo()[$mask]['name'] ?? 'NO DESCRIPTION SET';
   }
 
   /**
@@ -412,4 +492,83 @@ class CRM_Core_Action {
     return $mask;
   }
 
+  /**
+   * @param int $mask
+   * @return string|null
+   */
+  public static function getLabel(int $mask): ?string {
+    return self::getInfo()[$mask]['label'] ?? NULL;
+  }
+
+  /**
+   * @param int $mask
+   * @return int|null
+   */
+  public static function getWeight(int $mask): ?string {
+    return self::getInfo()[$mask]['weight'] ?? NULL;
+  }
+
+  /**
+   * Builds a title based on action and entity title, e.g. "Update Contact"
+   *
+   * @param int $action
+   * @param string $entityTitle
+   * @return string|null
+   */
+  public static function getTitle(int $action, string $entityTitle): ?string {
+    switch ($action) {
+      case self::ADD:
+        return ts('Add %1', [1 => $entityTitle]);
+
+      case self::UPDATE:
+        return ts('Update %1', [1 => $entityTitle]);
+
+      case self::VIEW:
+        return ts('View %1', [1 => $entityTitle]);
+
+      case self::DELETE:
+        return ts('Delete %1', [1 => $entityTitle]);
+
+      case self::BROWSE:
+        return ts('Browse %1', [1 => $entityTitle]);
+
+      case self::ENABLE:
+        return ts('Enable %1', [1 => $entityTitle]);
+
+      case self::DISABLE:
+        return ts('Disable %1', [1 => $entityTitle]);
+
+      case self::EXPORT:
+        return ts('Export %1', [1 => $entityTitle]);
+
+      case self::PREVIEW:
+        return ts('Preview %1', [1 => $entityTitle]);
+
+      case self::MAP:
+        return ts('Map %1', [1 => $entityTitle]);
+
+      case self::COPY:
+        return ts('Copy %1', [1 => $entityTitle]);
+
+      case self::PROFILE:
+        return ts('Profile %1', [1 => $entityTitle]);
+
+      case self::RENEW:
+        return ts('Renew %1', [1 => $entityTitle]);
+
+      case self::DETACH:
+        return ts('Detach %1', [1 => $entityTitle]);
+
+      case self::REVERT:
+        return ts('Revert %1', [1 => $entityTitle]);
+
+      case self::CLOSE:
+        return ts('Close %1', [1 => $entityTitle]);
+
+      case self::REOPEN:
+        return ts('Reopen %1', [1 => $entityTitle]);
+    }
+    return NULL;
+  }
+
 }
index 52730c05d0273cfa3aeb1686ba396e969274e774..366f16e332cb4659d17e567d2aa5fa45df862378 100644 (file)
@@ -18,24 +18,54 @@ abstract class CRM_Core_Page_Basic extends CRM_Core_Page {
 
   protected $_action;
 
-  /**
-   * Define all the abstract functions here.
-   */
-
   /**
    * Name of the BAO to perform various DB manipulations.
    *
-   * @return string
+   * @return CRM_Core_DAO|string
    */
   abstract protected function getBAOName();
 
   /**
-   * An array of action links.
+   * Get array of action links for the "browse" page.
    *
-   * @return array
-   *   (reference)
+   * Transforms from the 'paths' in metadata to the
+   * format expected by basic pages.
+   *
+   * @return array[]
    */
-  abstract protected function &links();
+  public function &links() {
+    $baoName = $this->getBAOName();
+    if (!isset(Civi::$statics[$baoName]['actionLinks'])) {
+      Civi::$statics[$baoName]['actionLinks'] = [];
+      $title = $baoName::getEntityTitle();
+      $paths = $baoName::getEntityPaths();
+      unset($paths['add']);
+      foreach ($paths as $action => $path) {
+        $actionKey = CRM_Core_Action::map($action);
+        if ($actionKey) {
+          [$path, $query] = array_pad(explode('?', $path), 2, '');
+          Civi::$statics[$baoName]['actionLinks'][$actionKey] = [
+            'name' => CRM_Core_Action::getLabel($actionKey),
+            'title' => CRM_Core_Action::getTitle($actionKey, $title),
+            'url' => $path,
+            'qs' => str_replace(['[', ']'], '%%', $query),
+            'weight' => CRM_Core_Action::getWeight($actionKey),
+          ];
+        }
+      }
+      if (isset($baoName::getSupportedFields()['is_active'])) {
+        foreach ([CRM_Core_Action::DISABLE, CRM_Core_Action::ENABLE] as $actionKey) {
+          Civi::$statics[$baoName]['actionLinks'][$actionKey] = [
+            'name' => CRM_Core_Action::getLabel($actionKey),
+            'title' => CRM_Core_Action::getTitle($actionKey, $title),
+            'ref' => 'crm-enable-disable',
+            'weight' => CRM_Core_Action::getWeight($actionKey),
+          ];
+        }
+      }
+    }
+    return Civi::$statics[$baoName]['actionLinks'];
+  }
 
   /**
    * Name of the edit form class.