The basic idea is to execute a chain of callbacks with the output of one as the input of the next. For example, node_load gets 123 as an argument (from the URL), returns a $node. Pass this to node_access which either returns the $node or FALSE (needs patching but if (node_access($node)) wont change). Pass this to node_show. Pass the return value of node_show to theme('page').
callbacks => array(
'menu_load' => array('callback' => 'node_load', 'arguments' => array(1), FALSE => MENU_NOT_FOUND),
'menu_access' => array('callback' => 'node_access', FALSE => MENU_ACCESS_DENIED),
'menu_page' => array('callback' => 'node_show'),
'menu_render' => array('callback' => 'theme', 'arguments' => 'page'),
);
function drupal_run_callbacks($callbacks, $last = NULL) {
$callback = reset($callbacks);
while ($callback) {
$function = $callback['callback'];
if (isset($callback['arguments'])) {
$arguments = array_merge(menu_unserialize($callback['arguments']), array($input));
$input = call_user_function_array($function, $arguments);
}
else {
$input = $function($input);
}
unset($transition);
// TRUE or FALSE.
$transition_key = (bool)$output;
if (isset($callback[$transition_key])) {
$transition = $callback[$transition_key];
if (isset($callbacks[$transition])) {
reset($callbacks)
while ((list($key, $callback) = each($callbacks)) && $key != $transition);
}
else {
return $transition;
}
}
else {
$callback = next($callbacks);
}
}
}
Comments
Comment #1
chx commentedNote that the function would need a return $input to make it really useful, also the keys of callbacks array are totally arbitrary and not even used in the above.
Comment #2
cwgordon7 commentedAnother very rough draft. This one assumes some nonexistent code that lets the administrator define which callback gives its output to which input(s).
Comment #3
Stefan Nagtegaal commentedchx, I'm sure you overthought this very well, and there are plenty of use cases for this.. Unfortunatly, I can't come up with one.. Can you share some use cases?
Comment #4
chx commentedWant to get back the results in some other format than the full themed page? Just alter the last callback. Want to restrict access more? Piece of cake. We can do tricks like execute a query and then just call node_feed with said result as the next callback. If you want, say, an Atom feed, change that step. Reusability and hackability at its best.
Comment #5
moshe weitzman commentedAs a conceptual model, this is terrific. We'll work some more on how this actually gets patched into drupal.
callback is a bit of a loaded word in drupal already. perhaps we create a new word. i pondered a bit and i think 'steps' works for me. the array element that refers to a function can still be called callback. just rename to hook_steps and drupal_run_steps()
Comment #6
cwgordon7 commentedHere's an initial patch, just for an update. The framework is pretty much there, may need some tweaking. What's needed next is implementations of the hooks, and then we can cut maybe 10% of all code from core modules ;). Any feedback would be appreciated. Note: this has no UI yet, but it will (and hopefully an excellent one, too).
Sorry that the .inc file is attached as a txt, I was having patching issues. It just needs to be placed in the includes directory.
Comment #7
starbow commentedSubscribing - I am keeping an eye on this in case it can provide a clean foundation for #218830: Popups in Drupal 7: Plugable renderers for generating content
Comment #8
kbahey commentedSubscribe.
Comment #9
Crell commentedSubscribing.
Comment #10
wim leersSubscribing.
Comment #11
catchme too.
Comment #12
cburschkaSubscribing too.
Comment #13
bcn commentedtrack
Comment #14
somes commentedyep subing
Comment #15
profix898 commentedSubscribing.
Comment #16
sign commentedSubscribing.
Comment #17
BioALIEN commentedSubscribe.
Comment #18
cpelham commentedCould this be used to create views or rss feeds with much more complex logic than is now possible, for instance to output 10 nodes, teasers, list, whatever, containing 3 nodes from one source, 2 from another, and 5 from a third, but all sorted together according to whatever sort criteria one specifies?
Meaning it would take the output of three views as input for a fourth view.
Comment #19
amitaibuSubscribing.
Comment #20
birdmanx35 commentedcwgordon7... any progress?
Comment #21
cwgordon7 commentedchx and I discussed this and decided that we have fundamentally different ideas. He will continue to work on this thread, and I will take mine into contrib.
Comment #22
catchMinor code style comment - I see a couple of if ifs there where && would be clearer.
Comment #23
ezra-g commentedSubscribing.
Comment #24
birdmanx35 commentedThere is, in fact, a patch.
Comment #25
cwgordon7 commentedUh, no, there's not.
Comment #26
gábor hojtsyInteresting concept, but I'd wonder how would this perform. The themes are already pluggable, so renderer changes are possible without this "If you want, say, an Atom feed, change that step" is not technically new.
Comment #27
macgirvin commentedTwo words. One dimension.
Comment #28
robertdouglass commentedSubscribe.
Comment #29
dropcube commentedInteresting... subscribing.
Comment #30
jscheel commentedSo this basically becomes a filter chain, right? That way you can branch off at any given link in the chain? It would be interesting to be able to branch off, then reconnect further down the chain, effectively by-passing only the one section of the chain that you want to bypass. Wow, I said chain a lot.
Comment #31
drewish commentedsubscribing
Comment #32
bdragon commentedsubscribe
Comment #33
summit commentedsubscribing
Comment #34
andypostLooks like workflow-rules and in conjunction with triggers can be very usefull
Comment #35
chx commentedRecording progress. http://www.drupalbin.com/4621 is some new code. Writeup (which wont likely to make sense without checking that pastebin):
Now, the menu definitions would not change that much because most of the magic (esp the transitions) will be added as defaults. I might move back the path into a key as I want more to make possible to have several steps array defined on node/% .
Comment #36
sdboyer commentedsubscribin.
Comment #37
chx commentedComment #38
chx commentedWe just discussed this with pwolanin and I was afraid of unserializing a huge array for every single link. So we now think that if the steps are only the known defaults which defines a menu entry with pretty much the same features as like now, then the first two steps, for example we can call them menu_load and menu_access, these will be stored like they are now so that the common case will be fast.
Comment #39
skilip commentedsubscribing
Comment #40
R.Muilwijk commentedsubscribin
Comment #41
jpetso commentedsubsub
Comment #42
chx commentedAnother step :p hopefully in the right direction. Still not integrated into Drupal but I implemented the transition part and set to CNR because I would like indeed the code to be reviewed and agreed upon before I continue. Writeup in #35. transition, for now, is just a simple compare.
Comment #43
Anonymous (not verified) commentedsubscribe
Comment #44
xanoSubscribing.
Comment #45
mfer commentedsubscribe
Comment #46
Arto commentedGood stuff. Subscribing.
Comment #47
Anonymous (not verified) commenteddiscussed this with chx at the DCDC code sprint. maybe i'm just missing stuff, so i'm going to post so i can be corrected.
i like the idea of chainable menu callbacks, but i don't know if building a general purpose pipe system is the way to go. do we really want to build a system that can just arbitrarily chain together functions? functions in php don't just read from STDIN and return a string to STDOUT :-(
how do we decide which step to take next if we are building up the chain ahead of time? aren't we going to want to do that at runtime?
how about a simpler approach that just allows for multiple callbacks?
here's a way to do that that is simpler, that chx doesn't like, but i'll let him explain why.
- it requires a set api for callback functions:
- it makes these functions not reusable as general purpose functions. in my opinion, this is not a problem, or at least, the solution to this (a system that can arbitrarily chain together functions with any signature and return values to any other function) is worse
- drupal_get_form, and anything else that is a callback and also something else, wouldn't work. i don't think this is a bad thing, but chx disagrees, not the first or last time i'm sure :-)
we can take the same approach to adding multiple access callbacks, much smaller scope patch, less powerful.
anyway, my US$0.02.
attached is a patch that shows a possible way to do the multiple page callbacks stuff. not complete, but i hope it makes some of what i'm saying clearer, even if to make it easier to explain why this approach wont fly. don't want to hijack this issue, so i'm happy to take this elsewhere.
Comment #49
EvanDonovan commentedWould this concept of multiple page callbacks (I'm thinking especially of the patch in #47) do anything that could help fix my issue #501372: RDF module conflicts with overridden taxonomy_term_page() implementations?
Essentially my problem is that various contrib modules (Panels 3 via the Delegator module, RDF, Taxonomy Translation (i18ntaxonomy), and Taxonomy Manager) want to do various things to alter taxonomy_term_page(), but ultimately want to return a display of nodes which have a particular taxonomy term.
I would love to be able to chain these implementations together, essentially altering the taxonomy_term_page() but not overriding it 100%. But I don't know enough of what these does to know if it's actually related, or if that's just a pipe dream.
Comment #50
catchMoving to D8.
Comment #51
arhak commentednote that Drupal have abrupt
exitcalls which might attempt against this featurefor instead, one callback ending in a
drupal_goto(or cron) would halt remaining callbacksI think Drupal should avoid using
exitcalls and let every function end naturally #592664: function calls should end naturally (avoid exit calls)Comment #52
mustanggb commentedSubscribe
Comment #53
valthebaldBumping to 9.x
Comment #54
chx commentednah, the whole idea is obsolete with routes.