Currently we always run the taxonomy_nodapi calls. All of them. On saves and updates that means a few extra database calls, even if we are 100% sure that no taxonomy terms are associated to that node.
This patch introduces a simple API function that can be used to check if your node has any vocabularies associated.
I then use this API in the hook_nodapi to return right away if this function returns FALSE.
I suspect a minor performance increase on sites that have large amount of nodes without any vocabularies associated. I expect hardly any performance increase on sites that have vocabularies with all nodes. the SQL uses a count and a LIMIT, thus limiting the overhead of that call.
However, the real reason for coming up with this patch is not performance, but ability to use taxonomy programattically.
Before the patch, taxonomy module does a taxonomy_node_delete on ANY save of ANY node. If you cannot or do not manage to insert your data after taxonomy_nodeapi, your data will always be trown away. That is useless, and annoying.
Case: content_taxonomy.module is a CCK module to insert taxonomy fields into your node on an arbitrary place. I need to do a lot of ugly tricks and hacks to avoid my terms being thrown away, when my content_taxonomy.module wants to save its stuff. First and for all, c(ontent_) comes before t(axonomy) so I need to hack the weight. Secondly, cck uses hook_update and the likes, so I need to catch stuff in a hacked in hook_nodeapi, which causes a LOT of overhead and extra code. And thirdly, on a single save, the term data will be inserted THREE times, and thrown away two times. The third one will be the one that stays in. Rather cludgy. After this patch, all I need to do, is make sure that vocs are not associated with the CCK node type. (which is preferred from usability point of view anyway).
| Comment | File | Size | Author |
|---|---|---|---|
| #23 | taxonomy.patch_4.txt | 5.2 KB | fago |
| #22 | taxonomy.patch_3.txt | 5.3 KB | fago |
| #17 | taxonomy_save.patch.txt | 3.63 KB | fago |
| #9 | 56670_taxonomy_nodeapi_check_types.patch_0.txt | 1.24 KB | Bèr Kessels |
| #5 | 56670_taxonomy_nodeapi_check_types.patch.txt | 1.24 KB | Bèr Kessels |
Comments
Comment #1
Bèr Kessels commentedgrr. project.module is borken.
Comment #2
Bèr Kessels commentedOptimised the SQL a bit. Made it PGsql compatible. Pity, because the limit speeds up the query in MySQL.
I do, however want to maintain the if() clause, simply becuase I want a function to return TRUE or FALSE, and not SOMEVALUE or NOVALUE. That latter is often done in PHP, but is rather ugly programming, IMO.
Comment #3
Tobias Maier commentederr...
this two patches are exactly the same...
Comment #4
Bèr Kessels commentednew patch
Comment #5
Bèr Kessels commentedWTF. cleared the session, trying again.
Comment #6
moshe weitzman commentedCan you clarify the Case some more. "content_taxonomy.module is a CCK module to insert taxonomy fields into your node on an arbitrary place." doesn't make sense to me yet.
Comment #7
Jaza commentedThis may be a significant performance boost for sites with very few categorised nodes, but I'm worried that it's a performance drain for sites where most (or all) nodes are categorised. For the latter group, this is just one extra query. Isn't there some way to get around executing the query every time? Perhaps a static cache for each node type, or a call to some other function that holds a cache of the data that's needed?
Comment #8
Bèr Kessels commented@moshe: Okay, let us forget about CCK and content_taxonomy for a little while.
Whenever you want to tinker with taxonomy-terms in a programmatic way, you will run into this blunt removal of ALL terms.
Whenever a node is stored or updated, ALL terms are first thrown away. Nothing you can do about that.
Another case, could be a module called auto_taxonomy.module. "This module would add certain terms to certain nodes for certain users without them interfering. when I am a user with term "technical", then all my nodes should be tagged "technical" without me interfering, without me being aable to interfere."
This case is not possible now too, because any term I add, with a module will be thrown away by taxonomy.
@Jaza, performance is not really an issue, since the _load is cashed. So this is not ran for loads anyway.
Comment #9
Bèr Kessels commentedrerolled the patch. But it still applies. Anyone?
Comment #10
drummAny non-obvious speed gain should be banchmarked.
I would rather see the extra term information needed to
$node->taxonomyso that the save/delete code is all in one place (in taxonomy module, where it belongs). Additionally, these use cases seem to break as soon as the node type in question gets a vocabulary associated with them through the usual means.Comment #11
Bèr Kessels commentedPLEASE read the thread. Speed is only a small part of why this is needed.
AGAIN:
taxonomy deletes all node-term relations on ANY node-update/-insert. It is not possible to get around this in a nice way.
This makes it impossible to add terms programatically/automatically to a node.
The fact that we win performance is only a nice side effect. Nothing more.
Comment #12
drummWhat happens if you want programmattically-controlled terms and normal terms on the same node type?
Comment #13
Bèr Kessels commentedthen taxonomy will revert to its old behaviour and remove all terms.
I have code to fix that too, but it needs three, instead of one, database calls, because it checks and deletes on a per voc basis.
Ill attach it here, but I am sure the patch we have now is a lot cleaner and smaller and does the job in most cases already.
Comment #14
nsyll commentedTHKs I had the same problem but with your path its ok now!!!
I tried to use taxonomy_node_save() but afte taxonomy_node_save() was run taxonomy_node_delete() and delete it
Comment #15
Jaza commentedreverting title
Comment #16
mh86 commented+1, that's what I've been searching for!!
Your patch works great and it would be also a performance improvement!
Comment #17
fagoI agree that this is a really important patch
However I would propose a bit different patch (attached). On node update I'm using the cached $node array and compare the new data with the old data. So there will be only queries, if there were changes. In the worst case, there will be as many queries as before. (1 delete query and one INSERT for every new term).
Programmatically changing terms:
This code will only delete terms from the database, which belongs to a vocabulary, which is maintained by the taxonomy module for this content type. So it would be possible to programmatically insert other terms from other vocabularies and they won't be touched.
It would also be possible to load custom supplied terms into $node->taxonomy and toapply any changes on this array - then the taxonomy module will do any saving for you, as it would do now.
so let's summarize the changes:
Comment #18
kweisblatt commentedI am trying to apply this patch, but I have no clue what I am doing. I don't hae shell access, so I have to do it manually right?
Comment #19
webchickNo, you can apply patches on your own computer and then upload the changed files to your server with FTP.
See instructions here: http://drupal.org/node/60108 (note there are also Mac and Windows-specific instructions on sub-pages there)
Comment #20
kweisblatt commentedthank you very much! now... figuring out the whole cygdrive thing...
thanks again!
Kris
Comment #21
kweisblatt commentedI have successfully applied the patch (thanks to webchick :). I am using this with content_taxonomy.module but when I go into contemplate to change the output, the taxonomy fields do not show. I downlaoded the latest patch (taxonomy_save.patch.txt) Should I download the other patch?
Comment #22
fagoyeah, I had a too quick look on taxonomy_node_get_terms(). It loaded all terms, so your term will be deleted as long as the code doesn't use $node->taxonomy itself. (content_taxonomy doesn't)
Now I've updated the patch, so that taxonomy_node_get_terms() only loads terms of activated vocabularies. This enables other modules to easily set terms programmatically, as long the vocabularies aren't used by the taxonomy module. Unfortunately, I had to change the function to take a $node object, instead of the nid. However this is no problem for core, because the function isn't used elsewhere, but it might in contrib modules.
Comment #23
fagosome tabs made it in my last patch. here a new one without tabs.
Comment #24
Jaza commentedHaven't tested yet, but looks good. A few suggestions:
Comment #25
fagoad 1: because of other modules, that might want to save some terms there too. What's so bad with that?
ad 2. we could use intval() instead..
ad 3. good idea
ad 4. yep. futher you can call node_load() there, because it would result in an endless loop (nodeapi load calls this!)
ad 5: Instead I can only think of removing all terms of all enabled vocabularies only. That would need a subquery - an this is not doable with our supported mysql versions.
Comment #26
kweisblatt commentedFago:
I tried your latest patch, but my fields were still not showing. I went into contemplate to see what it was calling but dodn't know what to change. One of my fields lloks like this:
Street Address
foreach ((array)$field_street_address as $item) {print $item['view']}If I even touch this code, my fields disappear.
Thanks for your work,
Kris
Comment #27
kweisblatt commentedSorry about that, here is the code:
Comment #28
fagokweisblatt, this issue is not about the cck taxonomy field.
this patch just enables modules like this to work. so please post any problems with the cck taxonmy field in its own issue.
Are there any other opinions to the IN() clause?
Ok it can become quite long, if one removes really many terms of a node. But otherwise, the old code would do a DELETE and an INSERT query for each term that is not removed.
so imho, it's better to have a bit longer query in the more unusual case of removing all terms vs having a lot of queries in the usual case of keeping all terms.
Comment #29
kweisblatt commentedSorry about that. I thought this thread was about getting modules like this to work, which mine isn't... doesn't show tax fields...
I have and will list in other areas as well for a solution.
Comment #30
kweisblatt commentedJust to make a note: I have also tried theming the node in by using node-content-my_content.tpl.php and it still doesn't work, so my assumtion that it was contemplate not reading the fields isn't the only problem I am guessing. Maybe it is a problem with the module itself.
Comment #31
webchickpatching file modules/taxonomy/taxonomy.module
Hunk #1 FAILED at 611.
Hunk #2 FAILED at 695.
Hunk #3 FAILED at 739.
Hunk #4 FAILED at 785.
Hunk #5 FAILED at 797.
Hunk #6 FAILED at 1193.
6 out of 6 hunks FAILED -- saving rejects to file modules/taxonomy/taxonomy.module.rej
Comment #32
webchickComment #33
catchComment #34
catch#412518: Convert taxonomy_node_* related code to use field API + upgrade path removes taxonomy_node_*() in favour of field storage.