Commit 1c4ff2fc authored by Dries's avatar Dries

- Patch #760238 by yched: optimize _field_invoke().

parent 29a93b8c
......@@ -181,40 +181,23 @@ function _field_invoke($op, $entity_type, $entity, &$a = NULL, &$b = NULL, $opti
);
$options += $default_options;
// Iterate through the entity's field instances.
$return = array();
// Determine the list of instances to iterate on.
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
$instances = _field_invoke_get_instances($entity_type, $bundle, $options);
if ($options['deleted']) {
$instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle), array('include_deleted' => $options['deleted']));
}
else {
$instances = field_info_instances($entity_type, $bundle);
}
// Iterate through the instances and collect results.
$return = array();
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
// When in 'single field' mode, only act on the specified field.
if ((!isset($options['field_id']) || $options['field_id'] == $instance['field_id']) && (!isset($options['field_name']) || $options['field_name'] == $field_name)) {
$field = field_info_field($field_name);
$field_translations = array();
// Unless a language suggestion is provided we iterate on all the
// available languages.
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Determine the list of languages to iterate on.
$available_languages = field_available_languages($entity_type, $field);
$languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
// Initialize field translations according to the available languages.
foreach ($languages as $langcode) {
$field_translations[$langcode] = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
}
// Invoke the field hook and collect results.
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Iterate over all the field translations.
foreach ($field_translations as $langcode => $items) {
$items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
$result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
if (isset($result)) {
// For hooks with array results, we merge results together.
......@@ -235,7 +218,6 @@ function _field_invoke($op, $entity_type, $entity, &$a = NULL, &$b = NULL, $opti
}
}
}
}
return $return;
}
......@@ -309,23 +291,19 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
// is deleted, so we reference field data via the
// $entity->$field_name property.
foreach ($entities as $entity) {
// Determine the list of instances to iterate on.
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
if ($options['deleted']) {
$instances = field_read_field(array('bundle' => $bundle, array('include_deleted' => $options['deleted'])));
}
else {
$instances = field_info_instances($entity_type, $bundle);
}
$instances = _field_invoke_get_instances($entity_type, $bundle, $options);
foreach ($instances as $instance) {
$field_id = $instance['field_id'];
$field_name = $instance['field_name'];
// When in 'single field' mode, only act on the specified field.
if ((empty($options['field_id']) || $options['field_id'] == $field_id) && (empty($options['field_name']) || $options['field_name'] == $field_name)) {
$field = field_info_field_by_id($field_id);
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Add the field to the list of fields to invoke the hook on.
if (!isset($fields[$field_id])) {
$fields[$field_id] = field_info_field_by_id($field_id);
$fields[$field_id] = $field;
}
// Group the corresponding instances and entities.
$grouped_instances[$field_id][$id] = $instance;
......@@ -334,7 +312,7 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
// by hook implementations.
// Unless a language suggestion is provided we iterate on all the
// available languages.
$available_languages = field_available_languages($entity_type, $fields[$field_id]);
$available_languages = field_available_languages($entity_type, $field);
$languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
foreach ($languages as $langcode) {
$grouped_items[$field_id][$langcode][$id] = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
......@@ -349,7 +327,6 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
foreach ($fields as $field_id => $field) {
$field_name = $field['field_name'];
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Iterate over all the field translations.
foreach ($grouped_items[$field_id] as $langcode => $items) {
$results = $function($entity_type, $grouped_entities[$field_id], $field, $grouped_instances[$field_id], $langcode, $grouped_items[$field_id][$langcode], $a, $b);
......@@ -367,7 +344,6 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
}
}
}
}
// Populate field values back in the entities, but avoid replacing missing
// fields with an empty array (those are not equivalent on update).
......@@ -411,6 +387,59 @@ function _field_invoke_multiple_default($op, $entity_type, $entities, &$a = NULL
return _field_invoke_multiple($op, $entity_type, $entities, $a, $b, $options);
}
/**
* Helper for _field_invoke(): retrieves a list of instances to operate on.
*
* @param $entity_type
* The entity type.
* @param $bundle
* The bundle name.
* @param $options
* An associative array of options, as provided to _field_invoke(). Only the
* following keys are considered :
* - deleted
* - field_name
* - field_id
* See _field_invoke() for details.
*
* @return
* The array of selected instance definitions.
*/
function _field_invoke_get_instances($entity_type, $bundle, $options) {
if ($options['deleted']) {
// Deleted fields are not included in field_info_instances(), and need to
// be fetched from the database with field_read_instances().
$params = array('entity_type' => $entity_type, 'bundle' => $bundle);
if (isset($options['field_id'])) {
// Single-field mode by field id: field_read_instances() does the filtering.
// Single-field mode by field name is not compatible with the 'deleted'
// option.
$params['field_id'] = $options['field_id'];
}
$instances = field_read_instances($params, array('include_deleted' => TRUE));
}
elseif (isset($options['field_name'])) {
// Single-field mode by field name: field_info_instance() does the
// filtering.
$instances = array(field_info_instance($entity_type, $options['field_name'], $bundle));
}
else {
$instances = field_info_instances($entity_type, $bundle);
if (isset($options['field_id'])) {
// Single-field mode by field id: we need to loop on each instance to
// find the right one.
foreach ($instances as $instance) {
if ($instance['field_id'] == $options['field_id']) {
$instances = array($instance);
break;
}
}
}
}
return $instances;
}
/**
* Add form elements for all fields for an entity to a form structure.
*
......@@ -611,19 +640,15 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
$function($entity_type, $queried_entities, $age, $skip_fields, $options);
}
$instances = array();
// Collect the storage backends used by the remaining fields in the entities.
$storages = array();
foreach ($queried_entities as $entity) {
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
if ($options['deleted']) {
$instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle), array('include_deleted' => $options['deleted']));
}
else {
$instances = field_info_instances($entity_type, $bundle);
}
$instances = _field_invoke_get_instances($entity_type, $bundle, $options);
foreach ($instances as $instance) {
if (!isset($options['field_id']) || $options['field_id'] == $instance['field_id']) {
$field_name = $instance['field_name'];
$field_id = $instance['field_id'];
// Make sure all fields are present at least as empty arrays.
......@@ -637,7 +662,6 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
}
}
}
}
// Invoke hook_field_storage_load() on the relevant storage backends.
foreach ($storages as $storage => $fields) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment