CRM_Core_Menu - Add helper method, `isPublicRoute($path)`.
authorTim Otten <totten@civicrm.org>
Tue, 31 Jan 2023 09:13:53 +0000 (01:13 -0800)
committerTim Otten <totten@civicrm.org>
Tue, 25 Jul 2023 08:00:34 +0000 (01:00 -0700)
CRM/Core/Menu.php
tests/phpunit/CRM/Core/MenuTest.php

index d22073f07b03dbc56c8f8a90c357b1cadb1b1df7..1f9b8c123bc048a1e5dd01f048f48f8dbb0f080e 100644 (file)
@@ -280,6 +280,44 @@ class CRM_Core_Menu {
     self::buildAdminLinks($menu);
   }
 
+  /**
+   * Determine whether a route should canonically use a frontend or backend UI.
+   *
+   * @param string $path
+   *   Ex: 'civicrm/contribute/transact'
+   * @return bool
+   *   TRUE if the route is marked with 'is_public=1'.
+   * @internal
+   *   We may wish to revise the metadata to allow more distinctions. In that case, `isPublicRoute()`
+   *   would probably get replaced by something else.
+   */
+  public static function isPublicRoute(string $path): bool {
+    // A page-view may include hundreds of links - so don't hit DB for every link. Use cache.
+    // In default+demo builds, the list of public routes is much smaller than the list of
+    // private routes (roughly 1:10; ~50 entries vs ~450 entries). Cache the smaller list.
+    $cache = Civi::cache('long');
+    $index = $cache->get('PublicRouteIndex');
+    if ($index === NULL) {
+      $routes = CRM_Core_DAO::executeQuery('SELECT id, path FROM civicrm_menu WHERE is_public = 1')
+        ->fetchMap('id', 'path');
+      if (empty($routes)) {
+        Civi::log()->warning('isPublicRoute() should not be called before the menu has been built.');
+        return FALSE;
+      }
+      $index = array_fill_keys(array_values($routes), TRUE);
+      $cache->set('PublicRouteIndex', $index);
+    }
+
+    $parts = explode('/', $path);
+    while (count($parts) > 1) {
+      if (isset($index[implode('/', $parts)])) {
+        return TRUE;
+      }
+      array_pop($parts);
+    }
+    return FALSE;
+  }
+
   /**
    * This function recomputes menu from xml and populates civicrm_menu.
    *
@@ -291,6 +329,7 @@ class CRM_Core_Menu {
       $query = 'TRUNCATE civicrm_menu';
       CRM_Core_DAO::executeQuery($query);
     }
+    Civi::cache('long')->delete('PublicRouteIndex');
     $menuArray = self::items($truncate);
 
     self::build($menuArray);
index a0184207764891d407ef4f7f9602e6dd00459e29..c70023a091c48c5625ccd989290e5540ec52e78a 100644 (file)
@@ -135,4 +135,9 @@ class CRM_Core_MenuTest extends CiviUnitTestCase {
     $this->assertEquals($expectedArray, $actual);
   }
 
+  public function testIsPublicRoute(): void {
+    $this->assertEquals(FALSE, \CRM_Core_Menu::isPublicRoute('civicrm/contribute'));
+    $this->assertEquals(TRUE, \CRM_Core_Menu::isPublicRoute('civicrm/contribute/transact'));
+  }
+
 }