I can't get either node_save() or drupal_execute() to successfully save a CCK node with content. Can anyone point me to an example of best practices doing this for Drupal 6? I saw this discussion and so it could be that there is no (best) way at the moment?
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | cck_node_save.patch | 1.08 KB | yched |
Comments
Comment #1
fractile81 commentedJust out of curiosity, are you explicitly defining all CCK-related fields in your
$nodevariable before you do thenode_save($node);, or are you leaving some of them undefined? Is your problem only with node creation, or updates as well?Comment #2
patrickharris commentedI got
node_saveworking in the end - I think I might have initially forgotten to include$node->validated = 1;. I looked at the way devel module creates cck content, and that helped me fix things up. I guessdrupal_executewould be a theoretically better way of doing it, but I haven't managed to get that working yet.Comment #3
yched commentedOK, testing with the following configuration (MySQL, non strict mode - lets check strict mode later) :
story : field_number, field_text
page : field_text
Works ok (with a few notices about non existing $node->field_texte, easily fixed).
Bigger problem is that no record is inserted in the shared table for the omitted text_field. This breaks convention, but more seriously, subsequent 'regular' (form) edit of the node will never store anything for field_text, because drupal_write_record in update mode will never insert a row that is not there...
I committed the attached patch, that takes care of filling all missing $node->field_* elements on 'insert'.
Some considerations about the 'update' case in the following comment...
Comment #4
yched commentedSo, about 'update', and ways to modify an existing node using node_save :
I think being able to do
is a nice and performance-friendly way to quickly change only the value of a given field, while leaving the others as is.
This is consistent with the way drupal_write_record works : update only the provided values, leave the rest untouched.
That's an API feature I've sometimes been missing from CCK.
Core currently behaves in different ways regarding this :
a) node_save($node) with no $node->body overwrites existing {node_revisions}.body and {node_revisions}.teaser with an empty string (see node_save)
b) node_save($node) with no $node-taxonomy keeps the existing {term_node} records in place (see taxonomy_nodeapi)
Current CCK HEAD does more or less b), with some 'undefined index' warnings. Doing a) simply means performing the check in the patch above for the 'update' case as well.
So, feedback welcome : do we want a) or b) ?
Comment #5
fractile81 commentedI think it's a great idea to not alter the data unless explicitly told to do so, so I'd vote for b). This prevents accidental data loss when trying to do a mass-update of nodes programmatically (a huge plus for developers).
Comment #6
matt_paz commented+1 on B ... very convenient for large cck nodes
Comment #7
moshe weitzman commentedyched - i think the right place to set those defaults is in nodeapi(presave). that way, the node is more properly formed for all the nodeapi operations. you can distinguish an insert since it has no nid.
i agree that B is the better approach for updates.
Comment #8
yched commentedAs per moshe's advice, moved filling omitted fields on node creation to 'presave'.
As per node_save on the 'update' side :
I added proper checking to preserve the content of omitted fields on node update (the 'b' option in comment #4).
This actually cannot be advised as a handy way to quickly update a field's content as I initially wanted to, using code like :
since you can't be certain other (non-cck) data won't get erased.
$node->files, $node->taxonomy won't be,
$node->body, book's $node->bid, forum's $node->path will be
(not to mention other contrib node additions...)
So to play safe, you have to start with a node_load.
At least this makes cck fields are resilient on this aspect, which is good anyway IMO, but quick'n fast field update will have to be something else.
Another consequence of this is if you want to programmatically *empty* a field, you have to be explicit about it :
instead of a simple
unset($node->field_text);.Which is also a good thing IMO.
Added on my TODO : put these node_save instructions and samples in CCK's handbook pages :-)
Comment #9
fractile81 commentedExcellent! One step closer to CCK in D6 for me. Does this also solve the problem with defaults as discussed here?
Comment #10
karens commentedyched, this may a place we can use the mask functions I added to the content_admin file. I would have to play around with it a bit to be sure, but they are intended to allow you to pass an array of values you want replaced in a node while preserving all other values as-is.
Comment #11
karens commentedI just committed a change that extracted some existing code out into a separate function, content_field_replace(). Pass in a $nid and an array of just the values you want to replace, and it will load the node, update the values, do a node_save, and return the updated node to you. It's in content_admin.inc.
Comment #12
yched commented@fractile81 : no, this does not add the 'default values' in node_save node creation, which is a separate issue better dealt with in in the thread you mention (and for which I personnally don't have any strong opionon for or against yet).
@Karen : Cool - is that content_field_replace() function designed to be used as an API function ? The format for the $updates param and the 'mask' stuff is still a bit beyond me (I *know* I grasped it at some point :-) ).
What would be a sample use case for a user willing to alter the value of field_foo in nid 75 ?
Comment #13
karens commentedYes, this would be an API function, I maybe should move it to content_crud.inc.
Probably not many times when you would use it by itself, the use case would probably be within a batch function where you want to do something like query for all nodes that have 'X' in field 'foo' and replace it with 'Y'. Then you create a batch to find all the nodes that have that and run them through this function to change the values in a way that will trigger all the right hooks and update the values.
Comment #14
karens commentedAnother use of this would be here http://drupal.org/node/207593. I hadn't thought of this, but we could work this into a solution for when fields are added to a content type that already has nodes created to set fields on any existing nodes to some default value rather than leave them empty until they are manually updated.
Comment #15
Anonymous (not verified) commentedAutomatically closed -- issue fixed for two weeks with no activity.