Tell me more ×
Drupal Answers is a question and answer site for Drupal developers and administrators. It's 100% free, no registration required.

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?
share|improve this question
 
This is for Drupal 7. –  Rob Jan 2 at 15:52
 
The body field is localized. So should this work? $node->body[$node->language][0]['value'] = 'This is a body text'; –  Rob Jan 2 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 Jan 2 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 Jan 2 at 16:42
 
that might be the key actually, I've added a wild stab in the dark as an answer –  Clive Jan 2 at 16:47
show 4 more comments

2 Answers

up vote 1 down vote accepted

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 ;)

share|improve this answer
 
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 Jan 2 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 Jan 2 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 Jan 2 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 Jan 2 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 Jan 2 at 17:35
show 1 more comment

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;
    }
  }
}
share|improve this answer
 
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 Jan 2 at 15:48
 
You are right. My mistake! –  Martin Poulsen Jan 2 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 Jan 2 at 16:07
 
@clive: Thanks for the clarification. –  Rob Jan 2 at 16:09
 
dpm of node, now included in first post. –  Rob Jan 2 at 16:13
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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