2

I am trying to create event type nodes in Drupal 7, using data from an external database. It's reading correctly, and creating a node almost perfectly. But, it doesn't seem to save the "body" part of the node.

db_set_active('default');

foreach ($results as $record) { // Results gained from an ext DB
  echo 'Creating event: ' . $record->name;

  $node = new stdClass();
  $node->type = 'event';
  node_object_prepare($node);

  $node->title    = $record->name;
  $node->language = "en";;

  $node->body[$node->language][0]['value']   = $record->bodytext;  /* This line ?? */

  $path = 'content/programmatically_created_node_' . date('YmdHis');
  $node->path = array('alias' => $path);

  node_save($node);  
}

This is early stages, and I have a number of fields to put into events type nodes, including some custom fields.

I am unsure how to map the fields in the external database to node fields. The line above might be completely wrong at this stage, but it's gone though many many failing iterations.

As requested: DPM output of the node (after save)

... (Object) stdClass
type (String, 5 characters ) event
uid (String, 2 characters ) 10
status (Integer) 1
promote (Integer) 0
sticky (Integer) 0
created (Integer) 1357635638
revision (Boolean) FALSE
comment (String, 1 characters ) 1
language (String, 3 characters ) und
menu (Array, 13 elements)
title (String, 42 characters ) Starter Course
field_pakp_p1_id (String, 36 characters ) 78ee9b05-9225-fb5b-9bbb-508eada6ba81
body (Array, 1 element)
  en (Array, 1 element)
    0 (Array, 3 elements)
      value (String, 19 characters ) This is a body text
      summary (String, 19 characters ) Here goes a summary
      format (String, 13 characters ) filtered_html
path (Array, 1 element)
validated (Boolean) TRUE
changed (Integer) 1357635638
timestamp (Integer) 1357635638
publish_on (Integer) 0
unpublish_on (Integer) 0
log (String, 0 characters )
nid (String, 3 characters ) 423
tnid (Integer) 0
translate (Integer) 0
vid (String, 3 characters ) 423
field_event_status (Array, 1 element)
xmlsitemap (Array, 15 elements)

...

I also tried using the drupal_form_submit method..

foreach ($results as $record) { // Results gained from an ext DB
    echo 'Creating event: ' . $record->name;
    $node = (object) array(
      'type' => 'event',
      'language' => LANGUAGE_NONE
    );
    node_object_prepare($node);

    $form_state = array();  
    $form_state['values']['language'] = "en";
    $form_state['values']['title'] = $record->name;  
    $form_state['values']['description']['value'] = "description....";
    $form_state['values']['body']['value'] = "body....";
    $form_state['values']['body']['format'] = filter_default_format();
    $form_state['values']['body']['LANGUAGE'] = "en";
    $form_state['values']['name'] = $user->name;  
    $form_state['values']['op'] = t('Save');

    drupal_form_submit("{$node->type}_node_form", $form_state, $node);

}

But again, try as I might, using this method I could not get the "body" to be saved. (I know there is some junk in this code, it's my experimentation.)

Questions.

  1. Which is the best method to use for my application. node_save or drupal_form_submit
  2. For the correct method, which is the best way to store the body text?
  3. How do I know what are valid $form_state array keys, or $node elements, so I can find the correct place for further field mapping?
9
  • This is for Drupal 7.
    – Rob
    Commented Jan 2, 2013 at 15:52
  • The body field is localized. So should this work? $node->body[$node->language][0]['value'] = 'This is a body text';
    – Rob
    Commented Jan 2, 2013 at 15:53
  • yes in theory that should work, I've done the same thing literally hundreds of times and I can't remember a single failure. There's no chance you've removed the body field from that content type is there?
    – Clive
    Commented Jan 2, 2013 at 16:26
  • I've just checked, and it's still there. How frustrating! I assume $node->language = "en"; is correct? "en" taken from node.language in DB.
    – Rob
    Commented Jan 2, 2013 at 16:42
  • that might be the key actually, I've added a wild stab in the dark as an answer
    – Clive
    Commented Jan 2, 2013 at 16:47

2 Answers 2

1

If your site is multi-lingual then 'en' would contain the English-language translations of your original node (I think that's right).

Going out on a limb, I'd say you're not running a multilingual site and instead want to use the LANGUAGE_NONE constant, e.g.

$node->language = LANGUAGE_NONE;

If your site isn't multi-lingual, using 'en' would probably explain why you're not seeing the body value saved. It might even be there in the database, but because the field system is looking for fields with a LANGUAGE_NONE when it's attaching data to a language-neutral node, nothing gets found.

That might be a load of nonsense though ;)

6
  • No it's not nonsense, I think you're right! Using LANGUAGE_NONE shows the body text. The problem is now, I'm using the Internationalization module, which doesn't display a Translate tab, with $node->language set to LANGUAGE_NONE; Only when set to "en"
    – Rob
    Commented Jan 2, 2013 at 17:07
  • Ah so this node is a translation of another? 'en' is probably correct then, but I think you also need to set $node->tnid. That column in the node table is defined as: "The translation set id for this node, which equals the node id of the source post in each set.". Basically the $nid of the original node.
    – Clive
    Commented Jan 2, 2013 at 17:20
  • The site is English/Welsh. I'm importing a new event in English which will be manually translated to Welsh once successfully imported.
    – Rob
    Commented Jan 2, 2013 at 17:25
  • Ah ok. I'm afraid I don't have masses of experience with the i18n module so I'm out of ideas off the top of my head...now that you've got the body field saving it's probably worth opening a new question to ask why the Translate tab is missing, referring back to this one for context. This question has a lot of comments and a couple of answers which might put people off from reading through it, so a new question would probably work in your favour
    – Clive
    Commented Jan 2, 2013 at 17:33
  • Oh, and make sure you don't try to put the full name for Llanfairpwll station in anywhere...no database in the world would be able to handle that ;)
    – Clive
    Commented Jan 2, 2013 at 17:35
0

Drupal 6 or 7?

I would use node_save(). Try using dpm() to inspect the structure of the specific node type. Maybe post it here?

I have just done something similar:

/**
 * Import upload form.
 */
function mymodule_import_form($form, &$form_state) {
  $form = array();

  $form['#attributes'] = array('enctype' => "multipart/form-data");

  $form['import_file'] = array(
    '#type' => 'file',
    '#title' => t('Import file'),
    '#description' => t('CSV file containing xx data.'),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Import'),
  );

  return $form;
}

/**
 * Import submit callback.
 */
function mymodule_import_form_submit($form, &$form_state) {
  $validators = array(
    'file_validate_extensions' => array('csv'),
  );

  if ($file = file_save_upload('import_file', $validators)) {
    $fp = fopen($file->uri, 'r');

    $count = 0;
    while ($row = fgetcsv($fp)) {

      // If event already exists, don't do anything.
      $result = db_query(
        "SELECT nid FROM node WHERE type = 'event' AND created = :created AND title = :title",
        array(':created' => $row[3], ':title' => $row[7])
      );
      $nid = $result->fetchField();
      if ($nid) {
        drupal_set_message('Already exists: ' . l($row[7], 'node/' . $nid . '/edit'));
        continue;
      }

      // Create event node
      $node = new stdClass();
      $node->type = 'event';
      node_object_prepare($node);
      $node->uid = 0;
      $node->created = $row[3];
      $node->title = $row[7];
      $node->language = 'da';
      $node->body['und'][0]['value'] = $row[10];
      $node->field_company_name['und'][0]['value'] = $row[8];
      $node->field_email['und'][0]['value'] = $row[10];
      $node->field_phone['und'][0]['value'] = $row[9];
      node_save($node);

      drupal_set_message('Created: ' . l($node->title, 'node/' . $node->nid . '/edit'));

      $count++;
      if ($count > 50) break;
    }
  }
}
6
  • If the body field is not localized, it should be set using $node->body[0]['value'] If you mean that to relate to Drupal 7 I'm afraid that's incorrect, all fields are 'localised' in Drupal 7 in that respect. LANGUAGE_NONE ('und') is used to denote an undetermined language, if you use $node->body[0]['value'] without a language key in D7 it definitely won't work
    – Clive
    Commented Jan 2, 2013 at 15:48
  • You are right. My mistake! Commented Jan 2, 2013 at 15:56
  • @martin: Thanks for the code. It's useful to see I'm on the right track. I can't see where you set the body part. :-)
    – Rob
    Commented Jan 2, 2013 at 16:07
  • dpm of node, now included in first post.
    – Rob
    Commented Jan 2, 2013 at 16:13
  • The dpm looks strange, without title and body. Have you done it with an existing node? Maybe using hook_form_alter(&$form, &$form_state, $form_id) to dpm($form['#node']) Commented Jan 2, 2013 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.