- <?php
- * @file
- * Attach custom data fields to Backdrop entities.
- */
-
- * Load all public Field API functions. Backdrop currently has no
- * mechanism for auto-loading core APIs, so we have to load them on
- * every page request.
- */
- require_once BACKDROP_ROOT . '/core/modules/field/field.crud.inc';
- require_once BACKDROP_ROOT . '/core/modules/field/field.default.inc';
- require_once BACKDROP_ROOT . '/core/modules/field/field.info.inc';
- require_once BACKDROP_ROOT . '/core/modules/field/field.multilingual.inc';
- require_once BACKDROP_ROOT . '/core/modules/field/field.attach.inc';
- require_once BACKDROP_ROOT . '/core/modules/field/field.form.inc';
-
- * @defgroup field Field API
- * @{
- * Attach custom data fields to Backdrop entities.
- *
- * The Field API allows custom data fields to be attached to Backdrop
- * entities and takes care of storing, loading, editing, and rendering
- * field data. Any entity type (node, user, etc.) can use the Field
- * API to make itself "fieldable" and thus allow fields to be attached
- * to it. Other modules can provide a user interface for managing custom
- * fields via a web browser as well as a wide and flexible variety of
- * data type, form element, and display format capabilities.
- *
- * The Field API defines two primary data structures, Field and
- * Instance, and the concept of a Bundle. A Field defines a
- * particular type of data that can be attached to entities. A Field
- * Instance is a Field attached to a single Bundle. A Bundle is a set
- * of fields that are treated as a group by the Field Attach API and
- * is related to a single fieldable entity type.
- *
- * For example, suppose a site administrator wants Post nodes to
- * have a subtitle and photo. Using the Field API or Field UI module,
- * the administrator creates a field named 'subtitle' of type 'text'
- * and a field named 'photo' of type 'image'. The administrator
- * (again, via a UI) creates two Field Instances, one attaching the
- * field 'subtitle' to the 'node' bundle 'post' and one attaching
- * the field 'photo' to the 'node' bundle 'post'. When the node
- * system uses the Field Attach API to load all fields for an Post
- * node, it passes the node's entity type (which is 'node') and
- * content type (which is 'post') as the node's bundle.
- * field_attach_load() then loads the 'subtitle' and 'photo' fields
- * because they are both attached to the 'node' bundle 'post'.
- *
- * Field definitions are represented as an array of key/value pairs.
- *
- * array $field:
- * - id (integer, read-only): The primary identifier of the field. It is
- * assigned automatically by field_create_field().
- * - field_name (string): The name of the field. Each field name is unique
- * within Field API. When a field is attached to an entity, the field's data
- * is stored in $entity->$field_name. Maximum length is 32 characters.
- * - type (string): The type of the field, such as 'text' or 'image'. Field
- * types are defined by modules that implement hook_field_info().
- * - entity_types (array): The array of entity types that can hold instances
- * of this field. If empty or not specified, the field can have instances
- * in any entity type.
- * - cardinality (integer): The number of values the field can hold. Legal
- * values are any positive integer or FIELD_CARDINALITY_UNLIMITED.
- * - translatable (integer): Whether the field is translatable.
- * - locked (integer): Whether or not the field is available for editing. If
- * TRUE, users can't change field settings or create new instances of the
- * field in the UI. Defaults to FALSE.
- * - module (string, read-only): The name of the module that implements the
- * field type.
- * - active (integer, read-only): TRUE if the module that implements the field
- * type is currently enabled, FALSE otherwise.
- * - deleted (integer, read-only): TRUE if this field has been deleted, FALSE
- * otherwise. Deleted fields are ignored by the Field Attach API. This
- * property exists because fields can be marked for deletion but only
- * actually destroyed by a separate garbage-collection process.
- * - columns (array, read-only): An array of the Field API columns used to
- * store each value of this field. The column list may depend on field
- * settings; it is not constant per field type. Field API column
- * specifications are exactly like Schema API column specifications but,
- * depending on the field storage module in use, the name of the column may
- * not represent an actual column in an SQL database.
- * - indexes (array): An array of indexes on data columns, using the same
- * definition format as Schema API index specifications. Only columns that
- * appear in the 'columns' setting are allowed. Note that field types can
- * specify default indexes, which can be modified or added to when
- * creating a field.
- * - foreign keys: (optional) An associative array of relations, using the same
- * structure as the 'foreign keys' definition of hook_schema(). Note,
- * however, that the field data is not necessarily stored in SQL. Also, the
- * possible usage is limited, as you cannot specify another field as
- * related, only existing SQL tables, such as filter formats.
- * - settings (array): A sub-array of key/value pairs of field-type-specific
- * settings. Each field type module defines and documents its own field
- * settings.
- * - storage (array): A sub-array of key/value pairs identifying the storage
- * backend to use for the for the field:
- * - type (string): The storage backend used by the field. Storage backends
- * are defined by modules that implement hook_field_storage_info().
- * - module (string, read-only): The name of the module that implements the
- * storage backend.
- * - active (integer, read-only): TRUE if the module that implements the
- * storage backend is currently enabled, FALSE otherwise.
- * - settings (array): A sub-array of key/value pairs of settings. Each
- * storage backend defines and documents its own settings.
- *
- * Field instance definitions are represented as an array of key/value pairs.
- *
- * array $instance:
- * - id (integer, read-only): The primary identifier of this field instance.
- * It is assigned automatically by field_create_instance().
- * - field_name (string): The name of the field attached to the bundle by this
- * instance.
- * - entity_type (string): The name of the entity type the instance is attached
- * to.
- * - bundle (string): The name of the bundle that the field is attached to.
- * - label (string): A human-readable label for the field when used with this
- * bundle. For example, the label will be the title of Form API elements
- * for this instance.
- * - description (string): A human-readable description for the field when
- * used with this bundle. For example, the description will be the help
- * text of Form API elements for this instance.
- * - required (integer): TRUE if a value for this field is required when used
- * with this bundle, FALSE otherwise. Currently, required-ness is only
- * enforced during Form API operations, not by field_attach_load(),
- * field_attach_insert(), or field_attach_update().
- * - default_value_function (string): The name of the function, if any, that
- * will provide a default value.
- * - default_value (array): If default_value_function is not set, then fixed
- * values can be provided.
- * - deleted (integer, read-only): TRUE if this instance has been deleted,
- * FALSE otherwise. Deleted instances are ignored by the Field Attach API.
- * This property exists because instances can be marked for deletion but
- * only actually destroyed by a separate garbage-collection process.
- * - settings (array): A sub-array of key/value pairs of field-type-specific
- * instance settings. Each field type module defines and documents its own
- * instance settings.
- * - widget (array): A sub-array of key/value pairs identifying the Form API
- * input widget for the field when used by this bundle:
- * - type (string): The type of the widget, such as text_textfield. Widget
- * types are defined by modules that implement hook_field_widget_info().
- * - settings (array): A sub-array of key/value pairs of
- * widget-type-specific settings. Each field widget type module defines
- * and documents its own widget settings.
- * - weight (float): The weight of the widget relative to the other elements
- * in entity edit forms.
- * - module (string, read-only): The name of the module that implements the
- * widget type.
- * - display (array): A sub-array of key/value pairs identifying the way field
- * values should be displayed in each of the entity type's display modes, plus
- * the 'default' mode. For each display mode, Field UI lets site administrators
- * define whether they want to use a dedicated set of display options or the
- * 'default' options to reduce the number of displays to maintain as they
- * add new fields. For nodes, on a fresh install, only the 'teaser' view
- * mode is configured to use custom display options, all other display modes
- * defined use the 'default' options by default. When programmatically
- * adding field instances on nodes, it is therefore recommended to at least
- * specify display options for 'default' and 'teaser':
- * - default (array): A sub-array of key/value pairs describing the display
- * options to be used when the field is being displayed in display modes
- * that are not configured to use dedicated display options:
- * - label (string): Position of the label. 'inline', 'above' and
- * 'hidden' are the values recognized by the default 'field' theme
- * implementation.
- * - type (string): The type of the display formatter, or 'hidden' for
- * no display.
- * - settings (array): A sub-array of key/value pairs of display
- * options specific to the formatter.
- * - weight (float): The weight of the field relative to the other entity
- * components displayed in this display mode.
- * - module (string, read-only): The name of the module which implements
- * the display formatter.
- * - some_mode: A sub-array of key/value pairs describing the display
- * options to be used when the field is being displayed in the 'some_mode'
- * display mode. Those options will only be actually applied at run time if
- * the display mode is not configured to use default settings for this bundle:
- * - ...
- * - other_mode:
- * - ...
- *
- * The (default) render arrays produced for field instances are documented at
- * field_attach_view().
- *
- * Bundles are represented by two strings, an entity type and a bundle name.
- *
- * - @link field_types Field Types API @endlink. Defines field types,
- * widget types, and display formatters. Field modules use this API
- * to provide field types like Text and Node Reference along with the
- * associated form elements and display formatters.
- *
- * - @link field_crud Field CRUD API @endlink. Create, updates, and
- * deletes fields, bundles (a.k.a. "content types"), and instances.
- * Modules use this API, often in hook_install(), to create
- * custom data structures.
- *
- * - @link field_attach Field Attach API @endlink. Connects entity
- * types to the Field API. Field Attach API functions load, store,
- * generate Form API structures, display, and perform a variety of
- * other functions for field data connected to individual entities.
- * Fieldable entity types like node and user use this API to make
- * themselves fieldable.
- *
- * - @link field_info Field Info API @endlink. Exposes information
- * about all fields, instances, widgets, and related information
- * defined by or with the Field API.
- *
- * - @link field_storage Field Storage API @endlink. Provides a
- * pluggable back-end storage system for actual field data. The
- * default implementation, field_sql_storage.module, stores field data
- * in the local SQL database.
- *
- * - @link field_purge Field API bulk data deletion @endlink. Cleans
- * up after bulk deletion operations such as field_delete_field()
- * and field_delete_instance().
- *
- * - @link field_language Field language API @endlink. Provides native
- * multilingual support for the Field API.
- */
-
- * Value for field API indicating a field accepts an unlimited number of values.
- */
- define('FIELD_CARDINALITY_UNLIMITED', -1);
-
- * Value for field API indicating a widget doesn't accept default values.
- *
- * @see hook_field_widget_info()
- */
- define('FIELD_BEHAVIOR_NONE', 0x0001);
-
- * Value for field API concerning widget default and multiple value settings.
- *
- * @see hook_field_widget_info()
- *
- * When used in a widget default context, indicates the widget accepts default
- * values. When used in a multiple value context for a widget that allows the
- * input of one single field value, indicates that the widget will be repeated
- * for each value input.
- */
- define('FIELD_BEHAVIOR_DEFAULT', 0x0002);
-
- * Value for field API indicating a widget can receive several field values.
- *
- * @see hook_field_widget_info()
- */
- define('FIELD_BEHAVIOR_CUSTOM', 0x0004);
-
- * Age argument for loading the most recent version of an entity's
- * field data with field_attach_load().
- */
- define('FIELD_LOAD_CURRENT', 'FIELD_LOAD_CURRENT');
-
- * Age argument for loading the version of an entity's field data
- * specified in the entity with field_attach_load().
- */
- define('FIELD_LOAD_REVISION', 'FIELD_LOAD_REVISION');
-
- * Implements hook_permission().
- */
- function field_permission() {
- return array(
- 'administer fields' => array(
- 'title' => t('Administer fields'),
- 'description' => t('Additional permissions are required based on what the fields are attached to (for example, <a href="@url">administer content types</a> to manage fields attached to content).', array(
- '@url' => '#module-node',
- )),
- 'restrict access' => TRUE,
- 'warning' => t('Deleting fields can cause irreversible data loss.'),
- ),
- );
- }
-
- * Implements hook_theme().
- */
- function field_theme() {
- $base = array(
- 'file' => 'field.theme.inc',
- );
-
- return array(
- 'field' => array(
- 'render element' => 'element',
- ) + $base,
- 'field_multiple_value_form' => array(
- 'render element' => 'element',
- ) + $base,
- );
- }
-
- * Implements hook_views_api().
- */
- function field_views_api() {
- return array(
- 'api' => '3.0',
- 'path' => backdrop_get_path('module', 'field') . '/views',
- );
- }
-
- * Implements hook_cron().
- */
- function field_cron() {
-
- field_sync_field_status();
-
-
- $limit = config_get('system.core', 'field_purge_batch_size');
- field_purge_batch($limit);
- }
-
- * Implements hook_system_info_alter().
- *
- * Goes through a list of all modules that provide a field type, and makes them
- * required if there are any active fields of that type.
- */
- function field_system_info_alter(&$info, $file, $type) {
- if ($type == 'module' && module_hook($file->name, 'field_info')) {
- $fields = field_read_fields(array('module' => $file->name), array('include_deleted' => TRUE));
- if ($fields) {
- $info['disabled'] = TRUE;
-
-
-
- $non_deleted = FALSE;
- foreach ($fields as $field) {
- if (empty($field['deleted'])) {
- $non_deleted = TRUE;
- break;
- }
- }
- if ($non_deleted) {
- if (module_exists('field_ui')) {
- $explanation = t('Field type(s) in use - see <a href="@fields-page">Field list</a>', array('@fields-page' => url('admin/reports/fields')));
- }
- else {
- $explanation = t('Fields type(s) in use');
- }
- }
- else {
- $explanation = t('Fields pending deletion');
- }
- $info['explanation'] = $explanation;
- }
- }
- }
-
- * Implements hook_autoload_info().
- */
- function field_autoload_info() {
- return array(
- 'FieldException' => 'field.exceptions.inc',
- 'FieldUpdateForbiddenException' => 'field.exceptions.inc',
- 'FieldValidationException' => 'field.exceptions.inc',
- 'FieldBlock' => 'field.block.inc',
-
- 'views_handler_field_field' => 'views/views_handler_field_field.inc',
- 'views_handler_relationship_entity_reverse' => 'views/views_handler_relationship_entity_reverse.inc',
- 'views_handler_argument_field_list' => 'views/views_handler_argument_field_list.inc',
- 'views_handler_argument_field_list_string' => 'views/views_handler_argument_field_list_string.inc',
- 'views_handler_filter_field_list' => 'views/views_handler_filter_field_list.inc',
- );
- }
-
- * Implements hook_flush_caches().
- */
- function field_flush_caches() {
-
-
-
- if (!defined('MAINTENANCE_MODE')) {
- field_sync_field_status();
- }
-
-
- return array('field');
- }
-
- * Implements hook_modules_enabled().
- */
- function field_modules_enabled($modules) {
-
- field_sync_field_status();
- }
-
- * Implements hook_modules_disabled().
- */
- function field_modules_disabled($modules) {
-
- field_sync_field_status();
- }
-
- * Implements hook_config_info().
- */
- function field_config_info() {
- $prefixes['field.field'] = array(
- 'name_key' => 'field_name',
- 'label_key' => 'field_name',
- 'group' => t('Fields'),
- );
- $prefixes['field.instance'] = array(
- 'name_key' => array('entity_type', 'bundle', 'field_name'),
- 'label_callback' => 'field_config_label_instance',
- 'group' => t('Field instances'),
- );
- $prefixes['field.bundle'] = array(
- 'name_key' => array('entity_type', 'bundle'),
- 'label_callback' => 'field_config_label_bundle',
- 'group' => t('Field display settings'),
- );
-
- return $prefixes;
- }
-
- * Given a field array, display a unique label.
- */
- function field_config_label_instance($instance, $config_name) {
- list($entity_type_name, $bundle, $field_name) = explode('.', str_replace('field.instance.', '', $config_name));
- $entity_type = entity_get_info($entity_type_name);
- $entity_label = $entity_type['label'];
- $bundle_label = isset($entity_type['bundles'][$bundle]['label']) ? $entity_type['bundles'][$bundle]['label'] : $bundle;
- return $entity_label . ' - ' . $bundle_label . ' - ' . $instance['label'];
- }
-
- * Given a bundle config file, display a unique label.
- */
- function field_config_label_bundle($bundle_config, $config_name) {
- list($entity_type_name, $bundle) = explode('.', str_replace('field.bundle.', '', $config_name));
- $entity_type = entity_get_info($entity_type_name);
- $entity_label = $entity_type['label'];
- $bundle_label = isset($entity_type['bundles'][$bundle]['label']) ? $entity_type['bundles'][$bundle]['label'] : $bundle;
-
- return $entity_label . ' - ' . $bundle_label;
- }
-
- * Implements hook_config_create_validate().
- */
- function field_config_create_validate(Config $staging_config, $all_changes) {
- $config_name = $staging_config->getName();
-
-
- if (strpos($config_name, 'field.field.') === 0) {
-
- $field_name = str_replace('field.field.', '', $config_name);
- if (field_info_field($field_name)) {
- throw new ConfigValidateException(t('The field "@name" cannot be created because another field with the same name already exists. Delete the field manually before importing the new field.', array('@name' => $field_name)));
- }
-
-
- try {
- $field = $staging_config->get();
- field_validate_field($field);
- }
- catch (FieldException $e) {
- throw new ConfigValidateException($e->getMessage());
- }
- }
-
-
- if (strpos($config_name, 'field.instance.') === 0) {
-
-
-
-
- $field_name = $staging_config->get('field_name');
- $label = $staging_config->get('label');
- if (!field_info_field($field_name) && empty($all_changes['field.field.' . $field_name])) {
- throw new ConfigValidateException(t('The field instance "@label" cannot be created because the field type "@field" does not exist.', array('@label' => $label, '@field' => $field_name)));
- }
-
-
- try {
- $instance = $staging_config->get();
- field_validate_instance($instance, FALSE, FALSE);
- }
- catch (FieldException $e) {
- throw new ConfigValidateException($e->getMessage());
- }
- }
- }
-
- * Implements hook_config_update_validate().
- */
- function field_config_update_validate(Config $staging_config, Config $active_config, $all_changes) {
- $config_name = $staging_config->getName();
-
-
- if (strpos($config_name, 'field.field.') === 0) {
-
-
- $field_name = str_replace('field.field.', '', $config_name);
- $current_type = $active_config->get('type');
- $new_type = $staging_config->get('type');
- if ($current_type !== $new_type) {
- throw new ConfigValidateException(t('The field "@name" cannot be created because another field with the same name already exists and is a different type of field. The current type is "@current" and the imported type would be "@new". Delete the field manually before importing the new field.', array('@name' => $field_name, '@current' => $current_type, '@new' => $new_type)));
- }
-
-
- try {
- $field = $staging_config->get();
- field_validate_field($field, TRUE);
- }
- catch (FieldException $e) {
- throw new ConfigValidateException($e->getMessage());
- }
- }
-
-
- if (strpos($config_name, 'field.instance.') === 0) {
-
- try {
- $instance = $staging_config->get();
- field_validate_instance($instance, FALSE, FALSE);
- }
- catch (FieldException $e) {
- throw new ConfigValidateException($e->getMessage());
- }
- }
- }
-
-
- * Implements hook_config_delete_validate().
- */
- function field_config_delete_validate(Config $active_config, $all_changes) {
- $config_name = $active_config->getName();
-
-
-
-
-
- if (strpos($config_name, 'field.field.') === 0) {
- $field_name = $active_config->get('field_name');
- $field = $active_config->get();
- if (field_has_data($field)) {
- throw new ConfigValidateException(t('The field "@field" cannot be deleted through a configuration import. Delete the field manually first, then retry the import.', array('@field' => $field_name)));
- }
- }
- }
-
- * Implements hook_config_create().
- */
- function field_config_create(Config $staging_config) {
- $config_name = $staging_config->getName();
- if (strpos($config_name, 'field.field.') === 0) {
- $field_data_table_exists = FALSE;
-
- $field = $staging_config->get();
- $schema = _field_sql_storage_schema($field);
-
- foreach ($schema as $name => $table) {
- if (db_table_exists($name)) {
- $field_data_table_exists = TRUE;
- break;
- }
- }
-
- if (!$field_data_table_exists) {
- field_create_field($field);
- }
- }
- }
-
- * Implements hook_config_update().
- */
- function field_config_update(Config $staging_config, Config $active_config) {
- $config_name = $staging_config->getName();
- if (strpos($config_name, 'field.field.') === 0) {
- $field = $staging_config->get();
- field_update_field($field);
- }
- }
-
- * Implements hook_config_delete().
- */
- function field_config_delete(Config $active_config) {
-
-
- $config_name = $active_config->getName();
- if (strpos($config_name, 'field.field.') === 0) {
- $field_name = $active_config->get('field_name');
- if (($field = field_read_field($field_name)) && !field_has_data($field)) {
- field_delete_field($field_name);
-
- field_purge_batch(0);
- }
- }
- }
-
- * Refreshes the 'active' and 'storage[active]' properties on fields.
- */
- function field_sync_field_status() {
-
-
- $modules = module_list();
- $fields = field_read_fields();
- foreach ($modules as $module_name) {
- field_associate_fields($module_name, $fields);
- }
-
- $fields = field_read_fields(array(), array('include_inactive' => TRUE, 'include_deleted' => TRUE));
- foreach ($fields as $field) {
- $current_field = $field;
- $field['active'] = (int) in_array($field['module'], $modules);
- $field['storage']['active'] = (int) in_array($field['storage']['module'], $modules);
- if ($current_field !== $field) {
- field_update_field($field);
- }
- }
- }
-
- * Allows a module to update the database for fields and columns it controls.
- *
- * @param $module
- * The name of the module to update on.
- * @param $fields
- * An optional array of field definitions to operate on. If left empty, all
- * fields will be loaded.
- *
- * @since 1.18.4 Second parameter $fields added for performance optimization.
- */
- function field_associate_fields($module, &$fields = NULL) {
-
- $field_types = (array) module_invoke($module, 'field_info');
- $storage_types = (array) module_invoke($module, 'field_storage_info');
-
-
-
- if (empty($field_types) && empty($storage_types)) {
- return;
- }
-
-
- if (is_null($fields)) {
- $fields = field_read_fields();
- }
-
- foreach (array_keys($fields) as $field_name) {
- $old_field = $fields[$field_name];
- if (array_key_exists($fields[$field_name]['type'], $field_types)) {
- $fields[$field_name]['module'] = $module;
- $fields[$field_name]['active'] = 1;
- }
- if (array_key_exists($fields[$field_name]['storage']['type'], $storage_types)) {
- $fields[$field_name]['storage']['module'] = $module;
- $fields[$field_name]['storage']['active'] = 1;
- }
- if ($old_field !== $fields[$field_name]) {
- field_update_field($fields[$field_name]);
- }
- }
- }
-
- * Helper function to get the default value for a field on an entity.
- *
- * @param $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $entity
- * The entity for the operation.
- * @param $field
- * The field structure.
- * @param $instance
- * The instance structure.
- * @param $langcode
- * The field language to fill-in with the default value.
- */
- function field_get_default_value($entity_type, $entity, $field, $instance, $langcode = NULL) {
- $items = array();
- if (!empty($instance['default_value_function'])) {
- $function = $instance['default_value_function'];
- $items = $function($entity_type, $entity, $field, $instance, $langcode);
- }
- elseif (!empty($instance['default_value'])) {
- $items = $instance['default_value'];
- }
- return $items;
- }
-
- * Returns the first value from a field.
- *
- * @param Entity $entity
- * The fully-loaded entity containing the field value requested.
- * @param string $field_name
- * The machine name of the field.
- * @param string $value_key
- * The key indicating the primary data value for the field. Defaults to
- * 'value' which is used in both text and number fields. For fields which do
- * not have a 'value' key such as terms (which use a 'tid' key) or files
- * (which use a 'fid' key), the key must be specified.
- * @param string $langcode (optional)
- * The language code for the requested language. Defaults to the
- * current language.
- *
- * @return
- * The first field value, or NULL if the field is empty, if the field does not
- * contain the $value_key specified, or if the entity does not contain the
- * $field_name specified.
- *
- * @since 1.13.0 Function added.
- *
- * @see field_get_values()
- */
- function field_get_value(Entity $entity, $field_name, $value_key = 'value', $langcode = NULL) {
- return $entity->getFieldValue($field_name, $value_key, $langcode);
- }
-
- * Returns all values from a field.
- *
- * @param Entity $entity
- * The fully-loaded entity containing the field value requested.
- * @param string $field_name
- * The machine name of the field.
- * @param string $value_key
- * The key indicating the primary data value for the field. Defaults to
- * 'value' which is used in both text and number fields. For fields which do
- * not have a 'value' key such as terms (which use a 'tid' key) or files
- * (which use a 'fid' key), the key must be specified.
- * @param string $langcode (optional)
- * The language code for the requested language. Defaults to the
- * current language.
- *
- * @return (array)
- * All field values, or an empty array if the field is empty, if the field does not
- * contain the $value_key specified, or if the entity does not contain the
- * $field_name specified.
- *
- * @since 1.13.0 Function added.
- *
- * @see field_get_value()
- */
- function field_get_values(Entity $entity, $field_name, $value_key = 'value', $langcode = NULL) {
- return $entity->getFieldValues($field_name, $value_key, $langcode);
- }
-
- * Helper function to filter out empty field values.
- *
- * @param $field
- * The field definition.
- * @param $items
- * The field values to filter.
- *
- * @return
- * The array of items without empty field values. The function also renumbers
- * the array keys to ensure sequential deltas.
- */
- function _field_filter_items($field, $items) {
- $function = $field['module'] . '_field_is_empty';
- foreach ((array) $items as $delta => $item) {
-
- if ($function($item, $field)) {
- unset($items[$delta]);
- }
- }
- return array_values($items);
- }
-
- * Helper function to sort items in a field according to
- * user drag-n-drop reordering.
- */
- function _field_sort_items($field, $items) {
- if (($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) && isset($items[0]['_weight'])) {
- usort($items, '_field_sort_items_helper');
- foreach ($items as $delta => $item) {
- if (is_array($items[$delta])) {
- unset($items[$delta]['_weight']);
- }
- }
- }
- return $items;
- }
-
- * Sort function for items order.
- * (copied form element_sort(), which acts on #weight keys)
- */
- function _field_sort_items_helper($a, $b) {
- $a_weight = (is_array($a) ? $a['_weight'] : 0);
- $b_weight = (is_array($b) ? $b['_weight'] : 0);
- return $a_weight - $b_weight;
- }
-
- * Same as above, using ['_weight']['#value']
- */
- function _field_sort_items_value_helper($a, $b) {
- $a_weight = (is_array($a) && isset($a['_weight']['#value']) ? $a['_weight']['#value'] : 0);
- $b_weight = (is_array($b) && isset($b['_weight']['#value']) ? $b['_weight']['#value'] : 0);
- return $a_weight - $b_weight;
- }
-
- * Gets or sets administratively defined bundle settings.
- *
- * @param string $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param string $bundle
- * The bundle name.
- * @param array|null $settings
- * (optional) The settings to store, an associative array with the following
- * elements:
- * - view_modes: An associative array keyed by display mode, with the
- * following key/value pairs:
- * - custom_settings: Boolean specifying whether the display mode uses a
- * dedicated set of display options (TRUE), or the 'default' options
- * (FALSE). Defaults to FALSE.
- * - extra_fields: An associative array containing the form and display
- * settings for extra fields (also known as pseudo-fields):
- * - form: An associative array whose keys are the names of extra fields,
- * and whose values are associative arrays with the following elements:
- * - weight: The weight of the extra field, determining its position on an
- * entity form.
- * - display: An associative array whose keys are the names of extra fields,
- * and whose values are associative arrays keyed by the name of view
- * modes. This array must include an item for the 'default' display mode.
- * Each display mode sub-array contains the following elements:
- * - weight: The weight of the extra field, determining its position when
- * an entity is viewed.
- * - visible: TRUE if the extra field is visible, FALSE otherwise.
- *
- * @return array|null
- * If no $settings are passed, the current settings are returned.
- */
- function field_bundle_settings($entity_type, $bundle, $settings = NULL) {
- if (isset($settings)) {
- $config = config('field.bundle.' . $entity_type . '.' . $bundle);
- $data = array(
- 'bundle' => $bundle,
- 'entity_type' => $entity_type,
- ) + $settings;
- $config->setData($data);
- $config->save();
- field_info_cache_clear();
- }
- else {
- $config = config('field.bundle.' . $entity_type . '.' . $bundle);
- $data = $config->get();
- if (empty($data)) {
- $settings = array();
- }
- else {
-
- $settings = array_diff_key($data, array(
- 'bundle' => $bundle,
- 'entity_type' => $entity_type,
- ));
- }
- $settings += array(
- 'view_modes' => array(),
- 'extra_fields' => array(),
- );
- $settings['extra_fields'] += array(
- 'form' => array(),
- 'display' => array(),
- );
-
- return $settings;
- }
- }
-
- * Returns display mode settings in a given bundle.
- *
- * @param $entity_type
- * The type of entity; e.g. 'node' or 'user'.
- * @param $bundle
- * The bundle name to return display mode settings for.
- *
- * @return
- * An array keyed by display mode, with the following key/value pairs:
- * - custom_settings: Boolean specifying whether the display mode uses a
- * dedicated set of display options (TRUE), or the 'default' options
- * (FALSE). Defaults to FALSE.
- */
- function field_view_mode_settings($entity_type, $bundle) {
- $cache = &backdrop_static(__FUNCTION__, array());
-
- if (!isset($cache[$entity_type][$bundle])) {
- $bundle_settings = field_bundle_settings($entity_type, $bundle);
- $settings = $bundle_settings['view_modes'];
-
-
-
- $entity_info = entity_get_info($entity_type);
- foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
- if (!isset($settings[$view_mode]['custom_settings']) && $view_mode_info['custom settings']) {
- $settings[$view_mode]['custom_settings'] = TRUE;
- }
- }
- $cache[$entity_type][$bundle] = $settings;
- }
-
- return $cache[$entity_type][$bundle];
- }
-
- * Returns the display settings to use for an instance in a given display mode.
- *
- * @param $instance
- * The field instance being displayed.
- * @param $view_mode
- * The display mode.
- * @param $entity
- * The entity being displayed.
- *
- * @return
- * The display settings to be used when displaying the field values.
- */
- function field_get_display($instance, $view_mode, $entity) {
-
-
- $view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
- $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default');
- $display = $instance['display'][$actual_mode];
-
-
- $context = array(
- 'entity_type' => $instance['entity_type'],
- 'field' => field_info_field($instance['field_name']),
- 'instance' => $instance,
- 'entity' => $entity,
- 'view_mode' => $view_mode,
- );
- backdrop_alter(array('field_display', 'field_display_' . $instance['entity_type']), $display, $context);
-
- return $display;
- }
-
- * Returns the display settings to use for pseudo-fields in a display mode.
- *
- * @param $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $bundle
- * The bundle name.
- * @param $view_mode
- * The display mode.
- *
- * @return
- * The display settings to be used when viewing the bundle's pseudo-fields.
- */
- function field_extra_fields_get_display($entity_type, $bundle, $view_mode) {
-
-
- $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
- $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings'])) ? $view_mode : 'default';
- $extra_fields = field_info_extra_fields($entity_type, $bundle, 'display');
-
- $displays = array();
- foreach ($extra_fields as $name => $value) {
- $displays[$name] = $extra_fields[$name]['display'][$actual_mode];
- }
-
-
- $context = array(
- 'entity_type' => $entity_type,
- 'bundle' => $bundle,
- 'view_mode' => $view_mode,
- );
- backdrop_alter('field_extra_fields_display', $displays, $context);
-
- return $displays;
- }
-
- * Pre-render callback to adjust weights and visibility of non-field elements.
- */
- function _field_extra_fields_pre_render($elements) {
- $entity_type = $elements['#entity_type'];
- $bundle = $elements['#bundle'];
-
- if (isset($elements['#type']) && $elements['#type'] == 'form') {
- $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form');
- foreach ($extra_fields as $name => $settings) {
- if (isset($elements[$name])) {
- $elements[$name]['#weight'] = $settings['weight'];
- }
- }
- }
- elseif (isset($elements['#view_mode'])) {
- $view_mode = $elements['#view_mode'];
- $extra_fields = field_extra_fields_get_display($entity_type, $bundle, $view_mode);
- foreach ($extra_fields as $name => $settings) {
- if (isset($elements[$name])) {
- $elements[$name]['#weight'] = $settings['weight'];
-
- $elements[$name]['#access'] = isset($elements[$name]['#access']) ? ($elements[$name]['#access'] && $settings['visible']) : $settings['visible'];
- }
- }
- }
-
- return $elements;
- }
-
- * Clear the field info and field data caches.
- */
- function field_cache_clear() {
- cache('field')->flush();
- field_info_cache_clear();
- }
-
- * Like filter_xss_admin(), but with a shorter list of allowed tags.
- *
- * Used for items entered by administrators, like field descriptions, allowed
- * values, where some (mainly inline) mark-up may be desired (so check_plain()
- * is not acceptable).
- */
- function field_filter_xss($string) {
- return filter_xss($string, _field_filter_xss_allowed_tags());
- }
-
- * List of tags allowed by field_filter_xss().
- */
- function _field_filter_xss_allowed_tags() {
- return array('a', 'b', 'big', 'code', 'del', 'em', 'i', 'ins', 'pre', 'q', 'small', 'span', 'strong', 'sub', 'sup', 'tt', 'ol', 'ul', 'li', 'p', 'br', 'img');
- }
-
- * Human-readable list of tags allowed tags by field_filter_xss(), for display
- * in help texts.
- */
- function _field_filter_xss_display_allowed_tags() {
- return '<' . implode('> <', _field_filter_xss_allowed_tags()) . '>';
- }
-
- * Returns a renderable array for a single field value.
- *
- * @param $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $entity
- * The entity containing the field to display. Must at least contain the id
- * key and the field data to display.
- * @param $field_name
- * The name of the field to display.
- * @param $item
- * The field value to display, as found in
- * $entity->field_name[$langcode][$delta].
- * @param $display
- * Can be either the name of a display mode, or an array of display settings.
- * See field_view_field() for more information.
- * @param $langcode
- * (Optional) The language of the value in $item. If not provided, the
- * current language will be assumed.
- * @return
- * A renderable array for the field value.
- */
- function field_view_value($entity_type, $entity, $field_name, $item, $display = array(), $langcode = NULL) {
- $output = array();
-
- if ($field = field_info_field($field_name)) {
-
- $langcode = field_language($entity_type, $entity, $field_name, $langcode);
-
-
-
- $clone = clone $entity;
- $clone->{$field_name}[$langcode] = array($item);
- $elements = field_view_field($entity_type, $clone, $field_name, $display, $langcode);
-
-
- $output = isset($elements[0]) ? $elements[0] : array();
- if (isset($elements['#access'])) {
- $output['#access'] = $elements['#access'];
- }
- }
-
- return $output;
- }
-
- * Returns a renderable array for the value of a single field in an entity.
- *
- * The resulting output is a fully themed field with label and multiple values.
- *
- * This function can be used by third-party modules that need to output an
- * isolated field.
- * - Do not use inside node (or any other entity) templates; use
- * render($content[FIELD_NAME]) instead.
- * - Do not use to display all fields in an entity; use
- * field_attach_prepare_view() and field_attach_view() instead.
- * - The field_view_value() function can be used to output a single formatted
- * field value, without label or wrapping field markup.
- *
- * The function takes care of invoking the prepare_view steps. It also respects
- * field access permissions.
- *
- * @param $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $entity
- * The entity containing the field to display. Must at least contain the id
- * key and the field data to display.
- * @param $field_name
- * The name of the field to display.
- * @param $display
- * Can be either:
- * - The name of a display mode. The field will be displayed according to the
- * display settings specified for this display mode in the $instance
- * definition for the field in the entity's bundle.
- * If no display settings are found for the display mode, the settings for
- * the 'default' display mode will be used.
- * - An array of display settings, as found in the 'display' entry of
- * $instance definitions. The following key/value pairs are allowed:
- * - label: (string) Position of the label. The default 'field' theme
- * implementation supports the values 'inline', 'above' and 'hidden'.
- * Defaults to 'hidden'.
- * - type: (string) The formatter to use. Defaults to the
- * 'default_formatter' for the field type, specified in
- * hook_field_info(). The default formatter will also be used if the
- * requested formatter is not available.
- * - settings: (array) Settings specific to the formatter. Defaults to the
- * formatter's default settings, specified in
- * hook_field_formatter_info().
- * - weight: (float) The weight to assign to the renderable element.
- * Defaults to 0.
- * @param $langcode
- * (Optional) The language the field values are to be shown in. The site's
- * current language fallback logic will be applied no values are available
- * for the language. If no language is provided the current language will be
- * used.
- * @return
- * A renderable array for the field value.
- *
- * @see field_view_value()
- */
- function field_view_field($entity_type, $entity, $field_name, $display = array(), $langcode = NULL) {
- $output = array();
-
- if ($field = field_info_field($field_name)) {
- if (is_array($display)) {
-
- $display = _field_info_prepare_instance_display($field, $display);
- }
-
-
-
-
-
- $display_language = field_language($entity_type, $entity, $field_name, $langcode);
- $options = array('field_name' => $field_name, 'language' => $display_language);
- $null = NULL;
-
-
- if (empty($entity->_field_view_prepared)) {
- list($id) = entity_extract_ids($entity_type, $entity);
-
-
- _field_invoke_multiple('prepare_view', $entity_type, array($id => $entity), $display, $null, $options);
-
- _field_invoke_multiple_default('prepare_view', $entity_type, array($id => $entity), $display, $null, $options);
- }
-
-
- $result = _field_invoke_default('view', $entity_type, $entity, $display, $null, $options);
-
-
-
- $context = array(
- 'entity_type' => $entity_type,
- 'entity' => $entity,
- 'view_mode' => '_custom',
- 'display' => $display,
- );
- backdrop_alter('field_attach_view', $result, $context);
-
- if (isset($result[$field_name])) {
- $output = $result[$field_name];
- }
- }
-
- return $output;
- }
-
- * Returns the field items in the language they currently would be displayed.
- *
- * @param $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $entity
- * The entity containing the data to be displayed.
- * @param $field_name
- * The field to be displayed.
- * @param $langcode
- * (optional) The language code $entity->{$field_name} has to be displayed in.
- * Defaults to the current language.
- *
- * @return
- * An array of field items keyed by delta if available, FALSE otherwise.
- */
- function field_get_items($entity_type, $entity, $field_name, $langcode = NULL) {
- $langcode = field_language($entity_type, $entity, $field_name, $langcode);
- return isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : FALSE;
- }
-
- * Determine whether a field has any data.
- *
- * @param $field
- * A field structure.
- * @return
- * TRUE if the field has data for any entity; FALSE otherwise.
- */
- function field_has_data($field) {
- $query = new EntityFieldQuery();
- $query = $query->fieldCondition($field)
- ->range(0, 1)
- ->count()
-
-
-
- ->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');
-
- return (bool) $query
- ->execute() || (bool) $query
- ->age(FIELD_LOAD_REVISION)
- ->execute();
- }
-
- * Determine whether the user has access to a given field.
- *
- * @param string $op
- * The operation to be performed. Possible values:
- * - 'edit'
- * - 'view'
- * @param array $field
- * The full field structure array for the field on which the operation is to
- * be performed. See field_info_field().
- * @param string $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $entity
- * (optional) The entity for the operation.
- * @param $account
- * (optional) The account to check, if not given use currently logged in user.
- *
- * @return
- * TRUE if the operation is allowed;
- * FALSE if the operation is denied.
- */
- function field_access($op, $field, $entity_type, $entity = NULL, $account = NULL) {
- global $user;
-
- if (!isset($account)) {
- $account = $user;
- }
-
- foreach (module_implements('field_access') as $module) {
- $function = $module . '_field_access';
- $access = $function($op, $field, $entity_type, $entity, $account);
- if ($access === FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
-
- * Helper function to extract the bundle name of from a bundle object.
- *
- * @param $entity_type
- * The type of $entity; e.g., 'node' or 'user'.
- * @param $bundle
- * The bundle object (or string if bundles for this entity type do not exist
- * as standalone objects).
- * @return
- * The bundle name.
- */
- function field_extract_bundle($entity_type, $bundle) {
- if (is_string($bundle)) {
- return $bundle;
- }
-
- $info = entity_get_info($entity_type);
- if (is_object($bundle) && isset($info['bundle keys']['bundle']) && isset($bundle->{$info['bundle keys']['bundle']})) {
- return $bundle->{$info['bundle keys']['bundle']};
- }
- }
-
- * @} End of "defgroup field".
- */
-
- * Implements hook_field_display_alter().
- */
- function field_field_display_alter(&$display, $context) {
- if ($context['view_mode'] == 'token') {
- $view_mode_settings = field_view_mode_settings($context['instance']['entity_type'], $context['instance']['bundle']);
-
-
- if (empty($view_mode_settings[$context['view_mode']]['custom_settings'])) {
- $field_type_info = field_info_field_types($context['field']['type']);
-
-
-
- $formatter = !empty($field_type_info['default_token_formatter']) ? $field_type_info['default_token_formatter'] : $field_type_info['default_formatter'];
-
-
- $display['type'] = $formatter;
- $formatter_info = field_info_formatter_types($formatter);
- $display['settings'] = isset($formatter_info['settings']) ? $formatter_info['settings'] : array();
- $display['settings']['label'] = 'hidden';
- $display['module'] = $formatter_info['module'];
- }
- }
- }
-
- * Implements hook_block_info().
- */
- function field_block_info() {
- $blocks['field_block'] = array(
- 'info' => t('Field block'),
- 'description' => 'Displays a field from a referenced entity.',
- 'class' => 'FieldBlock',
- 'required contexts' => array('entity' => 'entity'),
- );
-
- return $blocks;
- }
-
- * Helper function to build a list of fields that have been made available as
- * a block.
- * @return array
- * An array with all entity fields with known instances.
- */
- function field_get_block_list() {
- $types = &backdrop_static(__FUNCTION__, array());
- if (!empty($types)) {
- return $types;
- }
-
- $cache_key = 'field_block_list';
- if ($cache = cache_get($cache_key)) {
- $types = $cache->data;
- if (!empty($types)) {
- return $types;
- }
- }
-
-
- $all_entity_info = entity_get_info();
- $all_fields = array();
- foreach ($all_entity_info as $entity_type => $entity_info) {
- $description = t('Field from the available @type content.', array('@type' => backdrop_strtolower($entity_info['label'])));
- foreach ($entity_info['bundles'] as $type => $bundle) {
- foreach (field_info_instances($entity_type, $type) as $field_name => $field) {
-
-
- $field_info = field_info_field($field_name);
- $all_fields[$field_name] = $field_info;
- if (!isset($types[$entity_type . '-' . $field_name])) {
- $label = t($field['label']);
- $types[$entity_type . '-' . $field_name] = array(
- 'info' => t('Field: @widget_label (@field_name)', array('@widget_label' => $label, '@field_name' => $field_name)),
- 'description' => $description,
- 'required contexts' => array($entity_type => $entity_type),
- );
- }
- }
- }
- }
-
- cache_set($cache_key, $types);
-
- return $types;
- }
-
- * Implements hook_entity_view_mode_insert().
- */
- function field_entity_view_mode_insert($view_mode, $entity_type) {
- field_entity_view_mode_update($view_mode, $entity_type);
- }
-
- * Implements hook_entity_view_mode_update().
- */
- function field_entity_view_mode_update($view_mode, $entity_type) {
- module_load_include('inc', 'field_ui', 'field_ui.admin');
- $entity_info = entity_get_info($entity_type);
- $view_mode_name = $view_mode['machine_name'];
-
- if (!empty($view_mode['enabled_bundles'])) {
- foreach ($view_mode['enabled_bundles'] as $bundle => $value) {
- $bundle_settings = field_bundle_settings($entity_type, $bundle);
-
-
-
- $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
- if (!empty($value) && empty($view_mode_settings[$view_mode_name]['custom_settings'])) {
- $path = _field_ui_bundle_admin_path($entity_type, $bundle) . "/display/$view_mode_name";
- backdrop_set_message(t('The %view_mode @entity_type @bundle display mode now uses custom display settings copied from the default display mode. You might want to <a href="@url">configure them</a>.', array(
- '%view_mode' => $view_mode['label'],
- '@entity_type' => $entity_info['label'],
- '@bundle' => $entity_info['bundles'][$bundle]['label'],
- '@url' => url($path, array('query' => backdrop_get_destination())),
- )));
-
-
- _field_ui_add_default_view_mode_settings($entity_type, $bundle, $view_mode_name, $bundle_settings);
- }
-
-
- $bundle_settings['view_modes'][$view_mode_name]['custom_settings'] = !empty($value);
- field_bundle_settings($entity_type, $bundle, $bundle_settings);
- }
- }
- }
-
- * Implements hook_entity_view_mode_delete().
- */
- function field_entity_view_mode_delete($view_mode, $entity_type) {
- $entity_info = entity_get_info($entity_type);
- $view_mode_name = $view_mode['machine_name'];
-
- foreach (array_keys($entity_info['bundles']) as $bundle) {
-
- $settings = field_bundle_settings($entity_type, $bundle);
- if (isset($settings['view_modes'][$view_mode_name]) || isset($settings['extra_fields']['display'][$view_mode_name])) {
- unset($settings['view_modes'][$view_mode_name]);
- unset($settings['extra_fields']['display'][$view_mode_name]);
- field_bundle_settings($entity_type, $bundle, $settings);
- }
-
-
- $instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle));
- foreach ($instances as $instance) {
-
- if (isset($instance['display'][$view_mode_name])) {
- unset($instance['display'][$view_mode_name]);
- field_update_instance($instance);
- }
- }
- }
- }
-
- * Assembles a partial entity structure with initial IDs.
- *
- * This can be used to create an entity based on the the ids object returned by
- * EntityFieldQuery.
- *
- * @param stdClass $ids
- * An object with the properties entity_type (required), entity_id (required),
- * revision_id (optional) and bundle (optional).
- *
- * @return
- * An entity, initialized with the provided IDs.
- */
- function _field_create_entity_from_ids($ids) {
- $id_properties = array();
- $info = entity_get_info($ids->entity_type);
- $id_properties[$info['entity keys']['id']] = $ids->entity_id;
- if (!empty($info['entity keys']['revision']) && isset($ids->revision_id)) {
- $id_properties[$info['entity keys']['revision']] = $ids->revision_id;
- }
- if (!empty($info['entity keys']['bundle']) && isset($ids->bundle)) {
- $id_properties[$info['entity keys']['bundle']] = $ids->bundle;
- }
- return entity_create($ids->entity_type, $id_properties);
- }