If your module supports an arbitrary number of arguments and you want to verify that such a path is valid then you can't really do that because load functions get one argument. Now, you can't just add arguments to load because node_load will break. Instead we make this new functionality possible:
function gallery2_menu () {
$items['gallery/%gallery2'] = array(... );
}
function gallery2_menu_map(&$args) {
// For gallery/album1/album/pic1 $args is array('gallery', 'album1', 'album', 'pic1')
// Check whether this is a valid gallery2 path and if not set $args to FALSE.
}
Currently you need to do evil hacks and even then you will be dependent on $_GET['q'] which makes it impossible to add a menu link to such a path. The patch has a zero performance impact -- it adds very few lines of code (11) and to the normal execution path we have added one single if() command, nothing else. Even the condition that the if runs is already there.
If this gets in I will update the documentation -- but not the doxygen. It's very rarely used (but when you need it, you really do) and would just confuse people.
Core has no such thing, only search supports arbitrary number of arguments and it does not need to validate them.
| Comment | File | Size | Author |
|---|---|---|---|
| #28 | menu_map-177488-28.patch | 3.84 KB | chx |
| #15 | menu-map-177488-15.patch | 2.94 KB | chx |
| #8 | menu_load-177488-8.patch | 2.21 KB | chx |
| #7 | multi-args-177488-7.patch | 6.36 KB | pwolanin |
| #2 | menu_map-177488-2.patch | 2.91 KB | chx |
Comments
Comment #1
chx commentedActually, core has such a thing: profile categories. http://drupal.org/node/111481 I have fixed that issue depending on this one. And also, search can be slightly small if this gets in. The attached patch fixes a notice in the previous one and adds a comment in the code.
Comment #2
chx commentedI splitted the patch between here and the linked issue.
Comment #3
profix898 commented@chx: I didnt have time to join irc, so I hope you got my last mail about gallery_menu module. Looks like your session on this was quite productive. I will take time to review this patch shortly. Thanks a lot.
Comment #4
pwolanin commented@chx - could you please explain the logic of the code in more detail and/or add more code comments?
While I get the gist of what you're doing, this seems less than ideal. There seem to be other ways around this.
For example - if a single load function needs several args, you can put additional % elements in the path, and then get the values in the load function using arg().
Also, there seems to be a bug somewhere else in the code initially saving the load functions -
for example, in my DB in {menu_router} the path book/export/%/% has the load_function value of a:2:{i:2;N;i:3;N;}
Comment #5
chx commentedbook/export/%/% indeed reads as array(2 => NULL, 3 => NULL) regardless of my patch:
so, a bare percent sign will create a NULL.
This might not be needed any more, actually, but that's another issue. Regarding comments,
Finally, you must never use $_GET['q'] and friends in a load function because when you try to add a menu link to such a path then menu_get_item will run and you will get a nice 'path does not exist' error.
Comment #6
pwolanin commentedYes - sorry to confuse the issue - the book/export/%/% type issue is not a conequence of the patch, just something I noticed and probably needs a separate issue.
So, I don't really like this patch because it introduces a rather hackish flag of whether or no that column is serialized, and so on.
I see that you're right that a load function should never depend on arg(). So what's a clean alternative? One possibility - the prototype for all load functions could be something like:
this would mean we need to wrap node_load() in another function, but would be a cleaner general solution, I think.
Comment #7
pwolanin commentedthinking a little more - we need the $index as well as the $map
Comment #8
chx commentedLet's use an optional _menu_load function instead. %node_nid is not intuitive.
Comment #9
pwolanin commentedok - I like this one - it lets up keep %node while minimizing the changes to the menu code and still enabling a fix for the profile module bug.
Code tested and works fine.
Comment #10
gábor hojtsyNow this seems like an API break for those, who already started to post modules and depend on some load function not taking only one argument, right?
Comment #11
pwolanin commented@Gabor - a load function that only take a single argument will still work fine (e.g. user_load()) - it's only the rare cases like node_load() that take additional, different arguments that would have any problem. This patch provides a simple way around for them - see the node_menu_load() example.
Comment #12
chx commentedyes it's an api break indeed, sorry -- i can not really help it. the menu_map in #2 provides a non api break solution but it's far less elegant.
Comment #13
dries commentedWe need more code comments in this patch.
Also, the API is not 100% to my liking. The difference between _menu() and _menu_load() is not clear. Can we think of better names? Can we think of a better API?
Comment #14
pwolanin commented@Dries - so here are what I see as the 3 broad goals:
1) provide the full path and index information to the load function
2) have a fairly simple/obvious system of function naming for the load functions
3) be able to reuse as many existing load function as possible (this may be dispensible)
so, unfortunately #1 and #3 conflict for node_load() because it takes additional arguments. i think it might make the most sense in terms of a clean API to actually require a distinct name for all load functions, and not try to re-use existing functions - i.e. ditch #3. In the patch there is "X_menu_load". I'm not sure what would be more obvious? "X_callback_load", "X_menupath_load", "X_pathmap_load", "X_menutree_load".
So, in several cases these would just be simple wrappers around an existing load function (as with node_load in the patch). If you look at the linked issue for profile module, I've already had to introduce more logic than is handled by user_load(), so I used user_profile_load().
Comment #15
chx commentedThis patch is another way. It needs commenting and the user part removed to the other issue but it serves as an example.
Comment #16
pwolanin commentedhmm, this could work, but I still prefer something like #8 where we just pass all the needed info to the load function.
Comment #17
pwolanin commentedso, just to clarify, it seems there are at least 4 separate approaches proposed to fix this bug. So, more feedback fmor Dries/Gabor is needed.
a quick summary:
I don't like the 1st at all. The 4th is a bit weak too since then the load function doesn't know it's index and thus cannot be re-used for different menu paths where the load function may appear at different positions in the path.
So, my preference among the above is 3,2,4,1
Comment #18
chx commentedThe approach in #15 definitely knows about the index it returns array($index, $map). I really like the reusability of the load functions so I would say my order of preference is the exact opposite of pwolanin's: 1, 4, 2, 3.
Comment #19
pwolanin commentedwell in that case, my preference is really "any of these except #1"
Comment #20
chx commentedWell, then our choice should be #4 because Dries did not like #2 and I much do not like #3.
so, please review the latest patch :)
Comment #21
chx commentedI told eaton that in user/1/edit/this/is/a/problem , this/is/a/problem is one argument and that's the problem and then he came up with this title.
Comment #22
pwolanin commentedwas this supported in D5? I'm trying it now, and adding slashes to the profile name breaks in D5.
Comment #23
chx commentedthat may be but the other use of this patch is gallery2 which is more or less unportable at this moment. also, with !$may_cache you had ways to deal with this bug, it's a whole another issue that this was a bug in D5 but in D5 you *could* deal with it.
Comment #24
profix898 commented@chx: I wrote you an email about 2-3 days ago that I managed to port gallery_menu module. I found a simple way to 'hack' G2 (plain query against the db instead of using G2 API), so that the module can be ported to D6 using 'normal' static menu items and callbacks. However it requires a call to menu_rebuild() if an album changed in G2. It would be great to have an additional parameter for menu_rebuild to rebuild the menu items of a certain module only (reduces overhead of calling menu_rebuild()), e.g. menu_rebuild('gallery') refreshes the menu items of 'gallery' module only. Otherwise it is working without this patch now.
Comment #25
chx commentedGallery might work but it's an ugly quirk to mandate menu_rebuild -- but user categories still do not work... the latest patch is really not evasive API wise.
Comment #26
gábor hojtsyWell, I looked at the patch, but there is nothing to help me understand how menu_get_object_map() and menu_set_object_map() are useful / should be used. There are no docs. user_category_load() should also be sprinkled with docs on why this is done, what is the task, why is this the solution?
I think it is a good idea to keep the current naming scheme, and distance ourselfs from thinking about introducing new APIs or changing existing ones.
Comment #27
gábor hojtsychx asked for clarification. I tried to explain that the latest patch looks reasonable, because it does not modify any forward facing APIs. The object map code it adds and uses however is quite obscure without documentation, so let's see some explanation (phpdoc on all functions added) in the code to see the picture better. The user_category_load() is also in need of some inline comments to make it clear what it does and why.
Comment #28
chx commentedI mentioned above that if this patch will be chosen, I will add comments so there. The user part is still in, I guess we can fix http://drupal.org/node/111481 in one commit otherwise this patch makes no sense.
Comment #29
chx commentedhttp://drupal.org/node/184022 fixed this sorry mess.
Comment #30
(not verified) commented