Drupal Pipes
chx - February 7, 2008 - 03:29
| Project: | Drupal |
| Version: | 7.x-dev |
| Component: | base system |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | active |
Description
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').
<?php
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);
}
}
}
?>
#1
Note 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.
#2
<?php
function hook_callbacks() {
return array(
'node_load' => array('input' => array('integer'), 'output' => 'node', FALSE => MENU_NOT_FOUND),
'node_access' => array('input' => array('string', 'node'), 'output' => 'boolean', FALSE => MENU_ACCESS_DENIED),
'node_show' => array('input' => array('node'), 'output' => 'html'),
'theme' => array('input' => array('string', 'args'), 'output' => 'html', 'defaults' => array('string' => 'page')),
);
}
function drupal_run_callbacks($callbacks, $outputs = array()) {
$callback = reset($callbacks);
while ($callback) {
$function = key($callbacks);
if (isset($callback['input'])) {
$args = array();
foreach ($callback['input'] as $argument) {
if (isset($callback['args'][$argument])) {
$args[$argument] = menu_unserialize($callback['args'][$argument]);
}
elseif (isset($callback['defaults'][$argument])) {
$args[$argument] = menu_unserialize($callback['defaults'][$argument]);
}
else {
return FALSE;
}
}
$outputs[$callback['output']][$callback['destination']] = call_user_function_array($function, $args);
}
else {
$outputs[$callback['output']][$callback['destination']] = $function();
}
// TRUE or FALSE.
$transition_key = (bool)$output;
if (isset($callback[$transition_key])) {
return $callback[$transition_key];
}
else {
$callback = next($callbacks);
foreach ($callback['input'] as $argument) {
if (isset($outputs[$argument][key($callback)])) {
$callback['args'][$argument] = $outputs[$argument][key($callback)];
}
else {
return FALSE;
}
}
}
}
}
?>
Another very rough draft. This one assumes some nonexistent code that lets the administrator define which callback gives its output to which input(s).
#3
chx, 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?
#4
Want 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.
#5
As 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()
#6
Here'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.
#7
Subscribing - 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
#8
Subscribe.
#9
Subscribing.
#10
Subscribing.
#11
me too.
#12
Subscribing too.
#13
track
#14
yep subing
#15
Subscribing.
#16
Subscribing.
#17
Subscribe.
#18
Could 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.
#19
Subscribing.
#20
cwgordon7... any progress?
#21
chx 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.
#22
Minor code style comment - I see a couple of if ifs there where && would be clearer.
#23
Subscribing.
#24
There is, in fact, a patch.
#25
Uh, no, there's not.
#26
Interesting 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.
#27
Two words. One dimension.
#28
Subscribe.
#29
Interesting... subscribing.
#30
So 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.