Invokes a method across fields on multiple entities.
string $method: The name of the method to invoke.
callable $target_function: A function that receives an $instance object and returns the object on which the method should be invoked.
array $entities: An array of entities, keyed by entity ID.
mixed $a: (optional) A parameter for the invoked method. Defaults to NULL.
mixed $b: (optional) A parameter for the invoked method. Defaults to NULL.
$options: (optional) An associative array of additional options, with the following keys:
array An array of returned values keyed by entity ID.
function field_invoke_method_multiple($method, $target_function, array $entities, &$a = NULL, &$b = NULL, array $options = array()) {
// Merge default options.
$default_options = array(
'deleted' => FALSE,
'langcode' => NULL,
);
$options += $default_options;
$instances = array();
$grouped_entities = array();
$grouped_items = array();
$grouped_targets = array();
$return = array();
// Go through the entities and collect the instances on which the method
// should be called.
foreach ($entities as $entity) {
$id = $entity
->id();
$entity_type = $entity
->entityType();
// Determine the list of instances to iterate on.
$entity_instances = _field_invoke_get_instances($entity_type, $entity
->bundle(), $options);
foreach ($entity_instances as $instance) {
$instance_id = $instance['id'];
$field_name = $instance['field_name'];
// Let the closure determine the target object on which the method should
// be called.
if (empty($grouped_targets[$instance_id])) {
$grouped_targets[$instance_id] = call_user_func($target_function, $instance);
}
if (method_exists($grouped_targets[$instance_id], $method)) {
// Add the instance to the list of instances to invoke the hook on.
if (!isset($instances[$instance_id])) {
$instances[$instance_id] = $instance;
}
// Unless a language code suggestion is provided we iterate on all the
// available language codes.
$field = field_info_field_by_id($instance['field_id']);
$available_langcodes = field_available_languages($entity_type, $field);
$langcode = !empty($options['langcode'][$id]) ? $options['langcode'][$id] : $options['langcode'];
$langcodes = _field_language_suggestion($available_langcodes, $langcode, $field_name);
foreach ($langcodes as $langcode) {
// Group the entities and items corresponding to the current field.
$grouped_entities[$instance_id][$langcode][$id] = $entities[$id];
$grouped_items[$instance_id][$langcode][$id] = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
}
}
}
// Initialize the return value for each entity.
$return[$id] = array();
}
// For each instance, invoke the method and collect results.
foreach ($instances as $instance_id => $instance) {
$field_name = $instance['field_name'];
// Iterate over all the field translations.
foreach ($grouped_items[$instance_id] as $langcode => &$items) {
$entities = $grouped_entities[$instance_id][$langcode];
$results = $grouped_targets[$instance_id]
->{$method}($entities, $langcode, $items, $a, $b);
if (isset($results)) {
// Collect results by entity.
// For hooks with array results, we merge results together.
// For hooks with scalar results, we collect results in an array.
foreach ($results as $id => $result) {
if (is_array($result)) {
$return[$id] = array_merge($return[$id], $result);
}
else {
$return[$id][] = $result;
}
}
}
}
// Populate field values back in the entities, but avoid replacing missing
// fields with an empty array (those are not equivalent on update).
foreach ($grouped_entities[$instance_id] as $langcode => $entities) {
foreach ($entities as $id => $entity) {
if ($grouped_items[$instance_id][$langcode][$id] !== array() || isset($entity->{$field_name}[$langcode])) {
$entity->{$field_name}[$langcode] = $grouped_items[$instance_id][$langcode][$id];
}
}
}
}
return $return;
}