3

How can I save multiple values in a multi-value field collection using EntityMetadataWrapper ?

Here's some of my code

$field_collection = entity_create('field_collection_item', array('field_name' => 'MY_FIELD_COLLECTION'));
$field_collection->setHostEntity('commerce_line_item', $line_item);
$wrapper = entity_metadata_wrapper('field_collection_item', $field_collection);

for($delta=0; $delta<$max_delta; $delta++) {
  //MISSING something like $wrapper->setDelta($delta);
  $wrapper->field_example->set($new_value);  
  $wrapper->other_field_example->set($new_value); 
  $wrapper->save(); 

}

$field_collection->save();

I'm fighting with the field delta : I can't use $wrapper->field_example[$delta]->set($new_value) because the wrapper itself is the multi-value field, not its children fields.

So I need to find a way to perform something like

$wrapper[$delta]->field_example->set($new_value); 

But this returns "Fatal error: Cannot use object of type EntityDrupalWrapper as array".

Summary : where can I set the delta of the wrapper in the loop ?

1
  • 1
    You can't (not with setHostEntity(), anyway). That function just adds to the existing data, it doesn't offer a way to set the delta. The simplest way would be to reproduce the parts of that function you need and set the delta manually in your own function
    – Clive
    Aug 26, 2014 at 14:51

2 Answers 2

5

I've found this example in one of the bug reports on d.o, hopefully it will clear things up a bit:

// Load the entity and wrap it.
$entity = entity_load_single('my_entity', $entity_id);
$wrapper = entity_metadata_wrapper('my_entity', $entity);
// Create new field collection items.
$collections = array();
// This is a contrived example so assume $things contains some data that might be set on the collections.
foreach ($things as $thing) {
  $fc = entity_create('field_collection_item', array('field_name' => 'field_example_collections'));
  $fc->setHostEntity('my_entity', $entity, $entity->language, FALSE);
  // Skip saving the host entity since the order in which we are creating the items is not the order we want them saved.
  $fc->save(TRUE);
  $collections[] = $fc;
}
// Set the field collection items via the wrapper.
$wrapper->field_example_collections->set($collections);
// Save the entity.
$wrapper->save();

Just as @Clive commented, you need to first load the host entity that this field collection field is attached to (I'm assuming it's a commerce_line_item?), then loop through your data and create field collection entities. Then after you've done assigning values, collect them all in an array and set the array as the new value for the host entity's field collection field.

4
  • 1
    That's a good way to do it - you can control the delta by setting the order of $things to something appropriate, it'll have the same effect. I think you probably want to change it to $fc->setHostEntity('my_entity', $entity, LANGUAGE_NONE, FALSE);, just to save duplicated effort to create the 'link'. It's minimal though
    – Clive
    Aug 26, 2014 at 15:03
  • 1
    Powerful code example! Just a point : I had to change $entity->save() to $wrapper->save(). Seems to be all right now. Tks again !
    – Kojo
    Aug 26, 2014 at 16:58
  • Last, I was wondering what @Clive meant by change to $fc->setHostEntity('my_entity', $entity, LANGUAGE_NONE, FALSE);, just to save duplicated effort to create the 'link'?
    – Kojo
    Aug 26, 2014 at 17:18
  • 2
    @Kojo It's minor, it just stops setHostEntity from adding the link to the field collection onto the host node explicitly, since you're adding it yourself with $wrapper->field_example_collections->set($collections);. Micro-optimising probably
    – Clive
    Aug 26, 2014 at 17:28
1

To save multi-value field, you need to wrap the values in array(), e.g.

$wrapper->field_example->set(array($new_value1, $new_value2, $new_value3));

or append as this would be an array:

$wrapper->field_example[] = $next_value;

Here is some more complete example:

try {
  $line_item = entity_metadata_wrapper('commerce_line_item', $entity);
  // Create the collection entity, set field values and set it's "host".
  $field_collection_item = entity_create('field_collection_item', array('field_name' => 'MY_FIELD_COLLECTION'));
  $field_collection_item->setHostEntity('commerce_line_item', $line_item->value());
  $collections[$pname] = entity_metadata_wrapper('field_collection_item', $field_collection_item);
  $collections[$pname]->field_example = array($new_value1, $new_value2);
  $collections[$pname]->other_field_example[] = $new_value;
  $collections[$pname]->other_field_example[] = $other_value;
  $line_item->save();
} catch (Exception $e) {
  drupal_set_message(t('Error message: @error.',
        array('@error' => $e->getMessage())), 'error');
  watchdog_exception('MYMODULE', $e);
}
0

Your Answer

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

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