Hi, Reading the hook_nodeapi thread... In Drupal 6 I would like to see a hook registry -- mostly autodiscovered, but if you want ordering, then you can say "my implementation of hook_nodeapi is to be run before module this,that,foor,bar". Available in my sandbox, weight.php . It's trivial to extend this capatibility to packages as well, so that if you ask to be run before !views then you will run before all modules that belong to the views package. All nice and dandy. But, the next step would be to request for "I want to be the first for hook_foo". What am I to do if two module asks for this? Die a horrible death? Disable the offending modules? This code, quite obviously will run on the modules page. Regards NK Ps. Extending hook registry to hook#op is also in the plans.
Karoly Negyesi wrote:
In Drupal 6 I would like to see a hook registry -- mostly autodiscovered, but if you want ordering, then you can say "my implementation of hook_nodeapi is to be run before module this,that,foor,bar". Available in my sandbox, I don't know which sandbox is yours and didn't see 'knegyesi', 'negyesi' or 'karoly' under http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/. So, without looking at the code...
I've found more of a need to say 'this hook must run after module this,that,foo,bar'. I figure you were not actually implying that the two ordering options were going to be limited to 'before' and 'first', but I didn't want to leave the open assumption. Overall the registry would be helpful. I've encountered a number of cases where I needed to make sure one of my hooks ran after the hooks for other modules, and hacking the system weight is only something I'll do as a last resort and for a module that won't leave a deployment that I manage.
All nice and dandy. But, the next step would be to request for "I want to be the first for hook_foo". What am I to do if two module asks for this? Die a horrible death? Disable the offending modules? This code, quite obviously will run on the modules page.
I agree that is a challenge, since the person who picked the 'first' ordering may not run with the particular module combination that an arbitrary site builder/admin will install. I like the current pattern of hook_load() and friends as being 'first' for a module that defines its own type. How about leaving that in place and only allowing 'before' and 'after' designations in the proposed registry? Scott
----- Start Original Message ----- Sent: Wed, 03 Jan 2007 16:52:45 -0600 From: Scott McLewin <drupal@mclewin.com> To: development@drupal.org Subject: Re: [development] Hook ordering
Karoly Negyesi wrote:
In Drupal 6 I would like to see a hook registry -- mostly autodiscovered, but if you want ordering, then you can say "my implementation of hook_nodeapi is to be run before module this,that,foor,bar". Available in my sandbox, I don't know which sandbox is yours and didn't see 'knegyesi', 'negyesi' or 'karoly' under http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/. So, without looking at the code...
I need to work on my reputation :) http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/chx/weights.php?v...
I agree that is a challenge, since the person who picked the 'first' ordering may not run with the particular module combination that an arbitrary site builder/admin will install. I like the current pattern of hook_load() and friends as being 'first' for a module that defines its own type. How about leaving that in place and only allowing 'before' and 'after' designations in the proposed registry?
hook_load is not a real hook, it's a callback, because at any given time only one is called. hook_nodeapi is a hook, at any given time all implementations are called in order. For example, hook_form_alter. What happens when two modules try to be the first? Or the last for that matter?
Karoly Negyesi wrote:
I need to work on my reputation :) http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/chx/weights.php?v...
I never bound your handle to your name. Ok, I know where that sandbox is.
of hook_load() and friends as being 'first' for a module that defines its own type. How about leaving that in place and only allowing 'before' and 'after' designations in the proposed registry?
hook_load is not a real hook, it's a callback, because at any given time only one is called. hook_nodeapi is a hook, at any given time all implementations are called in order.
For example, hook_form_alter. What happens when two modules try to be the first? Or the last for that matter?
I realize that, I was using hook and callback synonymously when I should not have. Or rather Drupal is and I was sucked into the nomenclature. :) My point still stands, don't deal with the 'first' or 'last' case in a hook registry. I suggest that the registry only allow for 'before' and 'after', just as your sandbox code is authored. The module that 'owns' the node type can declare callback_load() when it needs logic to be run first. I recognize that there is confusion on hook_nodeapi() vs _load()/_update()/etc. The really do look like they overlap when one first sees them, but that difference of one being called on every single node type vs. being only called on the module's node type is important. Somewhere else in this thread it was suggested that hook_nodeapi() be renamed to hook_node_alter(). That is a simple change that is in line with the _alter() pattern that is spreading through the Drupal API. I think it also stands to clear up some of the confusion between _nodeapi(op=operator) vs hook#operator() callbacks. Larry Garfield states that he cannot understand the infatuation with fewer functions and more switch() statements. I agree with him. The callbacks we know as hook_load()/hook_update()/hook_insert()/etc are much more in line with object patterns. What do you all think about changing hook_nodeapi() to hook_node_alter() in Drupal 6? Scott
After the suggestion of "module" ordering for hook certain, I thought a bit and conclude that the problem is that we have some "events" missing. Let's make a resume: * hook_load() is called for the specific module that implements that node type (only after 4.7 it was implemented a nice way to have multiple node types inside a unique module) * hook_nodeapi('load') is called *after* a node is loaded (are you seeing the problem?) We need more events, and with correct names for nodeapi: * load - called only for the modules that implement the specific node types. If "example.module" implements a node "xpto" that, then nodeapi('load') will only be called for this module, because it knows that is "example.module" that has "xpto" node type * after load - called for every other module, after the 'load' was done and allowing the altering and adjustment of the already loaded fields * insert * after insert * update * after update * delete * after delete Are you seeing what we can do here? Funny, we can add a "before *event*" allowing us to do things before anything is done. What do you think? On 1/3/07, Karoly Negyesi <karoly@negyesi.net> wrote:
Hi,
Reading the hook_nodeapi thread...
In Drupal 6 I would like to see a hook registry -- mostly autodiscovered, but if you want ordering, then you can say "my implementation of hook_nodeapi is to be run before module this,that,foor,bar". Available in my sandbox, weight.php . It's trivial to extend this capatibility to packages as well, so that if you ask to be run before !views then you will run before all modules that belong to the views package.
All nice and dandy. But, the next step would be to request for "I want to be the first for hook_foo". What am I to do if two module asks for this? Die a horrible death? Disable the offending modules? This code, quite obviously will run on the modules page.
Regards
NK
Ps. Extending hook registry to hook#op is also in the plans.
We need more events, and with correct names for nodeapi:
Are you seeing what we can do here? Funny, we can add a "before *event*" allowing us to do things before anything is done.
What do you think?
You guys run on another track than I do. I am wrapping my head around renaming hook_nodeapi op foo to hook_node_foo and finding a better name for hook_load (which is not a hook). Functor came to my mind. I am vehemently against removing hook_load and friends -- it's ridiculous to remove a good, working concept just because it's confusing to some. When I explain Drupal coding I always explain that node system can be expanded in two, orthogonal directions, one being you can create your own node types and use hook_load and friends and the other direction being hook_nodeapi
These are just ideas. Don't misunderstand me, I've already spot that "hook_load and friends" vs "nodeapi" have just a difference: the first is reliable to create a new node type from ground up; the second is reliable to extend current node types adding new independent fields. Now the question is that these are two ways that are being badly mixed up. Do you want an example? nodeapi('delete revision')! If we are working with the hook_load and friends and really do not need nodeapi, there should be more hooks to allow the control (and development of a complete node type) without recurring to *both* mechanisms. The problem right know is quite simple: it is not possible to create a fully node type without recurring to both node APIs. And (assuming this) the questions are: * why do have we to use both? * if one will stand up, what will be? * CCK does not solve the "basic" and "primitive" problem of creating a fully node type, that is independent and that will not have fields available to "share" with other node types (despite the fact that almost everyone wants to say that CCK is the *only* future). CCK is fantastic (with the generic fields) for the creation of user node types and forms. Thats it. * when developing a fully node type we have the need to know where, when and how we can intercept some event (Drupal 5 has many new great things to do this for forms) Now, as I can see what you want is remove "nodeapi" stuff and convert it for the hook_node_foo naming scheme. Nice, I'll help you with that: * hook_load -> hook_node_load($when) * hook_insert -> hook_node_insert($when) * hook_nodeapi(op) -> hook_node_op($when) * etc, etc, etc Being that $when would have the values "before", "after" or empty That would result in: * hook_node_load('before') called for every available module * hook_node_load() called only for the module that implements the specific node type * hook_node_load('after') called again for every available module Ah, and if you want to change "hook" to something, you could try "event", but why would we do that if we have only one understandable system?! :-D On 1/5/07, Karoly Negyesi <karoly@negyesi.net> wrote:
We need more events, and with correct names for nodeapi:
Are you seeing what we can do here? Funny, we can add a "before *event*" allowing us to do things before anything is done.
What do you think?
You guys run on another track than I do.
I am wrapping my head around renaming hook_nodeapi op foo to hook_node_foo and finding a better name for hook_load (which is not a hook). Functor came to my mind.
I am vehemently against removing hook_load and friends -- it's ridiculous to remove a good, working concept just because it's confusing to some. When I explain Drupal coding I always explain that node system can be expanded in two, orthogonal directions, one being you can create your own node types and use hook_load and friends and the other direction being hook_nodeapi
On 1/5/07, Fernando Silva <fsilva.pt@gmail.com> wrote:
Now the question is that these are two ways that are being badly mixed up. Do you want an example? nodeapi('delete revision')! If we are working with the hook_load and friends and really do not need nodeapi, there should be more hooks to allow the control (and development of a complete node type) without recurring to *both* mechanisms.
I agree, I created an issue to add hook_delete_revision() back in feburary: http://drupal.org/node/50627 I'd also like to see 'rss item' made into a hook too but I'll wait to see the outcome of this thread. andrew
* why do have we to use both?
Because http://drupal.org/node/50627 got little love. We are not perfect. Working on it though.
* if one will stand up, what will be?
Both will stand up.
Now, as I can see what you want is remove "nodeapi" stuff and convert it for the hook_node_foo naming scheme. Nice, I'll help you with that: * hook_load -> hook_node_load($when) * hook_insert -> hook_node_insert($when) * hook_nodeapi(op) -> hook_node_op($when) * etc, etc, etc
Still no. If teddy.module implements a node type then teddy_load remains. Just I am trying to find a better name to call this, because the hook part of hook_load does not really fit. As said, functor came to my mind -- functor_load. Might be a bad idea. Do not know yet. It took me five years to get a good translation in Hungarian for the word 'bully'... Reason for this change: hook is something that is called by module_invoke_all or similar. Code change: zero. This is a documentation change. But, if event module wants to add events to teddy nodes then it currently acts on hook_nodeapi op load. It's a true hook. Currently I think we would be better off calling this hook_node_load. Reason for this change: easier to fit into hook registry/order system. But then again -- hook_nodeapi#load could also be ordered. Just feel clumsy. Code change: for more complex modules, extremely little -- they have their handlers for different ops in different functions already. If you want to further this discussion then give me reasons why your change is better than the current, nice, orthogonal system. I am not changing the system at all, just renaming stuff a little bit.
Karoly Negyesi wrote:
fit. As said, functor came to my mind -- functor_load. Might be a bad idea. Do not know yet. It took me five years to get a good translation in Hungarian for the word I get what you are after and agree that differentiation between hooks and whatever hook_load() is should be made.
I don't have a great answer on this myself. Functor strikes me as the correct term but as an inappropriately challenging word. A functor to me represents an object that is a calling proxy for an actual implemented function. One can have multiple functors, but only one implementation. 'callback' as the prefix term is also slightly off. I'm not passing the function pointer into something to get called back on. What about slight variations on either of these. func_load() or callout_load(). 'func' as the prefix implies more of a function rather than an object representing a function. I'm tainted by a C++ background and may be in the minority in how I read 'functor' vs. 'func'. 'callout' is fairly descriptive of what is happening. Something in core is calling out to my function. As I've left this message sitting to think about it more I find that this term sits best with me. Am I allowed to +1 my own idea? :)
If you want to further this discussion then give me reasons why your change is better than the current, nice, orthogonal system. I am not changing the system at all, just renaming stuff a little bit.
I like the current, nice, orthogonal system. Scott
On Friday 05 January 2007 5:11 pm, Scott McLewin wrote:
Karoly Negyesi wrote:
fit. As said, functor came to my mind -- functor_load. Might be a bad idea. Do not know yet. It took me five years to get a good translation in Hungarian for the word
I get what you are after and agree that differentiation between hooks and whatever hook_load() is should be made.
*snip*
What about slight variations on either of these. func_load() or callout_load().
'func' as the prefix implies more of a function rather than an object representing a function. I'm tainted by a C++ background and may be in the minority in how I read 'functor' vs. 'func'.
I'm going to be completely evil and toss out method_load(), since that suite of whatever-they-are are effectively methods of a node object, just not using Class syntax.
If you want to further this discussion then give me reasons why your change is better than the current, nice, orthogonal system. I am not changing the system at all, just renaming stuff a little bit.
I like the current, nice, orthogonal system.
Scott
Me three! -- Larry Garfield AIM: LOLG42 larry@garfieldtech.com ICQ: 6817012 "If nature has made any one thing less susceptible than all others of exclusive property, it is the action of the thinking power called an idea, which an individual may exclusively possess as long as he keeps it to himself; but the moment it is divulged, it forces itself into the possession of every one, and the receiver cannot dispossess himself of it." -- Thomas Jefferson
Scott, Can you clarify a bit between why "callout" is ok but "callback" is wrong. I understand your remark about not passing a function pointer into something to get called back (I'm an old C kernel device driver programmer). But if something in core is calling out to your function, and your module somehow registered that such a function is available, how is it not a callback? If I'm confused here, and you didn't register the function (you passed an object, so that seems like a positive registration action), but core just looks for the function, then it sounds like a hook -- which given other messages it seems like it is not. Sorry if my density is getting the way of understanding here. :-) Thanks. ..chrisxj
Chris,
Sorry if my density is getting the way of understanding here. :-)
It's probably not density on your part, but just the way I think about the pattern.
function, and your module somehow registered that such a function is available, how is it not a callback?
Unlike C, I'm not explicitly registering nodetype_operation() to be called in the hook_load() pattern. If the function exists, it is called when appropriate, if it does not exist, it is not called. In my way of thinking, if I don't explicitly register it and some bit of code is hot maintaining a function pointer to my callback, it's not a callback. I'm not being called 'back', rather core is calling out to a function that I can declare if I want to. It is a subtle difference, and not one that I'll go to the mat defending as The Right And Proper Way.
core just looks for the function, then it sounds like a hook -- which given other messages it seems like it is not.
The differentiation that chx is making with hooks vs 'something else' is that something like hook_nodeapi() is called on every implementing module every time the hook invocation function is called. It is up to each hook_nodeapi() implementation to figure out when to act and when to remain dormant, and in general any given hook_nodeapi() implementation should not rely on the order in which the hooks are called. hook_form_alter() follows this same pattern, as do many others. hook_load()/hook_insert() and such are called explicitly as a single function call based on the node type. In this pattern core is not calling a series of functions across all implementing modules, but rather calling a single function if it happens to exist. Larry Garfield thought he was being evil by suggesting 'method_load()' as the pattern name. That's not a bad idea either. I've chimed in on this thread because the distinction between hooks that are called in an 'unordered' (ignoring system weights) set vs the hooks that are called based on node type was not clear to me when I started with Drupal two years ago. Both were called hooks, and it took me a while to work out that they were different. I was confused as to when I needed to check input parameters to decide whether to take an action, vs when my function was expected to take an action no matter what. From the module authoring perspective that's a big difference. Like many others, I just cut and pasted from working code without really getting it (for a while). I'll happily field follow-on questions to my warped world views, but in the bigger picture I think this thread has probably run it's course. Scott Chris Johnson wrote:
Scott,
Can you clarify a bit between why "callout" is ok but "callback" is wrong. I understand your remark about not passing a function pointer into something to get called back (I'm an old C kernel device driver programmer). But if something in core is calling out to your function, and your module somehow registered that such a function is available, how is it not a callback?
If I'm confused here, and you didn't register the function (you passed an object, so that seems like a positive registration action), but core just looks for the function, then it sounds like a hook -- which given other messages it seems like it is not.
Sorry if my density is getting the way of understanding here. :-)
Thanks.
..chrisxj
Thanks for the follow-up, Scott. Now I do understand. I agree; it's not a call back at all. It's much closer to the hook system, but with significant enough differences that it is not a hook, either. I had the same confusion you did regarding these 2 different things which are called hook_*(). Finding a really good name would be helpful, but likewise may be (already is?) challenging. ..chrisxj
Hi, I should completely clear up one point: I do not want to change the systems I just propose to *unify* and *clarify* them (unfortunately that means change the current code)! A1. in the beginning I (wrongly) assumed that nodeapi() was the new API that unified in a single place the work with both node (full node type) and fields (fields added as a way to extend node functionality) A2. You guys helped by showing me the differences. So I assumed that I should use hook#operator() when working with nodes and _nodeapi(op=operator) when working with fields A3. The first problem of this orthogonal system, is that with the evolution it got we can easily forget to update both systems with the required hooks, examples: "delete revision", "search result" and "rss item"; forcing developers to make patches or use both hooks. A4. A nice and *orthogonal* system implies more code to maintain than a nice and *straight* system. A5. The second problem, is that is too easy to mix how this orthogonal system works. In fact some of you say that we should go with CCK fields to create new nodes, and in this case what is reason to have a system to work with nodes instead of only fields?! A6. This complex problem is result of insufficient documentation, a node system that has it's fully potential locked to the fear of changes, insufficient programmatic use of the node system by contrib developers. What I propose is the following (after reading all the messages here): P1. implement *all* hooks as hook_node#operator() -- eg. hook_node_load() -- which solves the naming scheme. P2. remove of _nodeapi(op=operator) which simplifies the system P3. add to the hook_node#operator() a parameter "when", allowing *all* modules to intercept "before" and/or "after" the event itself. Today with nodeapi(), we can only intercept "after". P4. Have the same functions to work the same logical way, helps doing a better documentation that is easier to understand. The hook_node#operator() would work with both complete nodes and extension fields. Think a bit... what can we do with the certain that we can intercept hooks "before", "on" and "after"?! Conclusion: I do not want to only do a simple name change. I'm proposing the leverage of the node system, so it can be more useful to implement much more flexible modules and easier to maintain. Regards, Fernando Silva On 1/5/07, Karoly Negyesi <karoly@negyesi.net> wrote:
* why do have we to use both?
Because http://drupal.org/node/50627 got little love. We are not perfect. Working on it though.
* if one will stand up, what will be?
Both will stand up.
Now, as I can see what you want is remove "nodeapi" stuff and convert it for the hook_node_foo naming scheme. Nice, I'll help you with that: * hook_load -> hook_node_load($when) * hook_insert -> hook_node_insert($when) * hook_nodeapi(op) -> hook_node_op($when) * etc, etc, etc
Still no.
If teddy.module implements a node type then teddy_load remains. Just I am trying to find a better name to call this, because the hook part of hook_load does not really fit. As said, functor came to my mind -- functor_load. Might be a bad idea. Do not know yet. It took me five years to get a good translation in Hungarian for the word 'bully'... Reason for this change: hook is something that is called by module_invoke_all or similar. Code change: zero. This is a documentation change.
But, if event module wants to add events to teddy nodes then it currently acts on hook_nodeapi op load. It's a true hook. Currently I think we would be better off calling this hook_node_load. Reason for this change: easier to fit into hook registry/order system. But then again -- hook_nodeapi#load could also be ordered. Just feel clumsy. Code change: for more complex modules, extremely little -- they have their handlers for different ops in different functions already.
If you want to further this discussion then give me reasons why your change is better than the current, nice, orthogonal system. I am not changing the system at all, just renaming stuff a little bit.
participants (7)
-
Andre Molnar -
andrew morton -
Chris Johnson -
Fernando Silva -
Karoly Negyesi -
Larry Garfield -
Scott McLewin