I have 2 fields (field_a nodereference and field_b text) in a multigroup (group_test). My multigroup can accept an unlimited # of values.

When I run the following test code only the first fieldgroup entry is saved (field_a = nid 391, field_b = test 1), the second entry is completely ignored:

require("modules/node/node.pages.inc");
$node = node_load(392);
$form_state['values'] = (array)$node;
$form_state['values']['field_a'][0]['nid'] = '391';
$form_state['values']['field_b'][0]['value'] = 'test 1';
$form_state['values']['field_a'][1]['nid'] = '391';
$form_state['values']['field_b'][1]['value'] = 'test 2';
$form_state['values']['op'] = 'Save';
drupal_execute('mynodetype_node_form',$form_state, $node);

A little investigation seems to indicate that the problem occurs somehow when drupal_prepare_form() runs (inside of drupal_execute()). The form prepared by drupal_prepare_form generates a group_test array with only as many delta entries as the node had before being edited.

You may wonder why use drupal_execute? The above code is just a simplified version of what the Services module uses to save nodes so I really need it to work. For reference, below is an exact copy of the relevant code from the Services module :

function node_service_save($edit) {
  // Load the required includes for drupal_execute
  module_load_include('inc', 'node', 'node.pages');
  $nid = NULL;
  $edit = (array) $edit;
  if ($edit['nid']) {
    $node = node_load($edit['nid']);
    if ($node->nid) {
      // Setup form_state.
      $form_state = array();
      $form_state['values'] = (array) $edit;
      $form_state['values']['op'] = t('Save');

      // Later on in the chain node_form seems to expect a copy of
      // the old node object.
      $form_state['node'] = (array) $node;

      $ret = drupal_execute($node->type .'_node_form', $form_state, (object)$node);

      // If the node is immediately reloaded after update, it will
      // load the OLD cached version.
      node_load(0, NULL, TRUE);

      // Set $nid, so it can be returned
      $nid = $node->nid;
    }
    else {
      return services_error(t('Node not found'), 401);
    }
  }
  else {
    // If the submitted node has no author (for instance if it was
    // created programmatically by hand) then set the currently logged 
    // in user as the author. 
    if (!$edit->uid) {
      global $user;
      $edit->uid = $user->uid;
    }

    // Setup form_state
    $form_state = array();
    $form_state['values'] = (array) $edit;
    $form_state['values']['op'] = t('Save');

    $ret = drupal_execute($edit['type'] .'_node_form', $form_state, (object)$edit);

    // Fetch $nid out of $form_state
    $nid = $form_state['nid'];
  }
  if ($errors = form_get_errors()) {
    return services_error(implode("\n", $errors), 401);
  }
  return $nid;
}

Comments

azinck’s picture

This might end up being a problem with the Services module. Please read the solution I posted here: #727108: node_service_save incompatibility with CCK multigroup

Anonymous’s picture

Hey azinck,

I'm having the exact same problem with adding multiple values programmatically into a multigroup field. But i'm not using the Services module at all. So I guess it's not an issue of the Service module.

Did you come up with a solution in the meantime? I tried to find the problem for some hours, with no success.

With normal CCK Fields i'm having no problems.

thanks in advance

karens’s picture

Status: Active » Fixed

You cannot use drupal_execute more than once in a single session, there is a core bug that misses validation processing if you do that. If you want to create multiple nodes in a single pass you need to use node_save().

There is a very very old issue about this on core, it still hasn't been fixed. But this is not a CCK bug.

azinck’s picture

Hi jazzati,

Best of luck finding a solution. I did solve my problem and linked to the solution in comment #1. You could try emulating what Services does and add a copy of your new (edited) node, in array format, to $form_state['node']

so something like:

<?php
$node = node_load($nid);

$form_state['values'] = /*your new node data as array*/;

$form_state['node'] = $form_state['values'];//this is probably the different part

$form_state['values']['op'] = t('Save');

drupal_execute(your_node_form_string, $form_state, $node);
?>

Here's another reference to pore over: #293663: Programmatically creating nodes with drupal_execute

Anonymous’s picture

@azinck

Thanks for your quick answer. Your solution actually worked!! I did follow the instructions in #293663: Programmatically creating nodes with drupal_execute and came out with the following:

<?php
public function saveNode($type,$values = array()){
    if(!empty($type)) {
      global $user;
      
      // import node functions
      module_load_include('inc', 'node', 'node.pages');
      
      // create basic node structure
      $node = array(
        'uid' => (string) $user->uid,
        'name' => (string) $user->name,
        'type' => $type,
        'language' => $language,
        'body' => NULL,
        'title' => NULL,
        'format' => NULL,
        'status' => true,
        'promote' => false,
        'sticky' => false,
        'created' => time(),
        'revision' => false,
        'comment' => '0',
      );
      
      $node = (object) $node;
      
      // set form state values (content)
      $form_state['values'] = $values;
      
      $form_state['values']['name'] = $node->name;
      $form_state['values']['op'] = t('Save');
      
      // drupal needs that, why? -> drupal.org/node/293663
      // drupal.org/node/726868
      $form_state['node'] = (array) $node;
      
      // run drupal_execute to follow the normal drupal process to save the node
      drupal_execute($type . '_node_form', $form_state, $node);
      
      if(isset($form_state['nid'])){
        return $form_state['nid'];
      }
    }
    return false;
  }
?>

now, as you suggested, i made the following change:

<?php

// old: $form_state['node'] = (array) $node;
$form_state['node'] = $form_state['values'];

?>

this works now perfectly with creating one node. But as KarenS said in comment #3, there seems to be a problem when creating multiple nodes with drupal_execute(). I call my nodeSave-Function in a recursive way so it is called several times to create a node together with all the nodes it references.

I'm going to try this with node_save to see if it does work.

thanks for your help.

Anonymous’s picture

the solution with "node_save" actually solved all problems. it's more a workaround rather than a fix.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

dunx’s picture

Okay, I've spent too long trying to work out how to create 1000s of node that includes node references and eventually came across the answer here:

http://drupal.org/node/178506#comment-895418

Basically...

$form_state['values']['field_mydropdown']['value'] = 3; // a select (dropdown, where 3 is the "option" value saved to the db
$form_state['values']['field_myuserref'][0]['uid']['uid'] = 'someusername'; // a user reference example
$form_state['values']['field_mycheckbox']['value'] = 1; // a checkbox example
$form_state['values']['field_mynoderef'][0]['nid']['nid'] = '[nid:9]'; // a node reference example. In this case, 9 is referring to node 9
$form_state['values']['field_mynoderef'][1]['nid']['nid'] = '[nid:15]'; //etc...

Remember, you don't want to do this for any blank value, so no '[nid:]' values passed in.

I wanted to use drupal_execute as this is actually a migration script rather than a module. I didn't want to use node_save. As there's the caching issue with drupal_execute's validation, then you may also need the solution detailed here:

http://drupal.org/node/260934

johannesdr’s picture

Hi, did anyone else have this problem.
Because adding

$form_state['node'] = (array) $node

didn't work for me.
I am also using the services module and when a node has a multigroup only the first field in this group is added to the node.