@@ -873,7 +873,7 @@ function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
||||
'#type' => $instance['widget']['type'],
|
||||
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
|
||||
);
|
||||
return $element;
|
||||
return array('value' => $element);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1735,11 +1735,14 @@ function hook_field_storage_details_alter(&$details, $field) {
|
||||
* loaded.
|
||||
*/
|
||||
function hook_field_storage_load($entity_type, $entities, $age, $fields, $options) {
|
||||
$field_info = field_info_field_by_ids();
|
||||
$load_current = $age == FIELD_LOAD_CURRENT;
|
||||
|
||||
foreach ($fields as $field_id => $ids) {
|
||||
$field = $field_info[$field_id];
|
||||
// By the time this hook runs, the relevant field definitions have been
|
||||
// populated and cached in FieldInfo, so calling field_info_field_by_id()
|
||||
// on each field individually is more efficient than loading all fields in
|
||||
// memory upfront with field_info_field_by_ids().
|
||||
$field = field_info_field_by_id($field_id);
|
||||
$field_name = $field['field_name'];
|
||||
$table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
|
||||
|
||||
|
@@ -283,7 +283,6 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
|
||||
'language' => NULL,
|
||||
);
|
||||
$options += $default_options;
|
||||
$field_info = field_info_field_by_ids();
|
||||
|
||||
$fields = array();
|
||||
$grouped_instances = array();
|
||||
@@ -307,7 +306,7 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
|
||||
foreach ($instances as $instance) {
|
||||
$field_id = $instance['field_id'];
|
||||
$field_name = $instance['field_name'];
|
||||
$field = $field_info[$field_id];
|
||||
$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.
|
||||
@@ -555,16 +554,23 @@ function _field_invoke_get_instances($entity_type, $bundle, $options) {
|
||||
* @param $langcode
|
||||
* The language the field values are going to be entered, if no language
|
||||
* is provided the default site language will be used.
|
||||
* @param array $options
|
||||
* An associative array of additional options. See _field_invoke() for
|
||||
* details.
|
||||
*
|
||||
* @see field_form_get_state()
|
||||
* @see field_form_set_state()
|
||||
*/
|
||||
function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode = NULL) {
|
||||
function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode = NULL, $options = array()) {
|
||||
// Validate $options since this is a new parameter added after Drupal 7 was
|
||||
// released.
|
||||
$options = is_array($options) ? $options : array();
|
||||
|
||||
// Set #parents to 'top-level' by default.
|
||||
$form += array('#parents' => array());
|
||||
|
||||
// If no language is provided use the default site language.
|
||||
$options = array('language' => field_valid_language($langcode));
|
||||
$options['language'] = field_valid_language($langcode);
|
||||
$form += (array) _field_invoke_default('form', $entity_type, $entity, $form, $form_state, $options);
|
||||
|
||||
// Add custom weight handling.
|
||||
@@ -614,7 +620,6 @@ function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcod
|
||||
* non-deleted fields are operated on.
|
||||
*/
|
||||
function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array()) {
|
||||
$field_info = field_info_field_by_ids();
|
||||
$load_current = $age == FIELD_LOAD_CURRENT;
|
||||
|
||||
// Merge default options.
|
||||
@@ -692,7 +697,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
|
||||
}
|
||||
// Collect the storage backend if the field has not been loaded yet.
|
||||
if (!isset($skip_fields[$field_id])) {
|
||||
$field = $field_info[$field_id];
|
||||
$field = field_info_field_by_id($field_id);
|
||||
$storages[$field['storage']['type']][$field_id][] = $load_current ? $id : $vid;
|
||||
}
|
||||
}
|
||||
@@ -709,7 +714,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
|
||||
_field_invoke_multiple('load', $entity_type, $queried_entities, $age, $null, $options);
|
||||
|
||||
// Invoke hook_field_attach_load(): let other modules act on loading the
|
||||
// entitiy.
|
||||
// entity.
|
||||
module_invoke_all('field_attach_load', $entity_type, $queried_entities, $age, $options);
|
||||
|
||||
// Build cache data.
|
||||
@@ -769,13 +774,21 @@ function field_attach_load_revision($entity_type, $entities, $options = array())
|
||||
* If validation errors are found, a FieldValidationException is thrown. The
|
||||
* 'errors' property contains the array of errors, keyed by field name,
|
||||
* language and delta.
|
||||
* @param array $options
|
||||
* An associative array of additional options. See _field_invoke() for
|
||||
* details.
|
||||
*/
|
||||
function field_attach_validate($entity_type, $entity) {
|
||||
function field_attach_validate($entity_type, $entity, $options = array()) {
|
||||
// Validate $options since this is a new parameter added after Drupal 7 was
|
||||
// released.
|
||||
$options = is_array($options) ? $options : array();
|
||||
|
||||
$errors = array();
|
||||
// Check generic, field-type-agnostic errors first.
|
||||
_field_invoke_default('validate', $entity_type, $entity, $errors);
|
||||
$null = NULL;
|
||||
_field_invoke_default('validate', $entity_type, $entity, $errors, $null, $options);
|
||||
// Check field-type specific errors.
|
||||
_field_invoke('validate', $entity_type, $entity, $errors);
|
||||
_field_invoke('validate', $entity_type, $entity, $errors, $null, $options);
|
||||
|
||||
// Let other modules validate the entity.
|
||||
// Avoid module_invoke_all() to let $errors be taken by reference.
|
||||
@@ -817,14 +830,21 @@ function field_attach_validate($entity_type, $entity) {
|
||||
* full form structure, or a sub-element of a larger form.
|
||||
* @param $form_state
|
||||
* An associative array containing the current state of the form.
|
||||
* @param array $options
|
||||
* An associative array of additional options. See _field_invoke() for
|
||||
* details.
|
||||
*/
|
||||
function field_attach_form_validate($entity_type, $entity, $form, &$form_state) {
|
||||
function field_attach_form_validate($entity_type, $entity, $form, &$form_state, $options = array()) {
|
||||
// Validate $options since this is a new parameter added after Drupal 7 was
|
||||
// released.
|
||||
$options = is_array($options) ? $options : array();
|
||||
|
||||
// Extract field values from submitted values.
|
||||
_field_invoke_default('extract_form_values', $entity_type, $entity, $form, $form_state);
|
||||
|
||||
// Perform field_level validation.
|
||||
try {
|
||||
field_attach_validate($entity_type, $entity);
|
||||
field_attach_validate($entity_type, $entity, $options);
|
||||
}
|
||||
catch (FieldValidationException $e) {
|
||||
// Pass field-level validation errors back to widgets for accurate error
|
||||
@@ -836,7 +856,7 @@ function field_attach_form_validate($entity_type, $entity, $form, &$form_state)
|
||||
field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
|
||||
}
|
||||
}
|
||||
_field_invoke_default('form_errors', $entity_type, $entity, $form, $form_state);
|
||||
_field_invoke_default('form_errors', $entity_type, $entity, $form, $form_state, $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,12 +877,19 @@ function field_attach_form_validate($entity_type, $entity, $form, &$form_state)
|
||||
* full form structure, or a sub-element of a larger form.
|
||||
* @param $form_state
|
||||
* An associative array containing the current state of the form.
|
||||
* @param array $options
|
||||
* An associative array of additional options. See _field_invoke() for
|
||||
* details.
|
||||
*/
|
||||
function field_attach_submit($entity_type, $entity, $form, &$form_state) {
|
||||
// Extract field values from submitted values.
|
||||
_field_invoke_default('extract_form_values', $entity_type, $entity, $form, $form_state);
|
||||
function field_attach_submit($entity_type, $entity, $form, &$form_state, $options = array()) {
|
||||
// Validate $options since this is a new parameter added after Drupal 7 was
|
||||
// released.
|
||||
$options = is_array($options) ? $options : array();
|
||||
|
||||
_field_invoke_default('submit', $entity_type, $entity, $form, $form_state);
|
||||
// Extract field values from submitted values.
|
||||
_field_invoke_default('extract_form_values', $entity_type, $entity, $form, $form_state, $options);
|
||||
|
||||
_field_invoke_default('submit', $entity_type, $entity, $form, $form_state, $options);
|
||||
|
||||
// Let other modules act on submitting the entity.
|
||||
// Avoid module_invoke_all() to let $form_state be taken by reference.
|
||||
@@ -1093,9 +1120,16 @@ function field_attach_delete_revision($entity_type, $entity) {
|
||||
* @param $langcode
|
||||
* (Optional) The language the field values are to be shown in. If no language
|
||||
* is provided the current language is used.
|
||||
* @param array $options
|
||||
* An associative array of additional options. See _field_invoke() for
|
||||
* details.
|
||||
*/
|
||||
function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcode = NULL) {
|
||||
$options = array('language' => array());
|
||||
function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcode = NULL, $options = array()) {
|
||||
// Validate $options since this is a new parameter added after Drupal 7 was
|
||||
// released.
|
||||
$options = is_array($options) ? $options : array();
|
||||
|
||||
$options['language'] = array();
|
||||
|
||||
// To ensure hooks are only run once per entity, only process items without
|
||||
// the _field_view_prepared flag.
|
||||
@@ -1167,14 +1201,21 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcod
|
||||
* @param $langcode
|
||||
* The language the field values are to be shown in. If no language is
|
||||
* provided the current language is used.
|
||||
* @param array $options
|
||||
* An associative array of additional options. See _field_invoke() for
|
||||
* details.
|
||||
* @return
|
||||
* A renderable array for the field values.
|
||||
*/
|
||||
function field_attach_view($entity_type, $entity, $view_mode, $langcode = NULL) {
|
||||
function field_attach_view($entity_type, $entity, $view_mode, $langcode = NULL, $options = array()) {
|
||||
// Validate $options since this is a new parameter added after Drupal 7 was
|
||||
// released.
|
||||
$options = is_array($options) ? $options : array();
|
||||
|
||||
// Determine the actual language to display for each field, given the
|
||||
// languages available in the field data.
|
||||
$display_language = field_language($entity_type, $entity, NULL, $langcode);
|
||||
$options = array('language' => $display_language);
|
||||
$options['language'] = $display_language;
|
||||
|
||||
// Invoke field_default_view().
|
||||
$null = NULL;
|
||||
|
@@ -319,7 +319,11 @@ function field_read_field($field_name, $include_additional = array()) {
|
||||
* Reads in fields that match an array of conditions.
|
||||
*
|
||||
* @param array $params
|
||||
* An array of conditions to match against.
|
||||
* An array of conditions to match against. Keys are columns from the
|
||||
* 'field_config' table, values are conditions to match. Additionally,
|
||||
* conditions on the 'entity_type' and 'bundle' columns from the
|
||||
* 'field_config_instance' table are supported (select fields having an
|
||||
* instance on a given bundle).
|
||||
* @param array $include_additional
|
||||
* The default behavior of this function is to not return fields that
|
||||
* are inactive or have been deleted. Setting
|
||||
@@ -337,8 +341,21 @@ function field_read_fields($params = array(), $include_additional = array()) {
|
||||
|
||||
// Turn the conditions into a query.
|
||||
foreach ($params as $key => $value) {
|
||||
// Allow filtering on the 'entity_type' and 'bundle' columns of the
|
||||
// field_config_instance table.
|
||||
if ($key == 'entity_type' || $key == 'bundle') {
|
||||
if (empty($fci_join)) {
|
||||
$fci_join = $query->join('field_config_instance', 'fci', 'fc.id = fci.field_id');
|
||||
}
|
||||
$key = 'fci.' . $key;
|
||||
}
|
||||
else {
|
||||
$key = 'fc.' . $key;
|
||||
}
|
||||
|
||||
$query->condition($key, $value);
|
||||
}
|
||||
|
||||
if (!isset($include_additional['include_inactive']) || !$include_additional['include_inactive']) {
|
||||
$query
|
||||
->condition('fc.active', 1)
|
||||
|
@@ -5,13 +5,14 @@ version = VERSION
|
||||
core = 7.x
|
||||
files[] = field.module
|
||||
files[] = field.attach.inc
|
||||
files[] = field.info.class.inc
|
||||
files[] = tests/field.test
|
||||
dependencies[] = field_sql_storage
|
||||
required = TRUE
|
||||
stylesheets[all][] = theme/field.css
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
668
modules/field/field.info.class.inc
Normal file
668
modules/field/field.info.class.inc
Normal file
@@ -0,0 +1,668 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @file
|
||||
* Definition of the FieldInfo class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides field and instance definitions for the current runtime environment.
|
||||
*
|
||||
* A FieldInfo object is created and statically persisted through the request
|
||||
* by the _field_info_field_cache() function. The object properties act as a
|
||||
* "static cache" of fields and instances definitions.
|
||||
*
|
||||
* The preferred way to access definitions is through the getBundleInstances()
|
||||
* method, which keeps cache entries per bundle, storing both fields and
|
||||
* instances for a given bundle. Fields used in multiple bundles are duplicated
|
||||
* in several cache entries, and are merged into a single list in the memory
|
||||
* cache. Cache entries are loaded for bundles as a whole, optimizing memory
|
||||
* and CPU usage for the most common pattern of iterating over all instances of
|
||||
* a bundle rather than accessing a single instance.
|
||||
*
|
||||
* The getFields() and getInstances() methods, which return all existing field
|
||||
* and instance definitions, are kept mainly for backwards compatibility, and
|
||||
* should be avoided when possible, since they load and persist in memory a
|
||||
* potentially large array of information. In many cases, the lightweight
|
||||
* getFieldMap() method should be preferred.
|
||||
*/
|
||||
class FieldInfo {
|
||||
|
||||
/**
|
||||
* Lightweight map of fields across entity types and bundles.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldMap;
|
||||
|
||||
/**
|
||||
* List of $field structures keyed by ID. Includes deleted fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldsById = array();
|
||||
|
||||
/**
|
||||
* Mapping of field names to the ID of the corresponding non-deleted field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldIdsByName = array();
|
||||
|
||||
/**
|
||||
* Whether $fieldsById contains all field definitions or a subset.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $loadedAllFields = FALSE;
|
||||
|
||||
/**
|
||||
* Separately tracks requested field names or IDs that do not exist.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $unknownFields = array();
|
||||
|
||||
/**
|
||||
* Instance definitions by bundle.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bundleInstances = array();
|
||||
|
||||
/**
|
||||
* Whether $bundleInstances contains all instances definitions or a subset.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $loadedAllInstances = FALSE;
|
||||
|
||||
/**
|
||||
* Separately tracks requested bundles that are empty (or do not exist).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $emptyBundles = array();
|
||||
|
||||
/**
|
||||
* Extra fields by bundle.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bundleExtraFields = array();
|
||||
|
||||
/**
|
||||
* Clears the "static" and persistent caches.
|
||||
*/
|
||||
public function flush() {
|
||||
$this->fieldMap = NULL;
|
||||
|
||||
$this->fieldsById = array();
|
||||
$this->fieldIdsByName = array();
|
||||
$this->loadedAllFields = FALSE;
|
||||
$this->unknownFields = array();
|
||||
|
||||
$this->bundleInstances = array();
|
||||
$this->loadedAllInstances = FALSE;
|
||||
$this->emptyBundles = array();
|
||||
|
||||
$this->bundleExtraFields = array();
|
||||
|
||||
cache_clear_all('field_info:', 'cache_field', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects a lightweight map of fields across bundles.
|
||||
*
|
||||
* @return
|
||||
* An array keyed by field name. Each value is an array with two entries:
|
||||
* - type: The field type.
|
||||
* - bundles: The bundles in which the field appears, as an array with
|
||||
* entity types as keys and the array of bundle names as values.
|
||||
*/
|
||||
public function getFieldMap() {
|
||||
// Read from the "static" cache.
|
||||
if ($this->fieldMap !== NULL) {
|
||||
return $this->fieldMap;
|
||||
}
|
||||
|
||||
// Read from persistent cache.
|
||||
if ($cached = cache_get('field_info:field_map', 'cache_field')) {
|
||||
$map = $cached->data;
|
||||
|
||||
// Save in "static" cache.
|
||||
$this->fieldMap = $map;
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
$map = array();
|
||||
|
||||
$query = db_query('SELECT fc.type, fci.field_name, fci.entity_type, fci.bundle FROM {field_config_instance} fci INNER JOIN {field_config} fc ON fc.id = fci.field_id WHERE fc.active = 1 AND fc.storage_active = 1 AND fc.deleted = 0 AND fci.deleted = 0');
|
||||
foreach ($query as $row) {
|
||||
$map[$row->field_name]['bundles'][$row->entity_type][] = $row->bundle;
|
||||
$map[$row->field_name]['type'] = $row->type;
|
||||
}
|
||||
|
||||
// Save in "static" and persistent caches.
|
||||
$this->fieldMap = $map;
|
||||
cache_set('field_info:field_map', $map, 'cache_field');
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all active fields, including deleted ones.
|
||||
*
|
||||
* @return
|
||||
* An array of field definitions, keyed by field ID.
|
||||
*/
|
||||
public function getFields() {
|
||||
// Read from the "static" cache.
|
||||
if ($this->loadedAllFields) {
|
||||
return $this->fieldsById;
|
||||
}
|
||||
|
||||
// Read from persistent cache.
|
||||
if ($cached = cache_get('field_info:fields', 'cache_field')) {
|
||||
$this->fieldsById = $cached->data;
|
||||
}
|
||||
else {
|
||||
// Collect and prepare fields.
|
||||
foreach (field_read_fields(array(), array('include_deleted' => TRUE)) as $field) {
|
||||
$this->fieldsById[$field['id']] = $this->prepareField($field);
|
||||
}
|
||||
|
||||
// Store in persistent cache.
|
||||
cache_set('field_info:fields', $this->fieldsById, 'cache_field');
|
||||
}
|
||||
|
||||
// Fill the name/ID map.
|
||||
foreach ($this->fieldsById as $field) {
|
||||
if (!$field['deleted']) {
|
||||
$this->fieldIdsByName[$field['field_name']] = $field['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->loadedAllFields = TRUE;
|
||||
|
||||
return $this->fieldsById;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all active, non-deleted instances definitions.
|
||||
*
|
||||
* @param $entity_type
|
||||
* (optional) The entity type.
|
||||
*
|
||||
* @return
|
||||
* If $entity_type is not set, all instances keyed by entity type and bundle
|
||||
* name. If $entity_type is set, all instances for that entity type, keyed
|
||||
* by bundle name.
|
||||
*/
|
||||
public function getInstances($entity_type = NULL) {
|
||||
// If the full list is not present in "static" cache yet.
|
||||
if (!$this->loadedAllInstances) {
|
||||
|
||||
// Read from persistent cache.
|
||||
if ($cached = cache_get('field_info:instances', 'cache_field')) {
|
||||
$this->bundleInstances = $cached->data;
|
||||
}
|
||||
else {
|
||||
// Collect and prepare instances.
|
||||
|
||||
// We also need to populate the static field cache, since it will not
|
||||
// be set by subsequent getBundleInstances() calls.
|
||||
$this->getFields();
|
||||
|
||||
// Initialize empty arrays for all existing entity types and bundles.
|
||||
// This is not strictly needed, but is done to preserve the behavior of
|
||||
// field_info_instances() before http://drupal.org/node/1915646.
|
||||
foreach (field_info_bundles() as $existing_entity_type => $bundles) {
|
||||
foreach ($bundles as $bundle => $bundle_info) {
|
||||
$this->bundleInstances[$existing_entity_type][$bundle] = array();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (field_read_instances() as $instance) {
|
||||
$field = $this->getField($instance['field_name']);
|
||||
$instance = $this->prepareInstance($instance, $field['type']);
|
||||
$this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
|
||||
}
|
||||
|
||||
// Store in persistent cache.
|
||||
cache_set('field_info:instances', $this->bundleInstances, 'cache_field');
|
||||
}
|
||||
|
||||
$this->loadedAllInstances = TRUE;
|
||||
}
|
||||
|
||||
if (isset($entity_type)) {
|
||||
return isset($this->bundleInstances[$entity_type]) ? $this->bundleInstances[$entity_type] : array();
|
||||
}
|
||||
else {
|
||||
return $this->bundleInstances;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field definition from a field name.
|
||||
*
|
||||
* This method only retrieves active, non-deleted fields.
|
||||
*
|
||||
* @param $field_name
|
||||
* The field name.
|
||||
*
|
||||
* @return
|
||||
* The field definition, or NULL if no field was found.
|
||||
*/
|
||||
public function getField($field_name) {
|
||||
// Read from the "static" cache.
|
||||
if (isset($this->fieldIdsByName[$field_name])) {
|
||||
$field_id = $this->fieldIdsByName[$field_name];
|
||||
return $this->fieldsById[$field_id];
|
||||
}
|
||||
if (isset($this->unknownFields[$field_name])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not check the (large) persistent cache, but read the definition.
|
||||
|
||||
// Cache miss: read from definition.
|
||||
if ($field = field_read_field($field_name)) {
|
||||
$field = $this->prepareField($field);
|
||||
|
||||
// Save in the "static" cache.
|
||||
$this->fieldsById[$field['id']] = $field;
|
||||
$this->fieldIdsByName[$field['field_name']] = $field['id'];
|
||||
|
||||
return $field;
|
||||
}
|
||||
else {
|
||||
$this->unknownFields[$field_name] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field definition from a field ID.
|
||||
*
|
||||
* This method only retrieves active fields, deleted or not.
|
||||
*
|
||||
* @param $field_id
|
||||
* The field ID.
|
||||
*
|
||||
* @return
|
||||
* The field definition, or NULL if no field was found.
|
||||
*/
|
||||
public function getFieldById($field_id) {
|
||||
// Read from the "static" cache.
|
||||
if (isset($this->fieldsById[$field_id])) {
|
||||
return $this->fieldsById[$field_id];
|
||||
}
|
||||
if (isset($this->unknownFields[$field_id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No persistent cache, fields are only persistently cached as part of a
|
||||
// bundle.
|
||||
|
||||
// Cache miss: read from definition.
|
||||
if ($fields = field_read_fields(array('id' => $field_id), array('include_deleted' => TRUE))) {
|
||||
$field = current($fields);
|
||||
$field = $this->prepareField($field);
|
||||
|
||||
// Store in the static cache.
|
||||
$this->fieldsById[$field['id']] = $field;
|
||||
if (!$field['deleted']) {
|
||||
$this->fieldIdsByName[$field['field_name']] = $field['id'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
else {
|
||||
$this->unknownFields[$field_id] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the instances for a bundle.
|
||||
*
|
||||
* The function also populates the corresponding field definitions in the
|
||||
* "static" cache.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type.
|
||||
* @param $bundle
|
||||
* The bundle name.
|
||||
*
|
||||
* @return
|
||||
* The array of instance definitions, keyed by field name.
|
||||
*/
|
||||
public function getBundleInstances($entity_type, $bundle) {
|
||||
// Read from the "static" cache.
|
||||
if (isset($this->bundleInstances[$entity_type][$bundle])) {
|
||||
return $this->bundleInstances[$entity_type][$bundle];
|
||||
}
|
||||
if (isset($this->emptyBundles[$entity_type][$bundle])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Read from the persistent cache.
|
||||
if ($cached = cache_get("field_info:bundle:$entity_type:$bundle", 'cache_field')) {
|
||||
$info = $cached->data;
|
||||
|
||||
// Extract the field definitions and save them in the "static" cache.
|
||||
foreach ($info['fields'] as $field) {
|
||||
if (!isset($this->fieldsById[$field['id']])) {
|
||||
$this->fieldsById[$field['id']] = $field;
|
||||
if (!$field['deleted']) {
|
||||
$this->fieldIdsByName[$field['field_name']] = $field['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($info['fields']);
|
||||
|
||||
// Store the instance definitions in the "static" cache'. Empty (or
|
||||
// non-existent) bundles are stored separately, so that they do not
|
||||
// pollute the global list returned by getInstances().
|
||||
if ($info['instances']) {
|
||||
$this->bundleInstances[$entity_type][$bundle] = $info['instances'];
|
||||
}
|
||||
else {
|
||||
$this->emptyBundles[$entity_type][$bundle] = TRUE;
|
||||
}
|
||||
|
||||
return $info['instances'];
|
||||
}
|
||||
|
||||
// Cache miss: collect from the definitions.
|
||||
|
||||
$instances = array();
|
||||
|
||||
// Collect the fields in the bundle.
|
||||
$params = array('entity_type' => $entity_type, 'bundle' => $bundle);
|
||||
$fields = field_read_fields($params);
|
||||
|
||||
// This iterates on non-deleted instances, so deleted fields are kept out of
|
||||
// the persistent caches.
|
||||
foreach (field_read_instances($params) as $instance) {
|
||||
$field = $fields[$instance['field_name']];
|
||||
|
||||
$instance = $this->prepareInstance($instance, $field['type']);
|
||||
$instances[$field['field_name']] = $instance;
|
||||
|
||||
// If the field is not in our global "static" list yet, add it.
|
||||
if (!isset($this->fieldsById[$field['id']])) {
|
||||
$field = $this->prepareField($field);
|
||||
|
||||
$this->fieldsById[$field['id']] = $field;
|
||||
$this->fieldIdsByName[$field['field_name']] = $field['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// Store in the 'static' cache'. Empty (or non-existent) bundles are stored
|
||||
// separately, so that they do not pollute the global list returned by
|
||||
// getInstances().
|
||||
if ($instances) {
|
||||
$this->bundleInstances[$entity_type][$bundle] = $instances;
|
||||
}
|
||||
else {
|
||||
$this->emptyBundles[$entity_type][$bundle] = TRUE;
|
||||
}
|
||||
|
||||
// The persistent cache additionally contains the definitions of the fields
|
||||
// involved in the bundle.
|
||||
$cache = array(
|
||||
'instances' => $instances,
|
||||
'fields' => array()
|
||||
);
|
||||
foreach ($instances as $instance) {
|
||||
$cache['fields'][] = $this->fieldsById[$instance['field_id']];
|
||||
}
|
||||
cache_set("field_info:bundle:$entity_type:$bundle", $cache, 'cache_field');
|
||||
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the "extra fields" for a bundle.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type.
|
||||
* @param $bundle
|
||||
* The bundle name.
|
||||
*
|
||||
* @return
|
||||
* The array of extra fields.
|
||||
*/
|
||||
public function getBundleExtraFields($entity_type, $bundle) {
|
||||
// Read from the "static" cache.
|
||||
if (isset($this->bundleExtraFields[$entity_type][$bundle])) {
|
||||
return $this->bundleExtraFields[$entity_type][$bundle];
|
||||
}
|
||||
|
||||
// Read from the persistent cache.
|
||||
if ($cached = cache_get("field_info:bundle_extra:$entity_type:$bundle", 'cache_field')) {
|
||||
$this->bundleExtraFields[$entity_type][$bundle] = $cached->data;
|
||||
return $this->bundleExtraFields[$entity_type][$bundle];
|
||||
}
|
||||
|
||||
// Cache miss: read from hook_field_extra_fields(). Note: given the current
|
||||
// shape of the hook, we have no other way than collecting extra fields on
|
||||
// all bundles.
|
||||
$info = array();
|
||||
$extra = module_invoke_all('field_extra_fields');
|
||||
drupal_alter('field_extra_fields', $extra);
|
||||
// Merge in saved settings.
|
||||
if (isset($extra[$entity_type][$bundle])) {
|
||||
$info = $this->prepareExtraFields($extra[$entity_type][$bundle], $entity_type, $bundle);
|
||||
}
|
||||
|
||||
// Store in the 'static' and persistent caches.
|
||||
$this->bundleExtraFields[$entity_type][$bundle] = $info;
|
||||
cache_set("field_info:bundle_extra:$entity_type:$bundle", $info, 'cache_field');
|
||||
|
||||
return $this->bundleExtraFields[$entity_type][$bundle];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a field definition for the current run-time context.
|
||||
*
|
||||
* @param $field
|
||||
* The raw field structure as read from the database.
|
||||
*
|
||||
* @return
|
||||
* The field definition completed for the current runtime context.
|
||||
*/
|
||||
public function prepareField($field) {
|
||||
// Make sure all expected field settings are present.
|
||||
$field['settings'] += field_info_field_settings($field['type']);
|
||||
$field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
|
||||
|
||||
// Add storage details.
|
||||
$details = (array) module_invoke($field['storage']['module'], 'field_storage_details', $field);
|
||||
drupal_alter('field_storage_details', $details, $field);
|
||||
$field['storage']['details'] = $details;
|
||||
|
||||
// Populate the list of bundles using the field.
|
||||
$field['bundles'] = array();
|
||||
if (!$field['deleted']) {
|
||||
$map = $this->getFieldMap();
|
||||
if (isset($map[$field['field_name']])) {
|
||||
$field['bundles'] = $map[$field['field_name']]['bundles'];
|
||||
}
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an instance definition for the current run-time context.
|
||||
*
|
||||
* @param $instance
|
||||
* The raw instance structure as read from the database.
|
||||
* @param $field_type
|
||||
* The field type.
|
||||
*
|
||||
* @return
|
||||
* The field instance array completed for the current runtime context.
|
||||
*/
|
||||
public function prepareInstance($instance, $field_type) {
|
||||
// Make sure all expected instance settings are present.
|
||||
$instance['settings'] += field_info_instance_settings($field_type);
|
||||
|
||||
// Set a default value for the instance.
|
||||
if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && !isset($instance['default_value'])) {
|
||||
$instance['default_value'] = NULL;
|
||||
}
|
||||
|
||||
// Prepare widget settings.
|
||||
$instance['widget'] = $this->prepareInstanceWidget($instance['widget'], $field_type);
|
||||
|
||||
// Prepare display settings.
|
||||
foreach ($instance['display'] as $view_mode => $display) {
|
||||
$instance['display'][$view_mode] = $this->prepareInstanceDisplay($display, $field_type);
|
||||
}
|
||||
|
||||
// Fall back to 'hidden' for view modes configured to use custom display
|
||||
// settings, and for which the instance has no explicit settings.
|
||||
$entity_info = entity_get_info($instance['entity_type']);
|
||||
$view_modes = array_merge(array('default'), array_keys($entity_info['view modes']));
|
||||
$view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
|
||||
foreach ($view_modes as $view_mode) {
|
||||
if ($view_mode == 'default' || !empty($view_mode_settings[$view_mode]['custom_settings'])) {
|
||||
if (!isset($instance['display'][$view_mode])) {
|
||||
$instance['display'][$view_mode] = array(
|
||||
'type' => 'hidden',
|
||||
'label' => 'above',
|
||||
'settings' => array(),
|
||||
'weight' => 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares widget properties for the current run-time context.
|
||||
*
|
||||
* @param $widget
|
||||
* Widget specifications as found in $instance['widget'].
|
||||
* @param $field_type
|
||||
* The field type.
|
||||
*
|
||||
* @return
|
||||
* The widget properties completed for the current runtime context.
|
||||
*/
|
||||
public function prepareInstanceWidget($widget, $field_type) {
|
||||
$field_type_info = field_info_field_types($field_type);
|
||||
|
||||
// Fill in default values.
|
||||
$widget += array(
|
||||
'type' => $field_type_info['default_widget'],
|
||||
'settings' => array(),
|
||||
'weight' => 0,
|
||||
);
|
||||
|
||||
$widget_type_info = field_info_widget_types($widget['type']);
|
||||
// Fall back to default formatter if formatter type is not available.
|
||||
if (!$widget_type_info) {
|
||||
$widget['type'] = $field_type_info['default_widget'];
|
||||
$widget_type_info = field_info_widget_types($widget['type']);
|
||||
}
|
||||
$widget['module'] = $widget_type_info['module'];
|
||||
// Fill in default settings for the widget.
|
||||
$widget['settings'] += field_info_widget_settings($widget['type']);
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts display specifications to the current run-time context.
|
||||
*
|
||||
* @param $display
|
||||
* Display specifications as found in $instance['display']['a_view_mode'].
|
||||
* @param $field_type
|
||||
* The field type.
|
||||
*
|
||||
* @return
|
||||
* The display properties completed for the current runtime context.
|
||||
*/
|
||||
public function prepareInstanceDisplay($display, $field_type) {
|
||||
$field_type_info = field_info_field_types($field_type);
|
||||
|
||||
// Fill in default values.
|
||||
$display += array(
|
||||
'label' => 'above',
|
||||
'type' => $field_type_info['default_formatter'],
|
||||
'settings' => array(),
|
||||
'weight' => 0,
|
||||
);
|
||||
if ($display['type'] != 'hidden') {
|
||||
$formatter_type_info = field_info_formatter_types($display['type']);
|
||||
// Fall back to default formatter if formatter type is not available.
|
||||
if (!$formatter_type_info) {
|
||||
$display['type'] = $field_type_info['default_formatter'];
|
||||
$formatter_type_info = field_info_formatter_types($display['type']);
|
||||
}
|
||||
$display['module'] = $formatter_type_info['module'];
|
||||
// Fill in default settings for the formatter.
|
||||
$display['settings'] += field_info_formatter_settings($display['type']);
|
||||
}
|
||||
|
||||
return $display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares 'extra fields' for the current run-time context.
|
||||
*
|
||||
* @param $extra_fields
|
||||
* The array of extra fields, as collected in hook_field_extra_fields().
|
||||
* @param $entity_type
|
||||
* The entity type.
|
||||
* @param $bundle
|
||||
* The bundle name.
|
||||
*
|
||||
* @return
|
||||
* The list of extra fields completed for the current runtime context.
|
||||
*/
|
||||
public function prepareExtraFields($extra_fields, $entity_type, $bundle) {
|
||||
$entity_type_info = entity_get_info($entity_type);
|
||||
$bundle_settings = field_bundle_settings($entity_type, $bundle);
|
||||
$extra_fields += array('form' => array(), 'display' => array());
|
||||
|
||||
$result = array();
|
||||
// Extra fields in forms.
|
||||
foreach ($extra_fields['form'] as $name => $field_data) {
|
||||
$settings = isset($bundle_settings['extra_fields']['form'][$name]) ? $bundle_settings['extra_fields']['form'][$name] : array();
|
||||
if (isset($settings['weight'])) {
|
||||
$field_data['weight'] = $settings['weight'];
|
||||
}
|
||||
$result['form'][$name] = $field_data;
|
||||
}
|
||||
|
||||
// Extra fields in displayed entities.
|
||||
$data = $extra_fields['display'];
|
||||
foreach ($extra_fields['display'] as $name => $field_data) {
|
||||
$settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array();
|
||||
$view_modes = array_merge(array('default'), array_keys($entity_type_info['view modes']));
|
||||
foreach ($view_modes as $view_mode) {
|
||||
if (isset($settings[$view_mode])) {
|
||||
$field_data['display'][$view_mode] = $settings[$view_mode];
|
||||
}
|
||||
else {
|
||||
$field_data['display'][$view_mode] = array(
|
||||
'weight' => $field_data['weight'],
|
||||
'visible' => TRUE,
|
||||
);
|
||||
}
|
||||
}
|
||||
unset($field_data['weight']);
|
||||
$result['display'][$name] = $field_data;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@@ -5,6 +5,32 @@
|
||||
* Field Info API, providing information about available fields and field types.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the FieldInfo object for the current request.
|
||||
*
|
||||
* @return FieldInfo
|
||||
* An instance of the FieldInfo class.
|
||||
*/
|
||||
function _field_info_field_cache() {
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['field_info_field_cache'] = &drupal_static(__FUNCTION__);
|
||||
}
|
||||
$field_info = &$drupal_static_fast['field_info_field_cache'];
|
||||
|
||||
if (!isset($field_info)) {
|
||||
// @todo The registry should save the need for an explicit include, but not
|
||||
// a couple upgrade tests (DisabledNodeTypeTestCase,
|
||||
// FilterFormatUpgradePathTestCase...) break in a strange way without it.
|
||||
include_once dirname(__FILE__) . '/field.info.class.inc';
|
||||
$field_info = new FieldInfo();
|
||||
}
|
||||
|
||||
return $field_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup field_info Field Info API
|
||||
* @{
|
||||
@@ -34,7 +60,50 @@ function field_info_cache_clear() {
|
||||
entity_info_cache_clear();
|
||||
|
||||
_field_info_collate_types(TRUE);
|
||||
_field_info_collate_fields(TRUE);
|
||||
_field_info_field_cache()->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collates all information on existing fields and instances.
|
||||
*
|
||||
* Deprecated. This function is kept to ensure backwards compatibility, but has
|
||||
* a serious performance impact, and should be absolutely avoided.
|
||||
* See http://drupal.org/node/1915646.
|
||||
*
|
||||
* Use the regular field_info_*() API functions to access the information, or
|
||||
* field_info_cache_clear() to clear the cached data.
|
||||
*/
|
||||
function _field_info_collate_fields($reset = FALSE) {
|
||||
if ($reset) {
|
||||
_field_info_field_cache()->flush();
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = _field_info_field_cache();
|
||||
|
||||
// Collect fields, and build the array of IDs keyed by field_name.
|
||||
$fields = $cache->getFields();
|
||||
$field_ids = array();
|
||||
foreach ($fields as $id => $field) {
|
||||
if (!$field['deleted']) {
|
||||
$field_ids[$field['field_name']] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect extra fields for all entity types.
|
||||
$extra_fields = array();
|
||||
foreach (field_info_bundles() as $entity_type => $bundles) {
|
||||
foreach ($bundles as $bundle => $info) {
|
||||
$extra_fields[$entity_type][$bundle] = $cache->getBundleExtraFields($entity_type, $bundle);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'fields' => $fields,
|
||||
'field_ids' => $field_ids,
|
||||
'instances' => $cache->getInstances(),
|
||||
'extra_fields' => $extra_fields,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,282 +230,69 @@ function _field_info_collate_types($reset = FALSE) {
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collates all information on existing fields and instances.
|
||||
*
|
||||
* @param $reset
|
||||
* If TRUE, clear the cache. The information will be rebuilt from the
|
||||
* database next time it is needed. Defaults to FALSE.
|
||||
*
|
||||
* @return
|
||||
* If $reset is TRUE, nothing.
|
||||
* If $reset is FALSE, an array containing the following elements:
|
||||
* - fields: Array of existing fields, keyed by field ID. This element
|
||||
* lists deleted and non-deleted fields, but not inactive ones.
|
||||
* Each field has an additional element, 'bundles', which is an array
|
||||
* of all non-deleted instances of that field.
|
||||
* - field_ids: Array of field IDs, keyed by field name. This element
|
||||
* only lists non-deleted, active fields.
|
||||
* - instances: Array of existing instances, keyed by entity type, bundle
|
||||
* name and field name. This element only lists non-deleted instances
|
||||
* whose field is active.
|
||||
*/
|
||||
function _field_info_collate_fields($reset = FALSE) {
|
||||
static $info;
|
||||
|
||||
if ($reset) {
|
||||
$info = NULL;
|
||||
cache_clear_all('field_info_fields', 'cache_field');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($info)) {
|
||||
if ($cached = cache_get('field_info_fields', 'cache_field')) {
|
||||
$info = $cached->data;
|
||||
}
|
||||
else {
|
||||
$definitions = array(
|
||||
'field_ids' => field_read_fields(array(), array('include_deleted' => 1)),
|
||||
'instances' => field_read_instances(),
|
||||
);
|
||||
|
||||
// Populate 'fields' with all fields, keyed by ID.
|
||||
$info['fields'] = array();
|
||||
foreach ($definitions['field_ids'] as $key => $field) {
|
||||
$info['fields'][$key] = $definitions['field_ids'][$key] = _field_info_prepare_field($field);
|
||||
}
|
||||
|
||||
// Build an array of field IDs for non-deleted fields, keyed by name.
|
||||
$info['field_ids'] = array();
|
||||
foreach ($info['fields'] as $key => $field) {
|
||||
if (!$field['deleted']) {
|
||||
$info['field_ids'][$field['field_name']] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate 'instances'. Only non-deleted instances are considered.
|
||||
$info['instances'] = array();
|
||||
foreach (field_info_bundles() as $entity_type => $bundles) {
|
||||
foreach ($bundles as $bundle => $bundle_info) {
|
||||
$info['instances'][$entity_type][$bundle] = array();
|
||||
}
|
||||
}
|
||||
foreach ($definitions['instances'] as $instance) {
|
||||
$field = $info['fields'][$instance['field_id']];
|
||||
$instance = _field_info_prepare_instance($instance, $field);
|
||||
$info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
|
||||
// Enrich field definitions with the list of bundles where they have
|
||||
// instances. NOTE: Deleted fields in $info['field_ids'] are not
|
||||
// enriched because all of their instances are deleted, too, and
|
||||
// are thus not in $definitions['instances'].
|
||||
$info['fields'][$instance['field_id']]['bundles'][$instance['entity_type']][] = $instance['bundle'];
|
||||
}
|
||||
|
||||
// Populate 'extra_fields'.
|
||||
$extra = module_invoke_all('field_extra_fields');
|
||||
drupal_alter('field_extra_fields', $extra);
|
||||
// Merge in saved settings.
|
||||
foreach ($extra as $entity_type => $bundles) {
|
||||
foreach ($bundles as $bundle => $extra_fields) {
|
||||
$extra_fields = _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle);
|
||||
$info['extra_fields'][$entity_type][$bundle] = $extra_fields;
|
||||
}
|
||||
}
|
||||
|
||||
cache_set('field_info_fields', $info, 'cache_field');
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a field definition for the current run-time context.
|
||||
*
|
||||
* Since the field was last saved or updated, new field settings can be
|
||||
* expected.
|
||||
* The functionality has moved to the FieldInfo class. This function is kept as
|
||||
* a backwards-compatibility layer. See http://drupal.org/node/1915646.
|
||||
*
|
||||
* @param $field
|
||||
* The raw field structure as read from the database.
|
||||
* @see FieldInfo::prepareField()
|
||||
*/
|
||||
function _field_info_prepare_field($field) {
|
||||
// Make sure all expected field settings are present.
|
||||
$field['settings'] += field_info_field_settings($field['type']);
|
||||
$field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
|
||||
|
||||
// Add storage details.
|
||||
$details = (array) module_invoke($field['storage']['module'], 'field_storage_details', $field);
|
||||
drupal_alter('field_storage_details', $details, $field, $instance);
|
||||
$field['storage']['details'] = $details;
|
||||
|
||||
// Initialize the 'bundles' list.
|
||||
$field['bundles'] = array();
|
||||
|
||||
return $field;
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->prepareField($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an instance definition for the current run-time context.
|
||||
*
|
||||
* Since the instance was last saved or updated, a number of things might have
|
||||
* changed: widgets or formatters disabled, new settings expected, new view
|
||||
* modes added...
|
||||
* The functionality has moved to the FieldInfo class. This function is kept as
|
||||
* a backwards-compatibility layer. See http://drupal.org/node/1915646.
|
||||
*
|
||||
* @param $instance
|
||||
* The raw instance structure as read from the database.
|
||||
* @param $field
|
||||
* The field structure for the instance.
|
||||
*
|
||||
* @return
|
||||
* Field instance array.
|
||||
* @see FieldInfo::prepareInstance()
|
||||
*/
|
||||
function _field_info_prepare_instance($instance, $field) {
|
||||
// Make sure all expected instance settings are present.
|
||||
$instance['settings'] += field_info_instance_settings($field['type']);
|
||||
|
||||
// Set a default value for the instance.
|
||||
if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && !isset($instance['default_value'])) {
|
||||
$instance['default_value'] = NULL;
|
||||
}
|
||||
|
||||
$instance['widget'] = _field_info_prepare_instance_widget($field, $instance['widget']);
|
||||
|
||||
foreach ($instance['display'] as $view_mode => $display) {
|
||||
$instance['display'][$view_mode] = _field_info_prepare_instance_display($field, $display);
|
||||
}
|
||||
|
||||
// Fallback to 'hidden' for view modes configured to use custom display
|
||||
// settings, and for which the instance has no explicit settings.
|
||||
$entity_info = entity_get_info($instance['entity_type']);
|
||||
$view_modes = array_merge(array('default'), array_keys($entity_info['view modes']));
|
||||
$view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
|
||||
foreach ($view_modes as $view_mode) {
|
||||
if ($view_mode == 'default' || !empty($view_mode_settings[$view_mode]['custom_settings'])) {
|
||||
if (!isset($instance['display'][$view_mode])) {
|
||||
$instance['display'][$view_mode] = array(
|
||||
'type' => 'hidden',
|
||||
'label' => 'above',
|
||||
'settings' => array(),
|
||||
'weight' => 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $instance;
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->prepareInstance($instance, $field['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts display specifications to the current run-time context.
|
||||
*
|
||||
* @param $field
|
||||
* The field structure for the instance.
|
||||
* @param $display
|
||||
* Display specifications as found in
|
||||
* $instance['display']['some_view_mode'].
|
||||
* The functionality has moved to the FieldInfo class. This function is kept as
|
||||
* a backwards-compatibility layer. See http://drupal.org/node/1915646.
|
||||
*
|
||||
* @see FieldInfo::prepareInstanceDisplay()
|
||||
*/
|
||||
function _field_info_prepare_instance_display($field, $display) {
|
||||
$field_type = field_info_field_types($field['type']);
|
||||
|
||||
// Fill in default values.
|
||||
$display += array(
|
||||
'label' => 'above',
|
||||
'type' => $field_type['default_formatter'],
|
||||
'settings' => array(),
|
||||
'weight' => 0,
|
||||
);
|
||||
if ($display['type'] != 'hidden') {
|
||||
$formatter_type = field_info_formatter_types($display['type']);
|
||||
// Fallback to default formatter if formatter type is not available.
|
||||
if (!$formatter_type) {
|
||||
$display['type'] = $field_type['default_formatter'];
|
||||
$formatter_type = field_info_formatter_types($display['type']);
|
||||
}
|
||||
$display['module'] = $formatter_type['module'];
|
||||
// Fill in default settings for the formatter.
|
||||
$display['settings'] += field_info_formatter_settings($display['type']);
|
||||
}
|
||||
|
||||
return $display;
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->prepareInstanceDisplay($display, $field['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares widget specifications for the current run-time context.
|
||||
*
|
||||
* @param $field
|
||||
* The field structure for the instance.
|
||||
* @param $widget
|
||||
* Widget specifications as found in $instance['widget'].
|
||||
* The functionality has moved to the FieldInfo class. This function is kept as
|
||||
* a backwards-compatibility layer. See http://drupal.org/node/1915646.
|
||||
*
|
||||
* @see FieldInfo::prepareInstanceWidget()
|
||||
*/
|
||||
function _field_info_prepare_instance_widget($field, $widget) {
|
||||
$field_type = field_info_field_types($field['type']);
|
||||
|
||||
// Fill in default values.
|
||||
$widget += array(
|
||||
'type' => $field_type['default_widget'],
|
||||
'settings' => array(),
|
||||
'weight' => 0,
|
||||
);
|
||||
|
||||
$widget_type = field_info_widget_types($widget['type']);
|
||||
// Fallback to default formatter if formatter type is not available.
|
||||
if (!$widget_type) {
|
||||
$widget['type'] = $field_type['default_widget'];
|
||||
$widget_type = field_info_widget_types($widget['type']);
|
||||
}
|
||||
$widget['module'] = $widget_type['module'];
|
||||
// Fill in default settings for the widget.
|
||||
$widget['settings'] += field_info_widget_settings($widget['type']);
|
||||
|
||||
return $widget;
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->prepareInstanceWidget($widget, $field['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares 'extra fields' for the current run-time context.
|
||||
*
|
||||
* @param $extra_fields
|
||||
* The array of extra fields, as collected in hook_field_extra_fields().
|
||||
* @param $entity_type
|
||||
* The entity type.
|
||||
* @param $bundle
|
||||
* The bundle name.
|
||||
* The functionality has moved to the FieldInfo class. This function is kept as
|
||||
* a backwards-compatibility layer. See http://drupal.org/node/1915646.
|
||||
*
|
||||
* @see FieldInfo::prepareExtraFields()
|
||||
*/
|
||||
function _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle) {
|
||||
$entity_type_info = entity_get_info($entity_type);
|
||||
$bundle_settings = field_bundle_settings($entity_type, $bundle);
|
||||
$extra_fields += array('form' => array(), 'display' => array());
|
||||
|
||||
$result = array();
|
||||
// Extra fields in forms.
|
||||
foreach ($extra_fields['form'] as $name => $field_data) {
|
||||
$settings = isset($bundle_settings['extra_fields']['form'][$name]) ? $bundle_settings['extra_fields']['form'][$name] : array();
|
||||
if (isset($settings['weight'])) {
|
||||
$field_data['weight'] = $settings['weight'];
|
||||
}
|
||||
$result['form'][$name] = $field_data;
|
||||
}
|
||||
|
||||
// Extra fields in displayed entities.
|
||||
$data = $extra_fields['display'];
|
||||
foreach ($extra_fields['display'] as $name => $field_data) {
|
||||
$settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array();
|
||||
$view_modes = array_merge(array('default'), array_keys($entity_type_info['view modes']));
|
||||
foreach ($view_modes as $view_mode) {
|
||||
if (isset($settings[$view_mode])) {
|
||||
$field_data['display'][$view_mode] = $settings[$view_mode];
|
||||
}
|
||||
else {
|
||||
$field_data['display'][$view_mode] = array(
|
||||
'weight' => $field_data['weight'],
|
||||
'visible' => TRUE,
|
||||
);
|
||||
}
|
||||
}
|
||||
unset($field_data['weight']);
|
||||
$result['display'][$name] = $field_data;
|
||||
}
|
||||
|
||||
return $result;
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->prepareExtraFields($extra_fields, $entity_type, $bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -583,22 +439,51 @@ function field_info_bundles($entity_type = NULL) {
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a lightweight map of fields across bundles.
|
||||
*
|
||||
* The function only returns active, non deleted fields.
|
||||
*
|
||||
* @return
|
||||
* An array keyed by field name. Each value is an array with two entries:
|
||||
* - type: The field type.
|
||||
* - bundles: The bundles in which the field appears, as an array with entity
|
||||
* types as keys and the array of bundle names as values.
|
||||
*/
|
||||
function field_info_field_map() {
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->getFieldMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all field definitions.
|
||||
*
|
||||
* Use of this function should be avoided when possible, since it loads and
|
||||
* statically caches a potentially large array of information. Use
|
||||
* field_info_field_map() instead.
|
||||
*
|
||||
* When iterating over the fields present in a given bundle after a call to
|
||||
* field_info_instances($entity_type, $bundle), it is recommended to use
|
||||
* field_info_field() on each individual field instead.
|
||||
*
|
||||
* @return
|
||||
* An array of field definitions, keyed by field name. Each field has an
|
||||
* additional property, 'bundles', which is an array of all the bundles to
|
||||
* which this field belongs keyed by entity type.
|
||||
*
|
||||
* @see field_info_field_map()
|
||||
*/
|
||||
function field_info_fields() {
|
||||
$cache = _field_info_field_cache();
|
||||
$info = $cache->getFields();
|
||||
|
||||
$fields = array();
|
||||
$info = _field_info_collate_fields();
|
||||
foreach ($info['fields'] as $key => $field) {
|
||||
foreach ($info as $key => $field) {
|
||||
if (!$field['deleted']) {
|
||||
$fields[$field['field_name']] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
@@ -620,10 +505,8 @@ function field_info_fields() {
|
||||
* @see field_info_field_by_id()
|
||||
*/
|
||||
function field_info_field($field_name) {
|
||||
$info = _field_info_collate_fields();
|
||||
if (isset($info['field_ids'][$field_name])) {
|
||||
return $info['fields'][$info['field_ids'][$field_name]];
|
||||
}
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->getField($field_name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,17 +524,19 @@ function field_info_field($field_name) {
|
||||
* @see field_info_field()
|
||||
*/
|
||||
function field_info_field_by_id($field_id) {
|
||||
$info = _field_info_collate_fields();
|
||||
if (isset($info['fields'][$field_id])) {
|
||||
return $info['fields'][$field_id];
|
||||
}
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->getFieldById($field_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the same data as field_info_field_by_id() for every field.
|
||||
*
|
||||
* This function is typically used when handling all fields of some entities
|
||||
* to avoid thousands of calls to field_info_field_by_id().
|
||||
* Use of this function should be avoided when possible, since it loads and
|
||||
* statically caches a potentially large array of information.
|
||||
*
|
||||
* When iterating over the fields present in a given bundle after a call to
|
||||
* field_info_instances($entity_type, $bundle), it is recommended to use
|
||||
* field_info_field() on each individual field instead.
|
||||
*
|
||||
* @return
|
||||
* An array, each key is a field ID and the values are field arrays as
|
||||
@@ -662,41 +547,57 @@ function field_info_field_by_id($field_id) {
|
||||
* @see field_info_field_by_id()
|
||||
*/
|
||||
function field_info_field_by_ids() {
|
||||
$info = _field_info_collate_fields();
|
||||
return $info['fields'];
|
||||
$cache = _field_info_field_cache();
|
||||
return $cache->getFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about field instances.
|
||||
*
|
||||
* Use of this function to retrieve instances across separate bundles (i.e.
|
||||
* when the $bundle parameter is NULL) should be avoided when possible, since
|
||||
* it loads and statically caches a potentially large array of information. Use
|
||||
* field_info_field_map() instead.
|
||||
*
|
||||
* When retrieving the instances of a specific bundle (i.e. when both
|
||||
* $entity_type and $bundle_name are provided), the function also populates a
|
||||
* static cache with the corresponding field definitions, allowing fast
|
||||
* retrieval of field_info_field() later in the request.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type for which to return instances.
|
||||
* (optional) The entity type for which to return instances.
|
||||
* @param $bundle_name
|
||||
* The bundle name for which to return instances.
|
||||
* (optional) The bundle name for which to return instances. If $entity_type
|
||||
* is NULL, the $bundle_name parameter is ignored.
|
||||
*
|
||||
* @return
|
||||
* If $entity_type is not set, return all instances keyed by entity type and
|
||||
* bundle name. If $entity_type is set, return all instances for that entity
|
||||
* type, keyed by bundle name. If $entity_type and $bundle_name are set, return
|
||||
* all instances for that bundle.
|
||||
*
|
||||
* @see field_info_field_map()
|
||||
*/
|
||||
function field_info_instances($entity_type = NULL, $bundle_name = NULL) {
|
||||
$info = _field_info_collate_fields();
|
||||
$cache = _field_info_field_cache();
|
||||
|
||||
if (isset($entity_type) && isset($bundle_name)) {
|
||||
return isset($info['instances'][$entity_type][$bundle_name]) ? $info['instances'][$entity_type][$bundle_name] : array();
|
||||
if (!isset($entity_type)) {
|
||||
return $cache->getInstances();
|
||||
}
|
||||
elseif (isset($entity_type)) {
|
||||
return isset($info['instances'][$entity_type]) ? $info['instances'][$entity_type] : array();
|
||||
}
|
||||
else {
|
||||
return $info['instances'];
|
||||
if (!isset($bundle_name)) {
|
||||
return $cache->getInstances($entity_type);
|
||||
}
|
||||
|
||||
return $cache->getBundleInstances($entity_type, $bundle_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of instance data for a specific field and bundle.
|
||||
*
|
||||
* The function populates a static cache with all fields and instances used in
|
||||
* the bundle, allowing fast retrieval of field_info_field() or
|
||||
* field_info_instance() later in the request.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type for the instance.
|
||||
* @param $field_name
|
||||
@@ -709,9 +610,10 @@ function field_info_instances($entity_type = NULL, $bundle_name = NULL) {
|
||||
* NULL if the instance does not exist.
|
||||
*/
|
||||
function field_info_instance($entity_type, $field_name, $bundle_name) {
|
||||
$info = _field_info_collate_fields();
|
||||
if (isset($info['instances'][$entity_type][$bundle_name][$field_name])) {
|
||||
return $info['instances'][$entity_type][$bundle_name][$field_name];
|
||||
$cache = _field_info_field_cache();
|
||||
$info = $cache->getBundleInstances($entity_type, $bundle_name);
|
||||
if (isset($info[$field_name])) {
|
||||
return $info[$field_name];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,11 +671,10 @@ function field_info_instance($entity_type, $field_name, $bundle_name) {
|
||||
* The array of pseudo-field elements in the bundle.
|
||||
*/
|
||||
function field_info_extra_fields($entity_type, $bundle, $context) {
|
||||
$info = _field_info_collate_fields();
|
||||
if (isset($info['extra_fields'][$entity_type][$bundle][$context])) {
|
||||
return $info['extra_fields'][$entity_type][$bundle][$context];
|
||||
}
|
||||
return array();
|
||||
$cache = _field_info_field_cache();
|
||||
$info = $cache->getBundleExtraFields($entity_type, $bundle);
|
||||
|
||||
return isset($info[$context]) ? $info[$context] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -459,6 +459,13 @@ function field_update_7002() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the FieldInfo class to the class registry.
|
||||
*/
|
||||
function field_update_7003() {
|
||||
// Empty update to force a rebuild of the registry.
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-7.x-extra".
|
||||
*/
|
||||
|
@@ -873,7 +873,8 @@ function field_view_field($entity_type, $entity, $field_name, $display = array()
|
||||
if ($field = field_info_field($field_name)) {
|
||||
if (is_array($display)) {
|
||||
// When using custom display settings, fill in default values.
|
||||
$display = _field_info_prepare_instance_display($field, $display);
|
||||
$cache = _field_info_field_cache();
|
||||
$display = $cache->prepareInstanceDisplay($display, $field["type"]);
|
||||
}
|
||||
|
||||
// Hook invocations are done through the _field_invoke() functions in
|
||||
@@ -1197,7 +1198,7 @@ function _element_validate_integer($element, &$form_state) {
|
||||
* Use element_validate_integer_positive() instead.
|
||||
*
|
||||
* @deprecated
|
||||
* @see element_validate_number_positive()
|
||||
* @see element_validate_integer_positive()
|
||||
*/
|
||||
function _element_validate_integer_positive($element, &$form_state) {
|
||||
element_validate_integer_positive($element, $form_state);
|
||||
|
@@ -7,8 +7,8 @@ dependencies[] = field
|
||||
files[] = field_sql_storage.test
|
||||
required = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
@@ -324,11 +324,14 @@ function field_sql_storage_field_storage_delete_field($field) {
|
||||
* Implements hook_field_storage_load().
|
||||
*/
|
||||
function field_sql_storage_field_storage_load($entity_type, $entities, $age, $fields, $options) {
|
||||
$field_info = field_info_field_by_ids();
|
||||
$load_current = $age == FIELD_LOAD_CURRENT;
|
||||
|
||||
foreach ($fields as $field_id => $ids) {
|
||||
$field = $field_info[$field_id];
|
||||
// By the time this hook runs, the relevant field definitions have been
|
||||
// populated and cached in FieldInfo, so calling field_info_field_by_id()
|
||||
// on each field individually is more efficient than loading all fields in
|
||||
// memory upfront with field_info_field_by_ids().
|
||||
$field = field_info_field_by_id($field_id);
|
||||
$field_name = $field['field_name'];
|
||||
$table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
|
||||
|
||||
|
@@ -7,8 +7,8 @@ dependencies[] = field
|
||||
dependencies[] = options
|
||||
files[] = tests/list.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
@@ -5,8 +5,8 @@ package = Testing
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
@@ -6,8 +6,8 @@ core = 7.x
|
||||
dependencies[] = field
|
||||
files[] = number.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
@@ -6,8 +6,8 @@ core = 7.x
|
||||
dependencies[] = field
|
||||
files[] = options.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
@@ -7,8 +7,8 @@ dependencies[] = field
|
||||
files[] = text.test
|
||||
required = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
@@ -85,12 +85,28 @@ class FieldAttachTestCase extends FieldTestCase {
|
||||
}
|
||||
parent::setUp($modules);
|
||||
|
||||
$this->field_name = drupal_strtolower($this->randomName() . '_field_name');
|
||||
$this->field = array('field_name' => $this->field_name, 'type' => 'test_field', 'cardinality' => 4);
|
||||
$this->field = field_create_field($this->field);
|
||||
$this->field_id = $this->field['id'];
|
||||
$this->instance = array(
|
||||
'field_name' => $this->field_name,
|
||||
$this->createFieldWithInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a field and an instance of it.
|
||||
*
|
||||
* @param string $suffix
|
||||
* (optional) A string that should only contain characters that are valid in
|
||||
* PHP variable names as well.
|
||||
*/
|
||||
function createFieldWithInstance($suffix = '') {
|
||||
$field_name = 'field_name' . $suffix;
|
||||
$field = 'field' . $suffix;
|
||||
$field_id = 'field_id' . $suffix;
|
||||
$instance = 'instance' . $suffix;
|
||||
|
||||
$this->$field_name = drupal_strtolower($this->randomName() . '_field_name' . $suffix);
|
||||
$this->$field = array('field_name' => $this->$field_name, 'type' => 'test_field', 'cardinality' => 4);
|
||||
$this->$field = field_create_field($this->$field);
|
||||
$this->$field_id = $this->{$field}['id'];
|
||||
$this->$instance = array(
|
||||
'field_name' => $this->$field_name,
|
||||
'entity_type' => 'test_entity',
|
||||
'bundle' => 'test_bundle',
|
||||
'label' => $this->randomName() . '_label',
|
||||
@@ -107,7 +123,7 @@ class FieldAttachTestCase extends FieldTestCase {
|
||||
)
|
||||
)
|
||||
);
|
||||
field_create_instance($this->instance);
|
||||
field_create_instance($this->$instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,13 +657,18 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
* Test field_attach_view() and field_attach_prepare_view().
|
||||
*/
|
||||
function testFieldAttachView() {
|
||||
$this->createFieldWithInstance('_2');
|
||||
|
||||
$entity_type = 'test_entity';
|
||||
$entity_init = field_test_create_stub_entity();
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$options = array('field_name' => $this->field_name_2);
|
||||
|
||||
// Populate values to be displayed.
|
||||
$values = $this->_generateTestFieldValues($this->field['cardinality']);
|
||||
$entity_init->{$this->field_name}[$langcode] = $values;
|
||||
$values_2 = $this->_generateTestFieldValues($this->field_2['cardinality']);
|
||||
$entity_init->{$this->field_name_2}[$langcode] = $values_2;
|
||||
|
||||
// Simple formatter, label displayed.
|
||||
$entity = clone($entity_init);
|
||||
@@ -662,15 +683,47 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
),
|
||||
);
|
||||
field_update_instance($this->instance);
|
||||
$formatter_setting_2 = $this->randomName();
|
||||
$this->instance_2['display'] = array(
|
||||
'full' => array(
|
||||
'label' => 'above',
|
||||
'type' => 'field_test_default',
|
||||
'settings' => array(
|
||||
'test_formatter_setting' => $formatter_setting_2,
|
||||
)
|
||||
),
|
||||
);
|
||||
field_update_instance($this->instance_2);
|
||||
// View all fields.
|
||||
field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
|
||||
$entity->content = field_attach_view($entity_type, $entity, 'full');
|
||||
$output = drupal_render($entity->content);
|
||||
$this->content = $output;
|
||||
$this->assertRaw($this->instance['label'], "Label is displayed.");
|
||||
$this->assertRaw($this->instance['label'], "First field's label is displayed.");
|
||||
foreach ($values as $delta => $value) {
|
||||
$this->content = $output;
|
||||
$this->assertRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
|
||||
}
|
||||
$this->assertRaw($this->instance_2['label'], "Second field's label is displayed.");
|
||||
foreach ($values_2 as $delta => $value) {
|
||||
$this->content = $output;
|
||||
$this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
|
||||
}
|
||||
// View single field (the second field).
|
||||
field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full', $langcode, $options);
|
||||
$entity->content = field_attach_view($entity_type, $entity, 'full', $langcode, $options);
|
||||
$output = drupal_render($entity->content);
|
||||
$this->content = $output;
|
||||
$this->assertNoRaw($this->instance['label'], "First field's label is not displayed.");
|
||||
foreach ($values as $delta => $value) {
|
||||
$this->content = $output;
|
||||
$this->assertNoRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
|
||||
}
|
||||
$this->assertRaw($this->instance_2['label'], "Second field's label is displayed.");
|
||||
foreach ($values_2 as $delta => $value) {
|
||||
$this->content = $output;
|
||||
$this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
|
||||
}
|
||||
|
||||
// Label hidden.
|
||||
$entity = clone($entity_init);
|
||||
@@ -697,7 +750,7 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
$this->content = $output;
|
||||
$this->assertNoRaw($this->instance['label'], "Hidden field: label is not displayed.");
|
||||
foreach ($values as $delta => $value) {
|
||||
$this->assertNoRaw($value['value'], "Hidden field: value $delta is not displayed.");
|
||||
$this->assertNoRaw("$formatter_setting|{$value['value']}", "Hidden field: value $delta is not displayed.");
|
||||
}
|
||||
|
||||
// Multiple formatter.
|
||||
@@ -907,11 +960,13 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
* hook_field_validate.
|
||||
*/
|
||||
function testFieldAttachValidate() {
|
||||
$this->createFieldWithInstance('_2');
|
||||
|
||||
$entity_type = 'test_entity';
|
||||
$entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
|
||||
$langcode = LANGUAGE_NONE;
|
||||
|
||||
// Set up values to generate errors
|
||||
// Set up all but one values of the first field to generate errors.
|
||||
$values = array();
|
||||
for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
|
||||
$values[$delta]['value'] = -1;
|
||||
@@ -920,6 +975,14 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
$values[1]['value'] = 1;
|
||||
$entity->{$this->field_name}[$langcode] = $values;
|
||||
|
||||
// Set up all values of the second field to generate errors.
|
||||
$values_2 = array();
|
||||
for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
|
||||
$values_2[$delta]['value'] = -1;
|
||||
}
|
||||
$entity->{$this->field_name_2}[$langcode] = $values_2;
|
||||
|
||||
// Validate all fields.
|
||||
try {
|
||||
field_attach_validate($entity_type, $entity);
|
||||
}
|
||||
@@ -929,26 +992,57 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
|
||||
foreach ($values as $delta => $value) {
|
||||
if ($value['value'] != 1) {
|
||||
$this->assertIdentical($errors[$this->field_name][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on value $delta");
|
||||
$this->assertEqual(count($errors[$this->field_name][$langcode][$delta]), 1, "Only one error set on value $delta");
|
||||
$this->assertIdentical($errors[$this->field_name][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on first field's value $delta");
|
||||
$this->assertEqual(count($errors[$this->field_name][$langcode][$delta]), 1, "Only one error set on first field's value $delta");
|
||||
unset($errors[$this->field_name][$langcode][$delta]);
|
||||
}
|
||||
else {
|
||||
$this->assertFalse(isset($errors[$this->field_name][$langcode][$delta]), "No error set on value $delta");
|
||||
$this->assertFalse(isset($errors[$this->field_name][$langcode][$delta]), "No error set on first field's value $delta");
|
||||
}
|
||||
}
|
||||
$this->assertEqual(count($errors[$this->field_name][$langcode]), 0, 'No extraneous errors set');
|
||||
foreach ($values_2 as $delta => $value) {
|
||||
$this->assertIdentical($errors[$this->field_name_2][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on second field's value $delta");
|
||||
$this->assertEqual(count($errors[$this->field_name_2][$langcode][$delta]), 1, "Only one error set on second field's value $delta");
|
||||
unset($errors[$this->field_name_2][$langcode][$delta]);
|
||||
}
|
||||
$this->assertEqual(count($errors[$this->field_name][$langcode]), 0, 'No extraneous errors set for first field');
|
||||
$this->assertEqual(count($errors[$this->field_name_2][$langcode]), 0, 'No extraneous errors set for second field');
|
||||
|
||||
// Validate a single field.
|
||||
$options = array('field_name' => $this->field_name_2);
|
||||
try {
|
||||
field_attach_validate($entity_type, $entity, $options);
|
||||
}
|
||||
catch (FieldValidationException $e) {
|
||||
$errors = $e->errors;
|
||||
}
|
||||
|
||||
foreach ($values_2 as $delta => $value) {
|
||||
$this->assertIdentical($errors[$this->field_name_2][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on second field's value $delta");
|
||||
$this->assertEqual(count($errors[$this->field_name_2][$langcode][$delta]), 1, "Only one error set on second field's value $delta");
|
||||
unset($errors[$this->field_name_2][$langcode][$delta]);
|
||||
}
|
||||
$this->assertFalse(isset($errors[$this->field_name]), 'No validation errors are set for the first field, despite it having errors');
|
||||
$this->assertEqual(count($errors[$this->field_name_2][$langcode]), 0, 'No extraneous errors set for second field');
|
||||
|
||||
// Check that cardinality is validated.
|
||||
$entity->{$this->field_name}[$langcode] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
|
||||
$entity->{$this->field_name_2}[$langcode] = $this->_generateTestFieldValues($this->field_2['cardinality'] + 1);
|
||||
// When validating all fields.
|
||||
try {
|
||||
field_attach_validate($entity_type, $entity);
|
||||
}
|
||||
catch (FieldValidationException $e) {
|
||||
$errors = $e->errors;
|
||||
}
|
||||
$this->assertEqual($errors[$this->field_name][$langcode][0][0]['error'], 'field_cardinality', t('Cardinality validation failed.'));
|
||||
|
||||
$this->assertEqual($errors[$this->field_name_2][$langcode][0][0]['error'], 'field_cardinality', 'Cardinality validation failed.');
|
||||
// When validating a single field (the second field).
|
||||
try {
|
||||
field_attach_validate($entity_type, $entity, $options);
|
||||
}
|
||||
catch (FieldValidationException $e) {
|
||||
$errors = $e->errors;
|
||||
}
|
||||
$this->assertEqual($errors[$this->field_name_2][$langcode][0][0]['error'], 'field_cardinality', 'Cardinality validation failed.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -958,34 +1052,59 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
* widgets show up.
|
||||
*/
|
||||
function testFieldAttachForm() {
|
||||
$this->createFieldWithInstance('_2');
|
||||
|
||||
$entity_type = 'test_entity';
|
||||
$entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
|
||||
$langcode = LANGUAGE_NONE;
|
||||
|
||||
// When generating form for all fields.
|
||||
$form = array();
|
||||
$form_state = form_state_defaults();
|
||||
field_attach_form($entity_type, $entity, $form, $form_state);
|
||||
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance['label'], "Form title is {$this->instance['label']}");
|
||||
$this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance['label'], "First field's form title is {$this->instance['label']}");
|
||||
$this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2['label'], "Second field's form title is {$this->instance_2['label']}");
|
||||
for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
|
||||
// field_test_widget uses 'textfield'
|
||||
$this->assertEqual($form[$this->field_name][$langcode][$delta]['value']['#type'], 'textfield', "Form delta $delta widget is textfield");
|
||||
}
|
||||
$this->assertEqual($form[$this->field_name][$langcode][$delta]['value']['#type'], 'textfield', "First field's form delta $delta widget is textfield");
|
||||
}
|
||||
for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
|
||||
// field_test_widget uses 'textfield'
|
||||
$this->assertEqual($form[$this->field_name_2][$langcode][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield");
|
||||
}
|
||||
|
||||
// When generating form for a single field (the second field).
|
||||
$options = array('field_name' => $this->field_name_2);
|
||||
$form = array();
|
||||
$form_state = form_state_defaults();
|
||||
field_attach_form($entity_type, $entity, $form, $form_state, NULL, $options);
|
||||
|
||||
$this->assertFalse(isset($form[$this->field_name]), 'The first field does not exist in the form');
|
||||
$this->assertEqual($form[$this->field_name_2][$langcode]['#title'], $this->instance_2['label'], "Second field's form title is {$this->instance_2['label']}");
|
||||
for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
|
||||
// field_test_widget uses 'textfield'
|
||||
$this->assertEqual($form[$this->field_name_2][$langcode][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test field_attach_submit().
|
||||
*/
|
||||
function testFieldAttachSubmit() {
|
||||
$entity_type = 'test_entity';
|
||||
$entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
|
||||
$this->createFieldWithInstance('_2');
|
||||
|
||||
// Build the form.
|
||||
$entity_type = 'test_entity';
|
||||
$entity_init = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
|
||||
$langcode = LANGUAGE_NONE;
|
||||
|
||||
// Build the form for all fields.
|
||||
$form = array();
|
||||
$form_state = form_state_defaults();
|
||||
field_attach_form($entity_type, $entity, $form, $form_state);
|
||||
field_attach_form($entity_type, $entity_init, $form, $form_state);
|
||||
|
||||
// Simulate incoming values.
|
||||
// First field.
|
||||
$values = array();
|
||||
$weights = array();
|
||||
for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
|
||||
@@ -999,22 +1118,59 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
||||
}
|
||||
// Leave an empty value. 'field_test' fields are empty if empty().
|
||||
$values[1]['value'] = 0;
|
||||
|
||||
$langcode = LANGUAGE_NONE;
|
||||
// Second field.
|
||||
$values_2 = array();
|
||||
$weights_2 = array();
|
||||
for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
|
||||
$values_2[$delta]['value'] = mt_rand(1, 127);
|
||||
// Assign random weight.
|
||||
do {
|
||||
$weight = mt_rand(0, $this->field_2['cardinality']);
|
||||
} while (in_array($weight, $weights_2));
|
||||
$weights_2[$delta] = $weight;
|
||||
$values_2[$delta]['_weight'] = $weight;
|
||||
}
|
||||
// Leave an empty value. 'field_test' fields are empty if empty().
|
||||
$values_2[1]['value'] = 0;
|
||||
// Pretend the form has been built.
|
||||
drupal_prepare_form('field_test_entity_form', $form, $form_state);
|
||||
drupal_process_form('field_test_entity_form', $form, $form_state);
|
||||
$form_state['values'][$this->field_name][$langcode] = $values;
|
||||
$form_state['values'][$this->field_name_2][$langcode] = $values_2;
|
||||
|
||||
// Call field_attach_submit() for all fields.
|
||||
$entity = clone($entity_init);
|
||||
field_attach_submit($entity_type, $entity, $form, $form_state);
|
||||
|
||||
asort($weights);
|
||||
asort($weights_2);
|
||||
$expected_values = array();
|
||||
$expected_values_2 = array();
|
||||
foreach ($weights as $key => $value) {
|
||||
if ($key != 1) {
|
||||
$expected_values[] = array('value' => $values[$key]['value']);
|
||||
}
|
||||
}
|
||||
$this->assertIdentical($entity->{$this->field_name}[$langcode], $expected_values, 'Submit filters empty values');
|
||||
foreach ($weights_2 as $key => $value) {
|
||||
if ($key != 1) {
|
||||
$expected_values_2[] = array('value' => $values_2[$key]['value']);
|
||||
}
|
||||
}
|
||||
$this->assertIdentical($entity->{$this->field_name_2}[$langcode], $expected_values_2, 'Submit filters empty values');
|
||||
|
||||
// Call field_attach_submit() for a single field (the second field).
|
||||
$options = array('field_name' => $this->field_name_2);
|
||||
$entity = clone($entity_init);
|
||||
field_attach_submit($entity_type, $entity, $form, $form_state, $options);
|
||||
$expected_values_2 = array();
|
||||
foreach ($weights_2 as $key => $value) {
|
||||
if ($key != 1) {
|
||||
$expected_values_2[] = array('value' => $values_2[$key]['value']);
|
||||
}
|
||||
}
|
||||
$this->assertFalse(isset($entity->{$this->field_name}), 'The first field does not exist in the entity object');
|
||||
$this->assertIdentical($entity->{$this->field_name_2}[$langcode], $expected_values_2, 'Submit filters empty values');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,6 +1300,16 @@ class FieldInfoTestCase extends FieldTestCase {
|
||||
$this->assertIdentical($instances, $expected, "field_info_instances('user') returns " . var_export($expected, TRUE) . '.');
|
||||
$instances = field_info_instances('user', 'user');
|
||||
$this->assertIdentical($instances, array(), "field_info_instances('user', 'user') returns an empty array.");
|
||||
|
||||
// Test that querying for invalid entity types does not add entries in the
|
||||
// list returned by field_info_instances().
|
||||
field_info_cache_clear();
|
||||
field_info_instances('invalid_entity', 'invalid_bundle');
|
||||
// Simulate new request by clearing static caches.
|
||||
drupal_static_reset();
|
||||
field_info_instances('invalid_entity', 'invalid_bundle');
|
||||
$instances = field_info_instances();
|
||||
$this->assertFalse(isset($instances['invalid_entity']), 'field_info_instances() does not contain entries for the invalid entity type that was queried before');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1253,6 +1419,80 @@ class FieldInfoTestCase extends FieldTestCase {
|
||||
$this->assertNull(field_info_instance('comment', 'field', 'comment_node_article'), t('No instances are returned on disabled entity types.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test field_info_field_map().
|
||||
*/
|
||||
function testFieldMap() {
|
||||
// We will overlook fields created by the 'standard' install profile.
|
||||
$exclude = field_info_field_map();
|
||||
|
||||
// Create a new bundle for 'test_entity' entity type.
|
||||
field_test_create_bundle('test_bundle_2');
|
||||
|
||||
// Create a couple fields.
|
||||
$fields = array(
|
||||
array(
|
||||
'field_name' => 'field_1',
|
||||
'type' => 'test_field',
|
||||
),
|
||||
array(
|
||||
'field_name' => 'field_2',
|
||||
'type' => 'hidden_test_field',
|
||||
),
|
||||
);
|
||||
foreach ($fields as $field) {
|
||||
field_create_field($field);
|
||||
}
|
||||
|
||||
// Create a couple instances.
|
||||
$instances = array(
|
||||
array(
|
||||
'field_name' => 'field_1',
|
||||
'entity_type' => 'test_entity',
|
||||
'bundle' => 'test_bundle',
|
||||
),
|
||||
array(
|
||||
'field_name' => 'field_1',
|
||||
'entity_type' => 'test_entity',
|
||||
'bundle' => 'test_bundle_2',
|
||||
),
|
||||
array(
|
||||
'field_name' => 'field_2',
|
||||
'entity_type' => 'test_entity',
|
||||
'bundle' => 'test_bundle',
|
||||
),
|
||||
array(
|
||||
'field_name' => 'field_2',
|
||||
'entity_type' => 'test_cacheable_entity',
|
||||
'bundle' => 'test_bundle',
|
||||
),
|
||||
);
|
||||
foreach ($instances as $instance) {
|
||||
field_create_instance($instance);
|
||||
}
|
||||
|
||||
$expected = array(
|
||||
'field_1' => array(
|
||||
'type' => 'test_field',
|
||||
'bundles' => array(
|
||||
'test_entity' => array('test_bundle', 'test_bundle_2'),
|
||||
),
|
||||
),
|
||||
'field_2' => array(
|
||||
'type' => 'hidden_test_field',
|
||||
'bundles' => array(
|
||||
'test_entity' => array('test_bundle'),
|
||||
'test_cacheable_entity' => array('test_bundle'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Check that the field map is correct.
|
||||
$map = field_info_field_map();
|
||||
$map = array_diff_key($map, $exclude);
|
||||
$this->assertEqual($map, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the field_info settings convenience functions work.
|
||||
*/
|
||||
@@ -1277,6 +1517,31 @@ class FieldInfoTestCase extends FieldTestCase {
|
||||
$this->assertIdentical(field_info_formatter_settings($type), $data['settings'], "field_info_formatter_settings returns {$type}'s formatter settings");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the field info cache can be built correctly.
|
||||
*/
|
||||
function testFieldInfoCache() {
|
||||
// Create a test field and ensure it's in the array returned by
|
||||
// field_info_fields().
|
||||
$field_name = drupal_strtolower($this->randomName());
|
||||
$field = array(
|
||||
'field_name' => $field_name,
|
||||
'type' => 'test_field',
|
||||
);
|
||||
field_create_field($field);
|
||||
$fields = field_info_fields();
|
||||
$this->assertTrue(isset($fields[$field_name]), 'The test field is initially found in the array returned by field_info_fields().');
|
||||
|
||||
// Now rebuild the field info cache, and set a variable which will cause
|
||||
// the cache to be cleared while it's being rebuilt; see
|
||||
// field_test_entity_info(). Ensure the test field is still in the returned
|
||||
// array.
|
||||
field_info_cache_clear();
|
||||
variable_set('field_test_clear_info_cache_in_hook_entity_info', TRUE);
|
||||
$fields = field_info_fields();
|
||||
$this->assertTrue(isset($fields[$field_name]), 'The test field is found in the array returned by field_info_fields() even if its cache is cleared while being rebuilt.');
|
||||
}
|
||||
}
|
||||
|
||||
class FieldFormTestCase extends FieldTestCase {
|
||||
@@ -2178,6 +2443,41 @@ class FieldCrudTestCase extends FieldTestCase {
|
||||
$this->assertTrue($field_definition < $field, t('The field was properly read.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests reading field definitions.
|
||||
*/
|
||||
function testReadFields() {
|
||||
$field_definition = array(
|
||||
'field_name' => 'field_1',
|
||||
'type' => 'test_field',
|
||||
);
|
||||
field_create_field($field_definition);
|
||||
|
||||
// Check that 'single column' criteria works.
|
||||
$fields = field_read_fields(array('field_name' => $field_definition['field_name']));
|
||||
$this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
|
||||
|
||||
// Check that 'multi column' criteria works.
|
||||
$fields = field_read_fields(array('field_name' => $field_definition['field_name'], 'type' => $field_definition['type']));
|
||||
$this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
|
||||
$fields = field_read_fields(array('field_name' => $field_definition['field_name'], 'type' => 'foo'));
|
||||
$this->assertTrue(empty($fields), 'No field was found.');
|
||||
|
||||
// Create an instance of the field.
|
||||
$instance_definition = array(
|
||||
'field_name' => $field_definition['field_name'],
|
||||
'entity_type' => 'test_entity',
|
||||
'bundle' => 'test_bundle',
|
||||
);
|
||||
field_create_instance($instance_definition);
|
||||
|
||||
// Check that criteria spanning over the field_config_instance table work.
|
||||
$fields = field_read_fields(array('entity_type' => $instance_definition['entity_type'], 'bundle' => $instance_definition['bundle']));
|
||||
$this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
|
||||
$fields = field_read_fields(array('entity_type' => $instance_definition['entity_type'], 'field_name' => $instance_definition['field_name']));
|
||||
$this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation of indexes on data column.
|
||||
*/
|
||||
|
@@ -9,6 +9,12 @@
|
||||
* Implements hook_entity_info().
|
||||
*/
|
||||
function field_test_entity_info() {
|
||||
// If requested, clear the field cache while this hook is being called. See
|
||||
// testFieldInfoCache().
|
||||
if (variable_get('field_test_clear_info_cache_in_hook_entity_info', FALSE)) {
|
||||
field_info_cache_clear();
|
||||
}
|
||||
|
||||
$bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle')));
|
||||
$test_entity_modes = array(
|
||||
'full' => array(
|
||||
|
@@ -6,8 +6,8 @@ files[] = field_test.entity.inc
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-03-07
|
||||
version = "7.21"
|
||||
; Information added by drupal.org packaging script on 2013-04-03
|
||||
version = "7.22"
|
||||
project = "drupal"
|
||||
datestamp = "1362616996"
|
||||
datestamp = "1365027012"
|
||||
|
||||
|
Reference in New Issue
Block a user