<HTML><BODY style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space; "><BR><DIV><DIV>On 30 Aug 2006, at 8:25 PM, Johan Forngren wrote:</DIV><BR class="Apple-interchange-newline"><BLOCKQUOTE type="cite"><BLOCKQUOTE type="cite"><P style="margin: 0.0px 0.0px 0.0px 10.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica">WWFAPID? (What would FormsAPI do?)</FONT></P> </BLOCKQUOTE><P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>$menu['menu'] = array(</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#type' => 'menu',</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#path' => array ('menu', 'yet', 'another', 'path', 'etc'),</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#title' => t('Menu'),</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#tree' => TRUE,</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#collapsible' => TRUE,</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#collapsed' => TRUE,</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>);</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>$menu['menu']['item'] = array('</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#type' => 'node',</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#nid' => 1337,</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#title' => t('Node'),</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#description' => t('A node item'),</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#weight' => 5,</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>);</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>$menu['menu']['item2'] = array('</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#type' => 'page',</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#callback' => 1337,</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#title' => t('A page'),</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>'#path' => array(t('translatable'), t('path')),</FONT></P> <P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica"><SPAN class="Apple-converted-space"> </SPAN>);</FONT></P></BLOCKQUOTE><DIV><BR class="khtml-block-placeholder"></DIV><DIV>a couple of things for this. </DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>You would still sit with the may_cache issue, in that every run would need 2 calls, because it can't be cached.</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>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. </DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>. In the following case :</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> $menu['node']['%d'][edit'] = array('</DIV><DIV style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> '#type' => 'page',</DIV><DIV style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> '#callback' => 'drupal_get_form',</DIV> '#callback_arguments' => callback('arg', 1), // returns an array, so you can do callback(something) + callback(something)</DIV><DIV> '#access' => callback('user_access', 'some_permission'),<BR><DIV style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> '#title' => t('A page'),</DIV><DIV style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> '#path' => array(t('translatable'), t('path')),</DIV><DIV style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> )</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>Take for example if you had the entire menu loaded into memory (and unserialising it is quite expensive too).</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>When loading up the system, is can go :</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>$section &= $menu;</DIV><DIV>$parts = expode('/', $_GET['q']);</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>foreach ($parts as $part) {</DIV><DIV> $x++;</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV> // this if statement will almost surely be incorrect, but it has the general idea</DIV><DIV> if (isset($section[$part]) || (is_numeric($part) && isset($section['%d'])) || (isset($section['%s']) ) {</DIV><DIV> // finds all callback arrays, and trigger them</DIV><DIV> trigger_callbacks($section[$part]); </DIV><DIV> if (!$section['#access']) {</DIV><DIV> drupal_access_denied();</DIV><DIV> break;</DIV><DIV> }</DIV><DIV> else {</DIV><DIV> //success, we have access to this item</DIV><DIV> $section &= $section[$part];</DIV><DIV> $found_part[] = $part;</DIV><DIV> }</DIV><DIV>}</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>What you will have here, is :</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>a) the stuff stored in the database not being role specific, and one data structure is capable of serving the entire system</DIV><DIV>b) expensive 'path index' building not needed.</DIV><DIV>c) no longer needing may_cache, as the callbacks can be stored in the database, but the final values can't. </DIV><DIV>d) Only the required parts of the tree are touched. </DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>You could possibly select only the part of the tree you are interested in .. in this example :</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>node, node/1, node/%d, node/%s, node/1/edit, node/1/%d, node/1/%s, node/%d/edit etc.</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>So you could put those all in an array, and search for just those menu items, and also sort them that way for traversal.</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>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 </DIV><DIV>the database, and just doing a search on md5sums in (list of integers). </DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>This is only part of the battle though, as matching paths to callbacks is a much lighter problem than actually displaying the menu.</DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>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 location), </DIV><DIV>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</DIV><DIV>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).</DIV><DIV><BR class="khtml-block-placeholder"></DIV><BR><BLOCKQUOTE type="cite"> <BLOCKQUOTE type="cite"><P style="margin: 0.0px 0.0px 0.0px 10.0px; font: 12.0px Helvetica; min-height: 14.0px"><BR></P> <P style="margin: 0.0px 0.0px 0.0px 10.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica">Would doing a more formsapi-ish approach make the code easier to read? Slower? Faster?</FONT></P> </BLOCKQUOTE><P style="margin: 0.0px 0.0px 0.0px 0.0px"><FONT face="Helvetica" size="3" style="font: 12.0px Helvetica">Not sure</FONT></P> </BLOCKQUOTE></DIV><BR><DIV>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,</DIV><DIV>since every load of drupal loads the _ENTIRE_ menu structure with _ALL_ the information needed to render that mammoth block. </DIV><DIV><BR class="khtml-block-placeholder"></DIV><DIV>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)</DIV></BODY></HTML>