[development] The menu - does it have to be different on each page?

adrian rossouw adrian at bryght.com
Thu Aug 31 01:17:05 UTC 2006

On 30 Aug 2006, at 8:25 PM, Johan Forngren wrote:

>> WWFAPID? (What would FormsAPI do?)
>  $menu['menu'] = array(
>    '#type' => 'menu',
>    '#path' => array ('menu', 'yet', 'another', 'path', 'etc'),
>    '#title' => t('Menu'),
>    '#tree' => TRUE,
>    '#collapsible' => TRUE,
>    '#collapsed' => TRUE,
>  );
>  $menu['menu']['item'] = array('
>    '#type' => 'node',
>    '#nid' => 1337,
>    '#title' => t('Node'),
>    '#description' => t('A node item'),
>    '#weight' => 5,
>  );
>  $menu['menu']['item2'] = array('
>    '#type' => 'page',
>    '#callback' => 1337,
>    '#title' => t('A page'),
>    '#path' => array(t('translatable'), t('path')),
>  );

a couple of things for this.

You would still sit with the may_cache issue, in that every run would  
need 2 calls, because it can't be cached.

What i plan to do is make fapi elements possibly be callbacks, which  
means any property can be a function that can instead be executed,  
along with variables that can be used in the call. What this would  
mean is that the instruction to check the function can be cached, but  
not the final value.. an example of this would be the access check,  
which currently needs to be cached per role because of permissions.

. In the following case :

  $menu['node']['%d'][edit'] = array('
    '#type' => 'page',
    '#callback' => 'drupal_get_form',
    '#callback_arguments' => callback('arg', 1), // returns an array,  
so you can do callback(something) + callback(something)
    '#access' => callback('user_access', 'some_permission'),
    '#title' => t('A page'),
    '#path' => array(t('translatable'), t('path')),

Take for example if you had the entire menu loaded into memory (and  
unserialising it is quite expensive too).

When loading up the system, is can go :

$section &= $menu;
$parts = expode('/', $_GET['q']);

foreach ($parts as $part) {

   // this if statement will almost surely be incorrect, but it has  
the general idea
   if (isset($section[$part]) || (is_numeric($part) && isset($section 
['%d'])) || (isset($section['%s']) ) {
     // finds all callback arrays, and trigger them
     if (!$section['#access']) {
     else {
       //success, we have access to this item
       $section &= $section[$part];
       $found_part[] = $part;

What you will have here, is :

a) the stuff stored in the database not being role specific, and one  
data structure is capable of serving the entire system
b) expensive 'path index' building not needed.
c) no longer needing may_cache, as the callbacks can be stored in the  
database, but the final values can't.
d) Only the required parts of the tree are touched.

You could possibly select only the part of the tree you are  
interested in .. in this example :

node, node/1, node/%d, node/%s, node/1/edit, node/1/%d, node/1/%s,  
node/%d/edit  etc.

So you could put those all in an array, and search for just those  
menu items, and also sort them that way for traversal.

Doing such a search on a textfield could be expensive, but earl  
mentioned that we could possibly just do md5's of the data in
the database, and just doing a search on md5sums in (list of integers).

This is only part of the battle though, as matching paths to  
callbacks is a much lighter problem than actually displaying the menu.

But I think , that if you had the md5 of each of the parent elements  
of the menu items (and you have the entire path to your current  
you could create a single sql query to retrieve only the necessary  
levels from the tree.. and each of these layers could very possibly be
cached. (ie: get all the elements directly in the root, all the  
elements in node/ , all the elements in node/1 and all the elements  
underneath node/1).

>> Would doing a more formsapi-ish approach make the code easier to  
>> read? Slower? Faster?
> Not sure

Eh. i'm not sure either, but I'm confident with the tricks I  
outlined, we should be able to at least get the bootstrap  
requirements lowered,
since every load of drupal loads the _ENTIRE_ menu structure with  
_ALL_ the information needed to render that mammoth block.

Not to mention, that all the menu items are always loaded into drupal  
(it was the same case with the paths, and made them perform quite badly)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.drupal.org/pipermail/development/attachments/20060831/b4490bb9/attachment-0001.htm

More information about the development mailing list