This posed no problem as such, except for perhaps performance. Whenever a field collection is saved, the host entity is saved also. In my case it caused a save of the node 26 times, which is perhaps a bit overkill for a new node.
The FieldCollectionItem entity has an internal parameter ($skip_host_save) on the save() method. However, this is not availabe via entity_save() or via the entity metadata wrapper, the latter which I use heavily.
The class below will allow you to call an entity object's save() method with arguments via an entity metadata wrapper object.
/**
/** * Class EntityDrupalWrapperSaveArguments * * Hax0r class for saving field collection without saving the host entity. * * When saving a new field collection, the host entity will be saved as well. * This can result in several of unnecessary (1) saves of the host entity, * especially if creating a new node with many field collection fields. * * The FieldCollectionItem::save() supports an internal option for only saving * the field collection entity, but there's no way to send this option via * entity_save() or EntityDrupalWrapper::save(). Only through Entity::save() is * this possible. However, if we use Entity::save() directly, we loose all the * benefits of the metadata wrapper. * * Instead we implement a "pseudo" class, which has access to the entity * metadata wrapper object's protected variables. * * (1) They SEEM unnecessary. */ class EntityDrupalWrapperSaveArguments extends EntityDrupalWrapper { /** * Re-implementation of EntityDrupalWrapper->save(). * * When saving a new entity, the wrapper object's id must be updated. * Since this is a protected variable, we implement this method in a class * "pretending" to be an EntityDrupalWrapper class. Thereby we gain access to * protected variables in other objects of the same type. * * @see EntityDrupalWrapper::save(). */ static public function saveArguments() { $args = func_get_args(); $wrapper = array_shift($args); if ($wrapper->data) { if (!entity_type_supports($wrapper->type, 'save')) { throw new EntityMetadataWrapperException("There is no information about how to save entities of type " . check_plain($wrapper->type) . '.'); } self::entity_save_arguments($wrapper->type, $wrapper->data, $args); // On insert, update the identifier afterwards. if (!$wrapper->id) { list($wrapper->id, , ) = entity_extract_ids($wrapper->type, $wrapper->data); } } // If the entity hasn't been loaded yet, don't bother saving it. return $wrapper; } /** * Re-implementation of entity_save(). * * In order to send arguments to the entity's save() method, we need to * re-implement the logic from entity_save(). * * This function takes an extra arguments ($args) compared to entity_save(). * $args contains an array of the arguments passed to $entity->save(). * * Note: ^ There's a difference between entity_save() and $entity->save(). * * @see entity_save(). * @see Entity::save(). */ static public function entity_save_arguments($entity_type, $entity, $args) { $info = entity_get_info($entity_type); if (method_exists($entity, 'save')) { return call_user_func_array(array($entity, 'save'), $args); } elseif (isset($info['save callback'])) { $info['save callback']($entity); } elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) { return entity_get_controller($entity_type)->save($entity); } else { return FALSE; } } } // Create an Entity and populate it $entity = entity_create('node', array('type' => 'article')); $entity->uid = 1; $entity->title = 'test'; $wrapper = entity_metadata_wrapper('node', $entity); $fc_entity = entity_create('field_collection_item', array('field_name' => 'field_my_field_collection_field')); $fc_entity->setHostEntity('node', $entity); $fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc_entity); $fc_wrapper->field_my_field_inside_the_field_collection->set('some value'); // Old style save. // $fc_wrapper->save(); // New style save. // Equivalent to $fc_entity->save(TRUE), but retains the functionality of the metadata wrapper. EntityDrupalWrapperSaveArguments::saveArguments($fc_wrapper, TRUE);
Disclaimer: I'm not responsible if you hurt yourself with this code. And be aware, that using this code will also bypass some presave/update/insert handlers. Which could hurt you. Big time. And I'm not responsible.
Ingen kommentarer:
Send en kommentar