#420816 by sun, smk-ka: Improved on-demand loading of dynamic paths.
authorsun
Thu, 6 Jan 2011 23:27:40 +0000 (23:27 +0000)
committersun
Thu, 6 Jan 2011 23:27:40 +0000 (23:27 +0000)
CHANGELOG.txt
admin_menu.api.php
admin_menu.inc
admin_menu.install
admin_menu.map.inc

index d3216df..2e8a402 100644 (file)
@@ -6,6 +6,7 @@ Admin Menu x.x-x.x, xxxx-xx-xx
 
 Admin Menu 7.x-3.x, xxxx-xx-xx
 ------------------------------
+#420816 by sun, smk-ka: Improved on-demand loading of dynamic paths.
 #420816 by tim.plunkett: Fixed dynamic Field UI paths for vocabularies.
 #871774 by swentel: Fixed developer modules toggle still uses referer_uri().
 #671760 by sun: Updated for new preprocess defaults.
index ed8e476..098a604 100644 (file)
@@ -7,36 +7,38 @@
  */
 
 /**
- * Provide expansion arguments for dynamic menu items, i.e. menu paths
- * containing one or more %placeholders.
- *
- * The map items must be keyed by the dynamic path to expand. Each map item may
- * have the following properties:
+ * Provide expansion arguments for dynamic menu items.
  *
+ * The map items must be keyed by the dynamic path to expand, i.e. a menu path
+ * containing one or more '%' placeholders. Each map item may have the following
+ * properties:
  * - parent: The parent menu path to link the expanded items to.
- * - arguments: An array of argument sets that will be used in the
- *   expansion. Each set consists of an array of one or more placeholders with
- *   an array of possible expansions as value. Upon expansion, each argument
- *   is combined with every other argument from the set (ie., the cartesian
- *   product of all arguments is created). The expansion values may be empty,
- *   that is, you don't need to insert logic to skip map items for which no
- *   values exist, since admin menu will take care of that.
- * - hide: (optional) Used to hide another menu item, usually a superfluous
+ * - arguments: An array of argument sets that will be used in the expansion.
+ *   Each set consists of an array of one or more placeholders, which again is
+ *   an array of possible expansion values. Upon expansion, each argument is
+ *   combined with every other argument from the set (technically, the cartesian
+ *   product of all arguments). The expansion values may be empty; that is, you
+ *   do not need to insert logic to skip map items for which no values exist,
+ *   since Administration menu will take care of that.
+ * - hide: (optional) Used to hide another menu path, usually a superfluous
  *   "List" item.
  *
  * @see admin_menu.map.inc
  */
 function hook_admin_menu_map() {
-  // Expand content types in Structure >> Content types.
+  // Expand content types below Structure > Content types.
   // The key denotes the dynamic path to expand to multiple menu items.
   $map['admin/structure/types/manage/%node_type'] = array(
-    // Link generated items directly to the "Content types" item, and hide the
-    // "List" item.
+    // Link generated items directly to the "Content types" item.
     'parent' => 'admin/structure/types',
+    // Hide the "List" item, as this expansion will expose all available
+    // options.
     'hide' => 'admin/structure/types/list',
-    // Create expansion arguments for the %node_type placeholder.
+    // Create expansion arguments for the '%node_type' placeholder.
     'arguments' => array(
-      array('%node_type' => array_keys(node_type_get_types())),
+      array(
+        '%node_type' => array_keys(node_type_get_types()),
+      ),
     ),
   );
   return $map;
index 9c90ab0..fd2b6cf 100644 (file)
@@ -25,7 +25,6 @@ function admin_menu_tree($menu_name) {
   foreach ($expand_map as $path => $data) {
     // Convert named placeholders to anonymous placeholders, since the menu
     // system stores paths using anonymous placeholders.
-    // @todo Why specify named placeholders in the first place then?
     $replacements = array_fill_keys(array_keys($data['arguments'][0]), '%');
     $data['parent'] = strtr($data['parent'], $replacements);
     $new_map[strtr($path, $replacements)] = $data;
@@ -91,7 +90,6 @@ function admin_menu_tree_dynamic(array $expand_map) {
 
   // The retrieved menu link trees have to be ordered by depth, so parents
   // always come before their children for the storage logic below.
-  // @todo Order by 'fit' or 'depth' instead for parent path handling below?
   foreach ($p_columns as $column) {
     $query->orderBy($column, 'ASC');
   }
@@ -141,14 +139,14 @@ function admin_menu_tree_dynamic(array $expand_map) {
  * @param $tree_dynamic
  *   A dynamic menu tree structure as returned by admin_menu_tree_dynamic().
  * @param $expand_map
- *   @todo Rename this argument, it's not the same $expand_map like elsewhere.
- *   Placeholder expansion arguments.
+ *   An array containing menu router path placeholder expansion argument
+ *   mappings.
  * @param $hidden
  *   An array containing links to hide, keyed by path.
  *
  * @see hook_admin_menu_map()
- * @see menu_tree_all_data()
  * @see admin_menu_tree_dynamic()
+ * @see menu_tree_all_data()
  */
 function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_map, array $hidden) {
   foreach ($tree as $key => $data) {
@@ -200,63 +198,51 @@ function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_
         $current_expand_map = $expand_map;
       }
 
-      // Set up path arguments map; depends on whether the item is dynamic
-      // (contains placeholders) or not.
-      if (strpos($link['path'], '%') === FALSE) {
-        // Build static item and subtree.
-        $map = explode('/', $link['path']);
-        $item = admin_menu_translate($link, $map);
-        admin_menu_merge_tree($item, $tree_dynamic, $current_expand_map, $hidden);
-        $tree[$key]['below'] += $item;
+      // Skip dynamic items without expansion parameters.
+      if (empty($current_expand_map)) {
+        continue;
       }
-      else {
-        // Drop dynamic items without required expansion parameters.
-        if (empty($current_expand_map)) {
-          continue;
-        }
 
-        // Expand anonymous to named placeholders.
-        // @see _menu_load_objects()
-        $path_args = explode('/', $link['path']);
-        $load_functions = unserialize($link['load_functions']);
-        foreach ($load_functions as $index => $function) {
-          if ($function) {
-            if (is_array($function)) {
-              list($function,) = each($function);
-            }
-            // Add the loader function name minus "_load".
-            $placeholder = '%' . substr($function, 0, -5);
-            $path_args[$index] = $placeholder;
+      // Expand anonymous to named placeholders.
+      // @see _menu_load_objects()
+      $path_args = explode('/', $link['path']);
+      $load_functions = unserialize($link['load_functions']);
+      foreach ($load_functions as $index => $function) {
+        if ($function) {
+          if (is_array($function)) {
+            list($function,) = each($function);
           }
+          // Add the loader function name minus "_load".
+          $placeholder = '%' . substr($function, 0, -5);
+          $path_args[$index] = $placeholder;
         }
-        $path_dynamic = implode('/', $path_args);
-
-        // Create new menu items using expansion arguments.
-        foreach ($current_expand_map as $arguments) {
-          // Create the cartesian product for all arguments and create new
-          // menu items for each generated combination thereof.
-          $expanded_args = admin_menu_expand_args($arguments);
-          foreach ($expanded_args as $replacements) {
-            $newpath = strtr($path_dynamic, $replacements);
-            // If any placeholder couldn't be replaced, skip this item.
-            if (strpos($newpath, '%') !== FALSE) {
-              continue;
-            }
-            $map = explode('/', $newpath);
-            $item = admin_menu_translate($link, $map);
-            // No access.
-            if (empty($item)) {
-              continue;
-            }
-            // Build subtree using current replacement arguments.
-            // @todo Avoid rebuilding this for each item.
-            $new_expand_map = array();
-            foreach ($replacements as $placeholder => $value) {
-              $new_expand_map[$placeholder] = array($value);
-            }
-            admin_menu_merge_tree($item, $tree_dynamic, array($new_expand_map), $hidden);
-            $tree[$key]['below'] += $item;
+      }
+      $path_dynamic = implode('/', $path_args);
+
+      // Create new menu items using expansion arguments.
+      foreach ($current_expand_map as $arguments) {
+        // Create the cartesian product for all arguments and create new
+        // menu items for each generated combination thereof.
+        foreach (admin_menu_expand_args($arguments) as $replacements) {
+          $newpath = strtr($path_dynamic, $replacements);
+          // Skip this item, if any placeholder could not be replaced.
+          // Faster than trying to invoke _menu_translate().
+          if (strpos($newpath, '%') !== FALSE) {
+            continue;
           }
+          $map = explode('/', $newpath);
+          $item = admin_menu_translate($link, $map);
+          // Skip this item, if the current user does not have access.
+          if (empty($item)) {
+            continue;
+          }
+          // Build subtree using current replacement arguments.
+          $new_expand_map = array();
+          foreach ($replacements as $placeholder => $value) {
+            $new_expand_map[$placeholder] = array($value);
+          }
+          admin_menu_merge_tree($item, $tree_dynamic, array($new_expand_map), $hidden);
+          $tree[$key]['below'] += $item;
         }
       }
     }
@@ -266,14 +252,12 @@ function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_
 }
 
 /**
- * Create a menu item suitable for rendering.
+ * Translate an expanded router item into a menu link suitable for rendering.
  *
  * @param $router_item
  *   A menu router item.
  * @param $map
  *   A path map with placeholders replaced.
- *
- * @todo We have links. Consider forking menu_link_translate() instead.
  */
 function admin_menu_translate($router_item, $map) {
   _menu_translate($router_item, $map, TRUE);
@@ -281,21 +265,23 @@ function admin_menu_translate($router_item, $map) {
   // Run through hook_translated_menu_link_alter() to add devel information,
   // if configured.
   $router_item['menu_name'] = 'management';
+  // @todo Invoke as usual like _menu_link_translate().
   admin_menu_translated_menu_link_alter($router_item, NULL);
 
   if ($router_item['access']) {
     // Override mlid to make this item unique; since these items are expanded
     // from dynamic items, the mlid is always the same, so each item would
     // replace any other.
+    // @todo Doing this instead leads to plenty of duplicate links below
+    //   admin/structure/menu; likely a hidden recursion problem.
+    // $router_item['mlid'] = $router_item['href'] . $router_item['mlid'];
     $router_item['mlid'] = $router_item['href'];
-    // Turn local task menu callbacks into regular menu items, otherwise they
-    // won't be visible.
+    // Turn menu callbacks into regular menu items to make them visible.
     if ($router_item['type'] == MENU_CALLBACK) {
       $router_item['type'] = MENU_NORMAL_ITEM;
     }
-    // @todo Strip potential HTML from titles?
-    $router_item['title'] = strip_tags($router_item['title']);
 
+    // @see _menu_tree_check_access()
     $key = (50000 + $router_item['weight']) . ' ' . $router_item['title'] . ' ' . $router_item['mlid'];
     return array($key => array(
       'link' => $router_item,
index 3102bd7..7c9bb65 100644 (file)
@@ -92,12 +92,9 @@ function admin_menu_update_7302() {
  * Remove local tasks from {menu_links} table.
  */
 function admin_menu_update_7303() {
-  $paths = db_query('SELECT path FROM {menu_router} WHERE path LIKE :prefix AND type & :type', array(
-    ':prefix' => 'admin/%',
-    ':type' => MENU_IS_LOCAL_TASK,
-  ))->fetchCol();
-  db_delete('menu_links')
-    ->condition('router_path', $paths, 'IN')
+  db_delete('menu_router')
+    ->condition('path', 'admin/%', 'LIKE')
+    ->condition('type', MENU_IS_LOCAL_TASK, '&')
     ->execute();
 }
 
index ca6edf0..2a3cdc3 100644 (file)
@@ -13,6 +13,9 @@
  * Implements hook_admin_menu_map() on behalf of Filter module.
  */
 function filter_admin_menu_map() {
+  if (!user_access('administer filters')) {
+    return;
+  }
   $map['admin/config/content/formats/%filter_format'] = array(
     'parent' => 'admin/config/content/formats',
     'hide' => 'admin/config/content/formats/list',
@@ -27,6 +30,9 @@ function filter_admin_menu_map() {
  * Implements hook_admin_menu_map() on behalf of Menu module.
  */
 function menu_admin_menu_map() {
+  if (!user_access('administer menu')) {
+    return;
+  }
   $map['admin/structure/menu/manage/%menu'] = array(
     'parent' => 'admin/structure/menu',
     'hide' => 'admin/structure/menu/list',
@@ -41,6 +47,9 @@ function menu_admin_menu_map() {
  * Implements hook_admin_menu_map() on behalf of Node module.
  */
 function node_admin_menu_map() {
+  if (!user_access('administer content types')) {
+    return;
+  }
   $map['admin/structure/types/manage/%node_type'] = array(
     'parent' => 'admin/structure/types',
     'hide' => 'admin/structure/types/list',
@@ -61,6 +70,23 @@ function field_ui_admin_menu_map() {
       if (isset($bundle_info['admin'])) {
         $arguments = array();
         switch ($obj_type) {
+          case 'comment':
+            $fields = array();
+            foreach (field_info_instances($obj_type, $bundle_name) as $field) {
+              $fields[] = $field['field_name'];
+            }
+            // @todo Make Comment module expose the original node type bundle,
+            //   pretty please.
+            if (drupal_substr($bundle_name, 0, 13) == 'comment_node_') {
+              $bundle_name = drupal_substr($bundle_name, 13);
+            }
+            // @todo Doesn't work yet. Why?
+            $arguments = array(
+              '%comment_node_type' => array($bundle_name),
+              '%field_ui_menu' => $fields,
+            );
+            break;
+
           case 'node':
             $fields = array();
             foreach (field_info_instances($obj_type, $bundle_name) as $field) {
@@ -105,6 +131,9 @@ function field_ui_admin_menu_map() {
  * Implements hook_admin_menu_map() on behalf of Taxonomy module.
  */
 function taxonomy_admin_menu_map() {
+  if (!user_access('administer taxonomy')) {
+    return;
+  }
   $map['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array(
     'parent' => 'admin/structure/taxonomy',
     'hide' => 'admin/structure/taxonomy/list',
@@ -119,6 +148,9 @@ function taxonomy_admin_menu_map() {
  * Implements hook_admin_menu_map() on behalf of Views UI module.
  */
 function views_ui_admin_menu_map() {
+  if (!user_access('administer views')) {
+    return;
+  }
   // @todo Requires patch to views_ui.
   $map['admin/structure/views/edit/%views_ui_cache'] = array(
     'parent' => 'admin/structure/views',