The Entity API provides classes and methods / functions that make CRUD for entities much, much easier and less prone to errors and bugs.

The first example shows the creation of a field collection entity that will be attached to a node that has a field collection field already defined for it through the Manage Fields tab of the node type creation / modification UI. The example shows creating the field collection entity (using the entity_create function of the Entity API, attaching it to a node, and using the Entity API then to set values of fields within the field collection.

<?php
// Code that would be here but is omitted loads a node called $my_node
// Nodes of the type that is $my_node have a field of the field collection
// type called field_text_files, which in turn is defined as having two
// fields called field_source_txt_filename and field_source_txt_content

// Begin by using the entity_create function to create a new entity of
// type field_collection_item. The second parameter to the function
// provides "an array of values to set, keyed by property name".
// In our example, the field in my_node that holds the field collection is 
// the field_text_files field.
$fc_item = entity_create('field_collection_item', array('field_name' => 'field_text_files'));

// Now connect / attach the new field collection item to a node that
// we loaded earlier in our code and stored in the $my_node variable.
// The setHostEntity function is provided by the Field Collection module.
$fc_item->setHostEntity('node', $my_node);

// Now, we use the entity_metadata_wrapper function from the Entity
// API to "wrap" the field collection entity in a class that simplifies
// working with the entity. 
$fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc_item);

// If we weren't using the entity_metadata_wrapper function, we'd have to 
// access and set field values within the field collection entity using this code:
//
// $fc_item->field_source_txt_filename[LANGUAGE_NONE][0]['value'] = $stat['name'];
//
// This code is obviously less readable and also not as friendly to translations
// perhaps.
 
// Now, we just put a string value into a field on the field collection entity
// The set() method appears to be the preferred way to set values on 
// entity fields, as opposed doing an assignment of data to the value() property
$fc_wrapper->field_source_txt_filename->set('my_text_file.txt');

// Put another string value into another field on the field collection entity
$txt_file_content = "A whole bunch of content.";
$fc_wrapper->field_source_txt_content->set($txt_file_content);

// Now save the node
node_save($my_node);

// As an alternative to node_save, you could use
// field_attach_update('node', $my_node);
// This function from the Field API saves field data for an existing entity but
// doesn't save the entity itself. So, in the code above, the field_text_files field
// that belongs to $my_node would get saved, but the $my_node node would
// not get saved.
?>

References for functions and methods used in the example above:

This example shows updating (loading/editing/saving) an existing field collection in an Entity Wrapper provided by the Entity API module.

// Load the node by NID
$raw_node = node_load($nid);
// Wrap it with Entity API
$node = entity_metadata_wrapper('node', $raw_node);
// Get the first item from the muli-value field collection
$raw_collection = $node->field_collection->value();
// Wrap it with Entity API
$collection = entity_metadata_wrapper('field_collection_item', $raw_collection);
//dsm the old value
dsm($collection->field_example->value());
// Set a new value on the field_example textfield.
$collection->field_example = 'New value';
// Save the changes to the entity
$collection->save();

Comments

sumaiyajaved’s picture

I was getting this error "field_collection Cannot use object of type EntityDrupalWrapper as array"

I just changed the line
$raw_collection = $node->field_personal_information[0]->value();
to this
$raw_collection = $node->field_personal_information->value();

and now it is working fine.

thank you

Regards,

Sumaiya Javed
Web Developer
www.sumaiyajaved.com
www.phpjavascript.com

Dru18’s picture

When I update/delete a fc, It returns "Illegal offset type in unset" error in .../field_collection/field_collection.module, line 1013. Any idea?

cmarcera’s picture

What would be the best way to add multiple field collections at once?

I could iterate through those 8 lines repeatedly, but multiple node_save() commands didn't seem very efficient.

s13’s picture

@cmarcera,
I have no idea if my case is similar to yours, but I also needed to insert multiple field collections while creating new users programmatically on a Drupal 7 site.

I have a category Jobs added to users like Drupal 6 Profile categories(using module user_categories). There is a field collection field_joining under category Jobs with fields, field_joining_job, field_joining_date and field_resigning_date. A user can enter many values for this field collection. I have to do the following to insert more than one set of values:

               
                $edit['name'] = $edit['mail'];		
		$edit['pass'] =  'password';
		$edit['status'] =  1;
		//$edit['access'] =  REQUEST_TIME;
		$edit['roles'] =  array(); // No other roles than Authenticated

                $newuser = user_save(NULL, $edit);

                $user_category = new stdClass();
		$user_category->category = 'Jobs';
		$user_category->uid = $newuser->uid;          

Repeat the following code as many times as many values you need to insert.

		  // Create the collection entity and set it's "host".
		  $collection = entity_create('field_collection_item', array('field_name' => 'field_joining'));
		  $collection->setHostEntity('user_category', $user_category);
	
		  // Now define the collection parameters.
		  $cwrapper = entity_metadata_wrapper('field_collection_item', $collection);
		  if(isset($joining_job) && trim($joining_job)!=''){
		    $cwrapper->field_joining_job->set($joining_job); 
		  }
		  if(isset($joining_date) && trim($joining_date)!=''){
		    list($m,$d,$y) = explode("/",$joining_date);
		    $cwrapper->field_joining_date->set(strtotime($y.'-'.$m.'-'.$d .' 00:00:00')); 
		  }
                  if(isset($resigning_date) && trim($resigning_date)!=''){
		    list($m,$d,$y) = explode("/",$resigning_date);
		    $cwrapper->field_resigning_date->set(strtotime($y.'-'.$m.'-'.$d .' 00:00:00')); 
		  }
		  
		  $cwrapper->save(TRUE);

Hope it helps..