Drupal version: 7.21
Field collection module version: 7.x-1.0-beta5
Short explanation: I'm busy trying to import field collections programmatically but when deleting some of them there's always some 'bogus' field collection left.
Long explanation: My users have a field collection field on their profile. This field collection contains 3 text fields. I want to import data from a custom sql database into the field collection of the user. This field collection can have multiple values. When I import the data for the first time everything works fine, I see the data in the fields of the field collection. Great.
But here comes the tricky part. Let's say I import for one specific user 5 rows from the custom database. They get added to the field collection, so this field collection has 5 items each containing 3 fields. Then I delete some rows from my custom database so that I have only 3 rows left for this user. I run the import again, updating the first 3 items of the field collection, but then I'm left with 2 items from the previous import. They should be deleted because I have only 3 imported rows but still 5 field collection items.
So I tried to delete these field collection items, but there's always one or more items left. The fields are empty when I look at the user profile but there's still something there. Let's say at this point I add 5 new rows for the user in my custom database, so I have 8 rows in total for this user. Then I run the import again. The first 3 items get updated, but then when I try to add the 4th row it still gets an entity id from the 4th field collection item, tries to update it but fails and returns this error:
Fatal error: Call to undefined method stdClass::save()
I tried deleting the field collection items with each of these methods below:
// Method 1
entity_delete_multiple('field_collection_item', array($fc_id));
// Method 2
$field_collection_item = field_collection_item_load($fc_id);
$field_collection_item->delete();
// Method 3
$field_collection_item = field_collection_item_load($fc_id);
$field_collection_item->deleteRevision();
This is my full code:
function import_user_field_collection(&$user, $old_user_id) {
// I do a query to get the rows I want to import for this specific user.
db_set_active('custom_sql_database');
$result = db_query("SELECT * FROM {users} WHERE user_id = :user_id", array(':user_id' => $old_user_id));
db_set_active('default');
$i = 0; // Keep count of how many rows I imported.
foreach($result as $row) {
// Check if the field collection item already exists.
if(!empty($user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'])) {
// If it does exists, update this particular field collection item.
$fc_id = $user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'];
$field_collection_item = entity_load('field_collection_item', array($fc_id));
// These 3 text fields are children of the field collection field.
$field_collection_item[$fc_id]->field_profile_diploma_instituut[LANGUAGE_NONE][0]['value'] = $row->instituut;
$field_collection_item[$fc_id]->field_profile_diploma_vakgebied[LANGUAGE_NONE][0]['value'] = $row->vakgebied;
$field_collection_item[$fc_id]->field_profile_diploma_jaar[LANGUAGE_NONE][0]['value'] = $row->jaar_diploma;
$field_collection_item[$fc_id]->save(TRUE);
} else {
// If the field collection item doesn't exist I want to create a new field collection item.
$field_collection_item = entity_create('field_collection_item', array('field_name' => 'field_profile_diploma_opleiding'));
$field_collection_item->setHostEntity('user', $user);
$field_collection_item->field_profile_diploma_instituut[LANGUAGE_NONE][0]['value'] = $row->instituut;
$field_collection_item->field_profile_diploma_vakgebied[LANGUAGE_NONE][0]['value'] = $row->vakgebied;
$field_collection_item->field_profile_diploma_jaar[LANGUAGE_NONE][0]['value'] = $row->jaar_diploma;
$field_collection_item->save(TRUE);
}
$i++;
}
$fc_fields = field_get_items('user', $user, 'field_profile_diploma_opleiding');
// Check if there are more field collection items than imported rows
if(count($fc_fields) > $i) {
for($i; $i <= count($fc_fields); $i++) {
// Run through each field collection item that's left from the previous import and delete it.
if(!empty($user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'])) {
// Method 1
$fc_id = $user->field_profile_diploma_opleiding[LANGUAGE_NONE][$i]['value'];
entity_delete_multiple('field_collection_item', array($fc_id));
// Method 2
//$field_collection_item = field_collection_item_load($fc_id);
//$field_collection_item->delete();
// Method 3
//$field_collection_item = field_collection_item_load($fc_id);
//$field_collection_item->deleteRevision();
}
}
}
}
So my question is: How do I delete field collection items so that they're actually gone?
entity_delete_multiple
is 100% definitely the right way to do it - have a look at thefield_collection_field_delete
function, which is what Field Collection itself uses to clean up items when the referenced field is removedentity_delete_multiple()
. You might need to run cron a couple of times after you delete fields (field data is purged on a schedule so as not to burden a single page load with all that processing to do)