Programmatically Create, Insert, and Update CCK Nodes
on
Programmatically Create, Insert, and Update CCK Nodes
I am working on a new module (uscongress module). The basics of the module is that it imports data and makes it available via CCK nodes. The dataset is a common one (U.S. Congressional Bills) that many people might want to develop applications around. I decided to try to implement the data using CCK rather than as a custom data model, thinking that CCK nodes would be more flexible to application developers.
It has posed three important development hurdles.
Create Content Types
Export the content type from CCK (admin/content/types/export), save the array in an array, and then pass it to the function below. This improves upon the previously known techniques, in that the exported CCK types no longer need to be escaped.
function _install_create_content($content) {
$type = $content['type']['type'];
global $_install_macro;
$_install_macro[$type] = $content;
include_once './'. drupal_get_path('module', 'node') .'/content_types.inc';
include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc');
$macro = 'global $_install_macro; $content = $_install_macro['. $type .'];';
drupal_execute('content_copy_import_form',
array('type_name' => '<create>', 'macro' => $macro));
content_clear_type_cache();
}
</pre>
Inserting Nodes
See Quick and Dirty CCK Imports.
The correct way to insert and update nodes is with drupal_execute, rather than node_submit because it handles form alter and form validation.
Debug the node edit form by placing a print_r($node) in node.module at the top of node_submit, edit node/add/yourtype, submit the form, remove your debugging print_r, then create your values array to match these values.
$node->type = 'yourtype';
$values = array();
$values[...] = ...;
drupal_execute('yourtype_node_form', $values, $node);
$errors = form_get_errors();
if (count($errors)) {
// do something ...
}
Updating Nodes
When updating nodes, you'll need to load the node using node_load, but then before updating the values, the default values need to be pre-populated from the node.
$node = node_load($nid);
_content_widget_invoke('prepare form values', $node);
SQL
Don't assume the database tables and columns are, even if they are created in by your module. As CCK fields, the administrator can add them to other tables, in which case, the single instance fields become multiple instance fields, and they database references change.
Always use content_database_info to get the database info. For example:
$field1 = content_database_info(content_fields('yourfield1', 'yourtable'));
$table1 = $field1['table'];
$column1 = $field1['columns']['value']['column'];
$field2 = content_database_info(content_fields('yourfield2', 'yourtable'));
$table2 = $field2['table'];
$column2 = $field2['columns']['value']['column'];
if ($table1 == $table2) {
$sql = "SELECT n.*, t1.$column1, t1.$column2 FROM {node} n ";
$sql .= " INNER JOIN {$table1} t1 ON t1.nid = n.nid AND t1.vid = n.vid";
}
else {
$sql = "SELECT n.*, t1.$column1, t2.$column2 FROM {node} n ";
$sql .= " INNER JOIN {$table1} t1 ON t1.nid = n.nid AND t1.vid = n.vid";
$sql .= " INNER JOIN {$table2} t2 ON t2.nid = n.nid AND t2.vid = n.vid";
}
$sql .= " WHERE n.nid = %d";
$sql .= " INNER JOIN {$table1} t1 ON t1.nid = n.nid AND t1.vid = n.vid";{} around the variable, so you won't get table prefixing. This could change to
$sql .= " INNER JOIN {". $table1 ."} t1 ON t1.nid = n.nid AND t1.vid = n.vid";$reg_nid = '21814';
if ($node = node_load($reg_nid, NULL, TRUE)) {
$node->log = t('Updated by sims_import.module on '. date('g:i:s a'));
_content_widget_invoke('prepare form values', $node);
$values = (array) $node;
// value of cck field that I want to update
$values['field_reg_status'][0]['value'] = 'DROP';
drupal_execute('registration_node_form', $values, $node);
$errors = form_get_errors();
if (count($errors)) {
return "Errors occurred while changing registration.";
}
}<?php
$node->type = 'album';
$node->field_cover_image = array(
array(
'fid' => 'upload',
'title' => (string)$xml->album->album_title,
'filename' => $img_file->filename,
'filepath' => $img_file->filepath,
'filesize' => $img_file->filesize,
),
);
$values = array();
$values['field_album_upc'][0]['value'] = (string)$xml->album->album_upc;
$values['title'] = (string)$xml->album->album_title;
$values[...] = ...; // rest of CCK fields created here
drupal_execute('album_node_form', $values, $node);
?><?php
function _uscongress_install_create_content($content, $type_name = '<create>') {
$type = $content['type']['type'];
global $_uscongress_install_macro;
$_uscongress_install_macro[$type] = $content;
include_once drupal_get_path('module', 'node') .'/content_types.inc';
include_once drupal_get_path('module', 'content') .'/content_admin.inc';
$macro = 'global $_uscongress_install_macro; $content = $_uscongress_install_macro['. $type .'];';
drupal_execute('content_copy_import_form', array('type_name' => $type_name, 'macro' => $macro));
content_clear_type_cache();
}
?>Fatal error: Only variables can be passed by reference in /Sites/d6trunk/modules/foo/foo.install on line 98/**
* Helper function to import a CCK content type definition from a text file.
*
* @param $cck_definition_file
* The full path to the file containing the CCK definition.
*/
function _create_content_type($cck_definition_file) {
include_once('./'. drupal_get_path('module', 'node') .'/content_types.inc');
include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc');
$values = array();
$values['type_name'] = '<create>';
$values['macro'] = file_get_contents($cck_definition_file);
drupal_execute("content_copy_import_form", $values);
}













function _install_create_content($content, $type_name = '<create>') {$type = $content['type']['type'];
global $_install_macro;
$_install_macro[$type] = $content;
include_once './'. drupal_get_path('module', 'node') .'/content_types.inc';
include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc');
$macro = 'global $_install_macro; $content = $_install_macro['. $type .'];';
$form_state = array('values' => array('type_name' => $type_name, 'macro' => $macro));
drupal_execute('content_copy_import_form', $form_state);
content_clear_type_cache();
}