[development] hook_nodeapi()
Scott McLewin
drupal at mclewin.com
Wed Jan 3 17:46:48 UTC 2007
Fernando,
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.
Scott
www.folkjam.org
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