Drupal: Field collections

Professional Article
October 12, 2012

This article will cover Field Collection module as a concept overall and we'll also look into some programming details.

Field Collection module a "field collection" field. This field is actually represented by an entity of type "field collection item". And as any entity, it's fieldable, so one can attach as many fields as he wants to a bundle of a field collection item. It can also store lots of values, just like any other field. The advantage of Field Collection is that it also embeds the editing form of the field collection item's fields

One can view and edit field collections separately.

When you define field collections, you can go anytime to this path, and editing them: /admin/structure/field-collections

And here's an example of a Field Collection and why we would use it: lets suppose we need a field that has multiple inputs, for instance we have an Author as a content-type, and we have a Work field. In that field we want to store multiple values of Book | Year | Number of Pages | Publisher. Well not it's possible, more than that, we can easily drag-and-drop those values via draggable tables and specify which are more important.

While this is sweet and nice, there are lots of cases in which we want (or need) to play with field collection items at a lower level. So, lets speak code.

Creating

Lets start with something simple, this is basically the way we can create an field collection item:

  1. $target_node = node_load(10); // Load the node or any entity
  2. $field_collection_item = entity_create('field_collection_item', array('field_name' => 'field_work')); // create a blank FieldCollectionItemEntity instance
  3. $field_collection_item->setHostEntity('node', $target_node); // Bind those two via this function
  4.  
  5. // Now we simply need to populate the values of FieldCollectionItemEntity and save it
  6. // We will use entitymetadatawrapper to save fields
  7. $emw = entity_metadata_wrapper('field_collection_item', $field_collection_item);
  8. $emw->field_book_title->set('Programmatically created');
  9. $emw->field_pages->set('333');
  10. $emw->field_published_year->set(strtotime('2010-05-05 00:00:00'));
  11. $emw->field_publisher->set('PHP');
  12. // Finally save our item
  13. $field_collection_item->save();

You can notice that field collection items have to have a host entity, they don't exist on their own.

Loading and Editing

Here's an example of how you can load a field collection item, edit it and save it back (update it):

  1. // Lets suppose we know the ID of the item,
  2. // Or we simply check the value of the field on the host entity
  3. $field_collection_item_id = 5;
  4. $field_collection_item = field_collection_item_load($field_collection_item_id);
  5. // Now we can use EntityMetadataWrapper or simply drill down the entity and change the fields values
  6. // And then we save it via $field_collection_item->save();
  7. dsm($field_collection_item);

 

Invoking field collection items' form

Here's an example of how you can invoke a field collection items' form and use it for any purposes (pop-ups for instance):

  1. // This step is needed
  2. module_load_include('inc', 'field_collection', 'field_collection.pages');
  3. // Create an empty field collection item
  4. $field_collection_item = entity_create('field_collection_item', array('field_name' => 'field_work'));
  5. $entity_form = field_collection_item_form($form, $form_state, $field_collection_item);
  6. $form['work'] = $entity_form;
  7. $form['label'] = array('#markup' => '<h2>Add new Work item</h2>', '#weight' => '-10');
  8. dsm($form);

 

Saving a field collection item

On one of my projects I've did a small generic submit handler that would save field collection items from my custom forms (in my case, I was using profile2 module and fields would be stored in a profile2 instance, you can use any entity type and bundle you have and load it how you want).

  1. /**
  2.  * Generic collection item submit handler
  3.  */
  4. function nikro_custom_collection_item_submit($form, &$form_state) {
  5. global $user;
  6. module_load_include('inc', 'field_collection', 'field_collection.pages');
  7. // Load profile2 of the user
  8. $profile2 = profile2_load_by_user($user, 'my-profile');
  9.  
  10. // This is a helper function tha helps us prepare form / form_state
  11. field_collection_item_form_submit_build_field_collection($form, $form_state);
  12. // Copy items, set host and shoot the save function
  13. $field_collection_item = $form_state['field_collection_item'];
  14. $field_collection_item->setHostEntity('profile2', $profile2);
  15. $field_collection_item->save();
  16. }

 

More to come

First of all I want to mention this module: http://drupal.org/project/field_collection_views , we use it in our projects. And second of all, I will continue this topic with a 2nd part - Multi-value Field Collection Items with Ctools (inspired by this guy: http://dominiquedecooman.com/blog/drupal-7-using-ctools-modal-frames-and-field-collection-forms-create-better-user-experience ).

Hopefully that was usefull for someone, thanks.

Comments:

Feel free to ask any question / or share any suggestion!