[development] hook_nodeapi()

Scott McLewin drupal at mclewin.com
Wed Jan 3 17:46:48 UTC 2007


It is, as you suggested about halfway down, about guaranteeing the 
calling order.  If I write a module that defines a new node type, I want 
to guarantee that my loading code is called before any other module 
attempts to modify the node through hook_nodeapi().  This is where 
hook_load()/hook_save() et. al. are necessary.

For the purpose of being a module author, hook_nodeapi() is called on 
every active module in an arbitrary order.  While it is the system 
weights order internally, as a module author you cannot guarantee that 
your module will be run at a given weight relative to other modules that 
are using hook_nodeapi() to modify it, even with a fresh new install 
system.  The more modules that are active on a site, the more load-order 
challenges you may have.  I only rely on system weight for modules on 
sites where I've written a module that will only run on that site and 
nowhere else.

hook_load() is a very simple (and clean) solution to this ordering 
challenge.  For a simple deployment where a node-defining module is not 
augmented by any other module I can see where one could argue that 
hook_load() and hook_nodeapi(op=load) are identical.  When you get into 
a site with more than a handful of custom/contributed node types they 
become different in a crucial and subtle way.


Fernando Silva wrote:
> I do not quite understand that. Let's assume the "example.module" that
> creates a new node type.
> I'll must use the "example_load()" hook to load some data from an 
> extra table:
> function example_load($node) {
>  $additions = db_fetch_object(db_query('SELECT * FROM {mytable} WHERE
> nid = %s', $node->nid));
>  return $additions;
> }
> But then, if I use "example_nodeapi()" instead the code should be
> something like this:
> function example_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
>  switch ($op) {
>    case 'load':
>      $additions = db_fetch_object(db_query('SELECT * FROM {mytable}
> WHERE nid = %s', $node->nid));
>      return $additions;
>  }
> }
> It's the exact same code, but we also need to have sure that both API
> functions run at exactly the places. If we go to the node.module, in
> the node_load() function we have at the lines 525 and 531 we have
> *exactly* the same code to invoke both APIs.
> This means, that when the nodeapi() is invoked with other $op it is
> already loaded. Or else, you can be saying that if another module (eg.
> "intercept.module") wants to intercept the 'load', the node will not
> be 'loaded':
> * example.module implements a new node type
> * node_load() will load example.module new node type by doing hook_load()
> * intercept.module will do something to the example.module node by
> using nodeapi()
> Is this a correct conclusion, or I am missing something?
> This seems to me a bit strange, because in this case the only reason
> we have hook_load() and hook_nodeapi('load') is because we can't get a
> way to enforce the correct 'loading' order with hook_nodeapi.
> Or can we?! If with the new "install system" we have module
> dependencies, why can't we have a way to give priorities to those
> dependencies...
> As a side note, this behaviour is implemented since Drupal 4.6
> Thanks,
>  Fernando Silva
> On 1/3/07, Gerhard Killesreiter <gerhard at killesreiter.de> wrote:
>> Fernando Silva wrote:
>> > node_load()
>> > if ($extra = node_invoke($node, 'load')) {
>> > foreach ($extra as $key => $value) {$node->$key = $value;}}
>> > if ($extra = node_invoke_nodeapi($node, 'load')) {
>> > foreach ($extra as $key => $value) {$node->$key = $value;}}
>> >
>> > node_save()
>> > node_invoke($node, 'insert');
>> > node_invoke_nodeapi($node, 'insert');
>> > node_invoke($node, 'update');
>> > node_invoke_nodeapi($node, 'update');
>> >
>> > node_delete()
>> > node_invoke($node, 'delete');
>> > node_invoke_nodeapi($node, 'delete');
>> >
>> > The conclusion is that the "nodeapi" is the way to do things, and that
>> > the other way was just keeped as unnecessary compatibility, and should
>> > be quickly deprecated.
>> I don't think that this is a valid conclusion. /If/ you create your own
>> node type and it has an extra table you should use the basic hooks.
>> Because then your node will already be fully populated once it gets into
>> nodeapi and other modules can act on the full node.
>> Cheers,
>>         Gerhard

More information about the development mailing list