Drupal PHP Cross Reference Content Management Systems

Source: /modules/field/field.crud.inc - 978 lines - 38080 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /**
   4   * @file
   5   * Field CRUD API, handling field and field instance creation and deletion.
   6   */
   7  
   8  /**
   9   * @defgroup field_crud Field CRUD API
  10   * @{
  11   * Create, update, and delete Field API fields, bundles, and instances.
  12   *
  13   * Modules use this API, often in hook_install(), to create custom
  14   * data structures. UI modules will use it to create a user interface.
  15   *
  16   * The Field CRUD API uses
  17   * @link field Field API data structures @endlink.
  18   *
  19   * See @link field Field API @endlink for information about the other parts of
  20   * the Field API.
  21   */
  22  
  23  /**
  24   * Creates a field.
  25   *
  26   * This function does not bind the field to any bundle; use
  27   * field_create_instance() for that.
  28   *
  29   * @param $field
  30   *   A field definition array. The field_name and type properties are required.
  31   *   Other properties, if omitted, will be given the following default values:
  32   *   - cardinality: 1
  33   *   - locked: FALSE
  34   *   - indexes: the field-type indexes, specified by the field type's
  35   *     hook_field_schema(). The indexes specified in $field are added
  36   *     to those default indexes. It is possible to override the
  37   *     definition of a field-type index by providing an index with the
  38   *     same name, or to remove it by redefining it as an empty array
  39   *     of columns. Overriding field-type indexes should be done
  40   *     carefully, for it might seriously affect the site's performance.
  41   *   - settings: each omitted setting is given the default value defined in
  42   *     hook_field_info().
  43   *   - storage:
  44   *     - type: the storage backend specified in the 'field_storage_default'
  45   *       system variable.
  46   *     - settings: each omitted setting is given the default value specified in
  47   *       hook_field_storage_info().
  48   *
  49   * @return
  50   *   The $field array with the id property filled in.
  51   *
  52   * @throws FieldException
  53   *
  54   * See: @link field Field API data structures @endlink.
  55   */
  56  function field_create_field($field) {
  57    // Field name is required.
  58    if (empty($field['field_name'])) {
  59      throw new FieldException('Attempt to create an unnamed field.');
  60    }
  61    // Field type is required.
  62    if (empty($field['type'])) {
  63      throw new FieldException('Attempt to create a field with no type.');
  64    }
  65    // Field name cannot contain invalid characters.
  66    if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $field['field_name'])) {
  67      throw new FieldException('Attempt to create a field with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character');
  68    }
  69  
  70    // Field name cannot be longer than 32 characters. We use drupal_strlen()
  71    // because the DB layer assumes that column widths are given in characters,
  72    // not bytes.
  73    if (drupal_strlen($field['field_name']) > 32) {
  74      throw new FieldException(t('Attempt to create a field with a name longer than 32 characters: %name',
  75        array('%name' => $field['field_name'])));
  76    }
  77  
  78    // Ensure the field name is unique over active and disabled fields.
  79    // We do not care about deleted fields.
  80    $prior_field = field_read_field($field['field_name'], array('include_inactive' => TRUE));
  81    if (!empty($prior_field)) {
  82      $message = $prior_field['active']?
  83        t('Attempt to create field name %name which already exists and is active.', array('%name' => $field['field_name'])):
  84        t('Attempt to create field name %name which already exists, although it is inactive.', array('%name' => $field['field_name']));
  85      throw new FieldException($message);
  86    }
  87  
  88    // Disallow reserved field names. This can't prevent all field name
  89    // collisions with existing entity properties, but some is better
  90    // than none.
  91    foreach (entity_get_info() as $type => $info) {
  92      if (in_array($field['field_name'], $info['entity keys'])) {
  93        throw new FieldException(t('Attempt to create field name %name which is reserved by entity type %type.', array('%name' => $field['field_name'], '%type' => $type)));
  94      }
  95    }
  96  
  97    $field += array(
  98      'entity_types' => array(),
  99      'cardinality' => 1,
 100      'translatable' => FALSE,
 101      'locked' => FALSE,
 102      'settings' => array(),
 103      'storage' => array(),
 104      'deleted' => 0,
 105    );
 106  
 107    // Check that the field type is known.
 108    $field_type = field_info_field_types($field['type']);
 109    if (!$field_type) {
 110      throw new FieldException(t('Attempt to create a field of unknown type %type.', array('%type' => $field['type'])));
 111    }
 112    // Create all per-field-type properties (needed here as long as we have
 113    // settings that impact column definitions).
 114    $field['settings'] += field_info_field_settings($field['type']);
 115    $field['module'] = $field_type['module'];
 116    $field['active'] = 1;
 117  
 118    // Provide default storage.
 119    $field['storage'] += array(
 120      'type' => variable_get('field_storage_default', 'field_sql_storage'),
 121      'settings' => array(),
 122    );
 123    // Check that the storage type is known.
 124    $storage_type = field_info_storage_types($field['storage']['type']);
 125    if (!$storage_type) {
 126      throw new FieldException(t('Attempt to create a field with unknown storage type %type.', array('%type' => $field['storage']['type'])));
 127    }
 128    // Provide default storage settings.
 129    $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
 130    $field['storage']['module'] = $storage_type['module'];
 131    $field['storage']['active'] = 1;
 132    // Collect storage information.
 133    module_load_install($field['module']);
 134    $schema = (array) module_invoke($field['module'], 'field_schema', $field);
 135    $schema += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array());
 136    // 'columns' are hardcoded in the field type.
 137    $field['columns'] = $schema['columns'];
 138    // 'foreign keys' are hardcoded in the field type.
 139    $field['foreign keys'] = $schema['foreign keys'];
 140    // 'indexes' can be both hardcoded in the field type, and specified in the
 141    // incoming $field definition.
 142    $field += array(
 143      'indexes' => array(),
 144    );
 145    $field['indexes'] += $schema['indexes'];
 146  
 147    // The serialized 'data' column contains everything from $field that does not
 148    // have its own column and is not automatically populated when the field is
 149    // read.
 150    $data = $field;
 151    unset($data['columns'], $data['field_name'], $data['type'], $data['active'], $data['module'], $data['storage_type'], $data['storage_active'], $data['storage_module'], $data['locked'], $data['cardinality'], $data['deleted']);
 152    // Additionally, do not save the 'bundles' property populated by
 153    // field_info_field().
 154    unset($data['bundles']);
 155  
 156    $record = array(
 157      'field_name' => $field['field_name'],
 158      'type' => $field['type'],
 159      'module' => $field['module'],
 160      'active' => $field['active'],
 161      'storage_type' => $field['storage']['type'],
 162      'storage_module' => $field['storage']['module'],
 163      'storage_active' => $field['storage']['active'],
 164      'locked' => $field['locked'],
 165      'data' => $data,
 166      'cardinality' => $field['cardinality'],
 167      'translatable' => $field['translatable'],
 168      'deleted' => $field['deleted'],
 169    );
 170  
 171    // Store the field and get the id back.
 172    drupal_write_record('field_config', $record);
 173    $field['id'] = $record['id'];
 174  
 175    // Invoke hook_field_storage_create_field after the field is
 176    // complete (e.g. it has its id).
 177    try {
 178      // Invoke hook_field_storage_create_field after
 179      // drupal_write_record() sets the field id.
 180      module_invoke($storage_type['module'], 'field_storage_create_field', $field);
 181    }
 182    catch (Exception $e) {
 183      // If storage creation failed, remove the field_config record before
 184      // rethrowing the exception.
 185      db_delete('field_config')
 186        ->condition('id', $field['id'])
 187        ->execute();
 188      throw $e;
 189    }
 190  
 191    // Clear caches
 192    field_cache_clear(TRUE);
 193  
 194    // Invoke external hooks after the cache is cleared for API consistency.
 195    module_invoke_all('field_create_field', $field);
 196  
 197    return $field;
 198  }
 199  
 200  /**
 201   * Updates a field.
 202   *
 203   * Any module may forbid any update for any reason. For example, the
 204   * field's storage module might forbid an update if it would change
 205   * the storage schema while data for the field exists. A field type
 206   * module might forbid an update if it would change existing data's
 207   * semantics, or if there are external dependencies on field settings
 208   * that cannot be updated.
 209   *
 210   * @param $field
 211   *   A field structure. $field['field_name'] must provided; it
 212   *   identifies the field that will be updated to match this
 213   *   structure. Any other properties of the field that are not
 214   *   specified in $field will be left unchanged, so it is not
 215   *   necessary to pass in a fully populated $field structure.
 216   * @return
 217   *   Throws a FieldException if the update cannot be performed.
 218   * @see field_create_field()
 219   */
 220  function field_update_field($field) {
 221    // Check that the specified field exists.
 222    $prior_field = field_read_field($field['field_name']);
 223    if (empty($prior_field)) {
 224      throw new FieldException('Attempt to update a non-existent field.');
 225    }
 226  
 227    // Use the prior field values for anything not specifically set by the new
 228    // field to be sure that all values are set.
 229    $field += $prior_field;
 230    $field['settings'] += $prior_field['settings'];
 231  
 232    // Some updates are always disallowed.
 233    if ($field['type'] != $prior_field['type']) {
 234      throw new FieldException("Cannot change an existing field's type.");
 235    }
 236    if ($field['entity_types'] != $prior_field['entity_types']) {
 237      throw new FieldException("Cannot change an existing field's entity_types property.");
 238    }
 239    if ($field['storage']['type'] != $prior_field['storage']['type']) {
 240      throw new FieldException("Cannot change an existing field's storage type.");
 241    }
 242  
 243    // Collect the new storage information, since what is in
 244    // $prior_field may no longer be right.
 245    module_load_install($field['module']);
 246    $schema = (array) module_invoke($field['module'], 'field_schema', $field);
 247    $schema += array('columns' => array(), 'indexes' => array());
 248    // 'columns' are hardcoded in the field type.
 249    $field['columns'] = $schema['columns'];
 250    // 'indexes' can be both hardcoded in the field type, and specified in the
 251    // incoming $field definition.
 252    $field += array(
 253      'indexes' => array(),
 254    );
 255    $field['indexes'] += $schema['indexes'];
 256  
 257    $has_data = field_has_data($field);
 258  
 259    // See if any module forbids the update by throwing an exception.
 260    foreach (module_implements('field_update_forbid') as $module) {
 261      $function = $module . '_field_update_forbid';
 262      $function($field, $prior_field, $has_data);
 263    }
 264  
 265    // Tell the storage engine to update the field. Do this before
 266    // saving the new definition since it still might fail.
 267    $storage_type = field_info_storage_types($field['storage']['type']);
 268    module_invoke($storage_type['module'], 'field_storage_update_field', $field, $prior_field, $has_data);
 269  
 270    // Save the new field definition. @todo: refactor with
 271    // field_create_field.
 272  
 273    // The serialized 'data' column contains everything from $field that does not
 274    // have its own column and is not automatically populated when the field is
 275    // read.
 276    $data = $field;
 277    unset($data['columns'], $data['field_name'], $data['type'], $data['locked'], $data['module'], $data['cardinality'], $data['active'], $data['deleted']);
 278    // Additionally, do not save the 'bundles' property populated by
 279    // field_info_field().
 280    unset($data['bundles']);
 281  
 282    $field['data'] = $data;
 283  
 284    // Store the field and create the id.
 285    $primary_key = array('id');
 286    drupal_write_record('field_config', $field, $primary_key);
 287  
 288    // Clear caches
 289    field_cache_clear(TRUE);
 290  
 291    // Invoke external hooks after the cache is cleared for API consistency.
 292    module_invoke_all('field_update_field', $field, $prior_field, $has_data);
 293  }
 294  
 295  /**
 296   * Reads a single field record directly from the database.
 297   *
 298   * Generally, you should use the field_info_field() instead.
 299   *
 300   * This function will not return deleted fields. Use
 301   * field_read_fields() instead for this purpose.
 302   *
 303   * @param $field_name
 304   *   The field name to read.
 305   * @param array $include_additional
 306   *   The default behavior of this function is to not return a field that
 307   *   is inactive. Setting
 308   *   $include_additional['include_inactive'] to TRUE will override this
 309   *   behavior.
 310   * @return
 311   *   A field definition array, or FALSE.
 312   */
 313  function field_read_field($field_name, $include_additional = array()) {
 314    $fields = field_read_fields(array('field_name' => $field_name), $include_additional);
 315    return $fields ? current($fields) : FALSE;
 316  }
 317  
 318  /**
 319   * Reads in fields that match an array of conditions.
 320   *
 321   * @param array $params
 322   *   An array of conditions to match against.
 323   * @param array $include_additional
 324   *   The default behavior of this function is to not return fields that
 325   *   are inactive or have been deleted. Setting
 326   *   $include_additional['include_inactive'] or
 327   *   $include_additional['include_deleted'] to TRUE will override this
 328   *   behavior.
 329   * @return
 330   *   An array of fields matching $params. If
 331   *   $include_additional['include_deleted'] is TRUE, the array is keyed
 332   *   by field id, otherwise it is keyed by field name.
 333   */
 334  function field_read_fields($params = array(), $include_additional = array()) {
 335    $query = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC));
 336    $query->fields('fc');
 337  
 338    // Turn the conditions into a query.
 339    foreach ($params as $key => $value) {
 340      $query->condition($key, $value);
 341    }
 342    if (!isset($include_additional['include_inactive']) || !$include_additional['include_inactive']) {
 343      $query
 344        ->condition('fc.active', 1)
 345        ->condition('fc.storage_active', 1);
 346    }
 347    $include_deleted = (isset($include_additional['include_deleted']) && $include_additional['include_deleted']);
 348    if (!$include_deleted) {
 349      $query->condition('fc.deleted', 0);
 350    }
 351  
 352    $fields = array();
 353    $results = $query->execute();
 354    foreach ($results as $record) {
 355      $field = unserialize($record['data']);
 356      $field['id'] = $record['id'];
 357      $field['field_name'] = $record['field_name'];
 358      $field['type'] = $record['type'];
 359      $field['module'] = $record['module'];
 360      $field['active'] = $record['active'];
 361      $field['storage']['type'] = $record['storage_type'];
 362      $field['storage']['module'] = $record['storage_module'];
 363      $field['storage']['active'] = $record['storage_active'];
 364      $field['locked'] = $record['locked'];
 365      $field['cardinality'] = $record['cardinality'];
 366      $field['translatable'] = $record['translatable'];
 367      $field['deleted'] = $record['deleted'];
 368  
 369      module_invoke_all('field_read_field', $field);
 370  
 371      // Populate storage information.
 372      module_load_install($field['module']);
 373      $schema = (array) module_invoke($field['module'], 'field_schema', $field);
 374      $schema += array('columns' => array(), 'indexes' => array());
 375      $field['columns'] = $schema['columns'];
 376  
 377      $field_name = $field['field_name'];
 378      if ($include_deleted) {
 379        $field_name = $field['id'];
 380      }
 381      $fields[$field_name] = $field;
 382    }
 383    return $fields;
 384  }
 385  
 386  /**
 387   * Marks a field and its instances and data for deletion.
 388   *
 389   * @param $field_name
 390   *   The field name to delete.
 391   */
 392  function field_delete_field($field_name) {
 393    // Delete all non-deleted instances.
 394    $field = field_info_field($field_name);
 395    if (isset($field['bundles'])) {
 396      foreach ($field['bundles'] as $entity_type => $bundles) {
 397        foreach ($bundles as $bundle) {
 398          $instance = field_info_instance($entity_type, $field_name, $bundle);
 399          field_delete_instance($instance, FALSE);
 400        }
 401      }
 402    }
 403  
 404    // Mark field data for deletion.
 405    module_invoke($field['storage']['module'], 'field_storage_delete_field', $field);
 406  
 407    // Mark the field for deletion.
 408    db_update('field_config')
 409      ->fields(array('deleted' => 1))
 410      ->condition('field_name', $field_name)
 411      ->execute();
 412  
 413    // Clear the cache.
 414    field_cache_clear(TRUE);
 415  
 416    module_invoke_all('field_delete_field', $field);
 417  }
 418  
 419  /**
 420   * Creates an instance of a field, binding it to a bundle.
 421   *
 422   * @param $instance
 423   *   A field instance definition array. The field_name, entity_type and
 424   *   bundle properties are required. Other properties, if omitted,
 425   *   will be given the following default values:
 426   *   - label: the field name
 427   *   - description: empty string
 428   *   - required: FALSE
 429   *   - default_value_function: empty string
 430   *   - settings: each omitted setting is given the default value specified in
 431   *     hook_field_info().
 432   *   - widget:
 433   *     - type: the default widget specified in hook_field_info().
 434   *     - settings: each omitted setting is given the default value specified in
 435   *       hook_field_widget_info().
 436   *   - display:
 437   *     Settings for the 'default' view mode will be added if not present, and
 438   *     each view mode in the definition will be completed with the following
 439   *     default values:
 440   *     - label: 'above'
 441   *     - type: the default formatter specified in hook_field_info().
 442   *     - settings: each omitted setting is given the default value specified in
 443   *       hook_field_formatter_info().
 444   *     View modes not present in the definition are left empty, and the field
 445   *     will not be displayed in this mode.
 446   *
 447   * @return
 448   *   The $instance array with the id property filled in.
 449   *
 450   * @throws FieldException
 451   *
 452   * See: @link field Field API data structures @endlink.
 453   */
 454  function field_create_instance($instance) {
 455    $field = field_read_field($instance['field_name']);
 456    if (empty($field)) {
 457      throw new FieldException(t("Attempt to create an instance of a field @field_name that doesn't exist or is currently inactive.", array('@field_name' => $instance['field_name'])));
 458    }
 459    // Check that the required properties exists.
 460    if (empty($instance['entity_type'])) {
 461      throw new FieldException(t('Attempt to create an instance of field @field_name without an entity type.', array('@field_name' => $instance['field_name'])));
 462    }
 463    if (empty($instance['bundle'])) {
 464      throw new FieldException(t('Attempt to create an instance of field @field_name without a bundle.', array('@field_name' => $instance['field_name'])));
 465    }
 466    // Check that the field can be attached to this entity type.
 467    if (!empty($field['entity_types']) && !in_array($instance['entity_type'], $field['entity_types'])) {
 468      throw new FieldException(t('Attempt to create an instance of field @field_name on forbidden entity type @entity_type.', array('@field_name' => $instance['field_name'], '@entity_type' => $instance['entity_type'])));
 469    }
 470  
 471    // Set the field id.
 472    $instance['field_id'] = $field['id'];
 473  
 474    // Note that we do *not* prevent creating a field on non-existing bundles,
 475    // because that would break the 'Body as field' upgrade for contrib
 476    // node types.
 477  
 478    // TODO: Check that the widget type is known and can handle the field type ?
 479    // TODO: Check that the formatters are known and can handle the field type ?
 480    // TODO: Check that the display view modes are known for the entity type ?
 481    // Those checks should probably happen in _field_write_instance() ?
 482    // Problem : this would mean that a UI module cannot update an instance with a disabled formatter.
 483  
 484    // Ensure the field instance is unique within the bundle.
 485    // We only check for instances of active fields, since adding an instance of
 486    // a disabled field is not supported.
 487    $prior_instance = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
 488    if (!empty($prior_instance)) {
 489      $message = t('Attempt to create an instance of field @field_name on bundle @bundle that already has an instance of that field.', array('@field_name' => $instance['field_name'], '@bundle' => $instance['bundle']));
 490      throw new FieldException($message);
 491    }
 492  
 493    _field_write_instance($instance);
 494  
 495    // Clear caches
 496    field_cache_clear();
 497  
 498    // Invoke external hooks after the cache is cleared for API consistency.
 499    module_invoke_all('field_create_instance', $instance);
 500  
 501    return $instance;
 502  }
 503  
 504  /**
 505   * Updates an instance of a field.
 506   *
 507   * @param $instance
 508   *   An associative array representing an instance structure. The required
 509   *   keys and values are:
 510   *   - entity_type: The type of the entity the field is attached to.
 511   *   - bundle: The bundle this field belongs to.
 512   *   - field_name: The name of an existing field.
 513   *   Read-only_id properties are assigned automatically. Any other
 514   *   properties specified in $instance overwrite the existing values for
 515   *   the instance.
 516   *
 517   * @throws FieldException
 518   *
 519   * @see field_create_instance()
 520   */
 521  function field_update_instance($instance) {
 522    // Check that the specified field exists.
 523    $field = field_read_field($instance['field_name']);
 524    if (empty($field)) {
 525      throw new FieldException(t('Attempt to update an instance of a nonexistent field @field.', array('@field' => $instance['field_name'])));
 526    }
 527  
 528    // Check that the field instance exists (even if it is inactive, since we
 529    // want to be able to replace inactive widgets with new ones).
 530    $prior_instance = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle'], array('include_inactive' => TRUE));
 531    if (empty($prior_instance)) {
 532      throw new FieldException(t("Attempt to update an instance of field @field on bundle @bundle that doesn't exist.", array('@field' => $instance['field_name'], '@bundle' => $instance['bundle'])));
 533    }
 534  
 535    $instance['id'] = $prior_instance['id'];
 536    $instance['field_id'] = $prior_instance['field_id'];
 537  
 538    _field_write_instance($instance, TRUE);
 539  
 540    // Clear caches.
 541    field_cache_clear();
 542  
 543    module_invoke_all('field_update_instance', $instance, $prior_instance);
 544  }
 545  
 546  /**
 547   * Stores an instance record in the field configuration database.
 548   *
 549   * @param $instance
 550   *   An instance structure.
 551   * @param $update
 552   *   Whether this is a new or existing instance.
 553   */
 554  function _field_write_instance($instance, $update = FALSE) {
 555    $field = field_read_field($instance['field_name']);
 556    $field_type = field_info_field_types($field['type']);
 557  
 558    // Set defaults.
 559    $instance += array(
 560      'settings' => array(),
 561      'display' => array(),
 562      'widget' => array(),
 563      'required' => FALSE,
 564      'label' => $instance['field_name'],
 565      'description' => '',
 566      'deleted' => 0,
 567    );
 568  
 569    // Set default instance settings.
 570    $instance['settings'] += field_info_instance_settings($field['type']);
 571  
 572    // Set default widget and settings.
 573    $instance['widget'] += array(
 574      // TODO: what if no 'default_widget' specified ?
 575      'type' => $field_type['default_widget'],
 576      'settings' => array(),
 577    );
 578    // If no weight specified, make sure the field sinks at the bottom.
 579    if (!isset($instance['widget']['weight'])) {
 580      $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], 'form');
 581      $instance['widget']['weight'] = isset($max_weight) ? $max_weight + 1 : 0;
 582    }
 583    // Check widget module.
 584    $widget_type = field_info_widget_types($instance['widget']['type']);
 585    $instance['widget']['module'] = $widget_type['module'];
 586    $instance['widget']['settings'] += field_info_widget_settings($instance['widget']['type']);
 587  
 588    // Make sure there are at least display settings for the 'default' view mode,
 589    // and fill in defaults for each view mode specified in the definition.
 590    $instance['display'] += array(
 591      'default' => array(),
 592    );
 593    foreach ($instance['display'] as $view_mode => $display) {
 594      $display += array(
 595        'label' => 'above',
 596        'type' => isset($field_type['default_formatter']) ? $field_type['default_formatter'] : 'hidden',
 597        'settings' => array(),
 598      );
 599      if ($display['type'] != 'hidden') {
 600        $formatter_type = field_info_formatter_types($display['type']);
 601        $display['module'] = $formatter_type['module'];
 602        $display['settings'] += field_info_formatter_settings($display['type']);
 603      }
 604      // If no weight specified, make sure the field sinks at the bottom.
 605      if (!isset($display['weight'])) {
 606        $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], $view_mode);
 607        $display['weight'] = isset($max_weight) ? $max_weight + 1 : 0;
 608      }
 609      $instance['display'][$view_mode] = $display;
 610    }
 611  
 612    // The serialized 'data' column contains everything from $instance that does
 613    // not have its own column and is not automatically populated when the
 614    // instance is read.
 615    $data = $instance;
 616    unset($data['id'], $data['field_id'], $data['field_name'], $data['entity_type'], $data['bundle'], $data['deleted']);
 617  
 618    $record = array(
 619      'field_id' => $instance['field_id'],
 620      'field_name' => $instance['field_name'],
 621      'entity_type' => $instance['entity_type'],
 622      'bundle' => $instance['bundle'],
 623      'data' => $data,
 624      'deleted' => $instance['deleted'],
 625    );
 626    // We need to tell drupal_update_record() the primary keys to trigger an
 627    // update.
 628    if ($update) {
 629      $record['id'] = $instance['id'];
 630      $primary_key = array('id');
 631    }
 632    else {
 633      $primary_key = array();
 634    }
 635    drupal_write_record('field_config_instance', $record, $primary_key);
 636  }
 637  
 638  /**
 639   * Reads a single instance record from the database.
 640   *
 641   * Generally, you should use field_info_instance() instead, as it
 642   * provides caching and allows other modules the opportunity to
 643   * append additional formatters, widgets, and other information.
 644   *
 645   * @param $entity_type
 646   *   The type of entity to which the field is bound.
 647   * @param $field_name
 648   *   The field name to read.
 649   * @param $bundle
 650   *   The bundle to which the field is bound.
 651   * @param array $include_additional
 652   *   The default behavior of this function is to not return an instance that
 653   *   has been deleted, or whose field is inactive. Setting
 654   *   $include_additional['include_inactive'] or
 655   *   $include_additional['include_deleted'] to TRUE will override this
 656   *   behavior.
 657   * @return
 658   *   An instance structure, or FALSE.
 659   */
 660  function field_read_instance($entity_type, $field_name, $bundle, $include_additional = array()) {
 661    $instances = field_read_instances(array('entity_type' => $entity_type, 'field_name' => $field_name, 'bundle' => $bundle), $include_additional);
 662    return $instances ? current($instances) : FALSE;
 663  }
 664  
 665  /**
 666   * Reads in field instances that match an array of conditions.
 667   *
 668   * @param $param
 669   *   An array of properties to use in selecting a field
 670   *   instance. Valid keys include any column of the
 671   *   field_config_instance table. If NULL, all instances will be returned.
 672   * @param $include_additional
 673   *   The default behavior of this function is to not return field
 674   *   instances that have been marked deleted, or whose field is inactive.
 675   *   Setting $include_additional['include_inactive'] or
 676   *   $include_additional['include_deleted'] to TRUE will override this
 677   *   behavior.
 678   * @return
 679   *   An array of instances matching the arguments.
 680   */
 681  function field_read_instances($params = array(), $include_additional = array()) {
 682    $include_inactive = isset($include_additional['include_inactive']) && $include_additional['include_inactive'];
 683    $include_deleted = isset($include_additional['include_deleted']) && $include_additional['include_deleted'];
 684  
 685    $query = db_select('field_config_instance', 'fci', array('fetch' => PDO::FETCH_ASSOC));
 686    $query->join('field_config', 'fc', 'fc.id = fci.field_id');
 687    $query->fields('fci');
 688  
 689    // Turn the conditions into a query.
 690    foreach ($params as $key => $value) {
 691      $query->condition('fci.' . $key, $value);
 692    }
 693    if (!$include_inactive) {
 694      $query
 695        ->condition('fc.active', 1)
 696        ->condition('fc.storage_active', 1);
 697    }
 698    if (!$include_deleted) {
 699      $query->condition('fc.deleted', 0);
 700      $query->condition('fci.deleted', 0);
 701    }
 702  
 703    $instances = array();
 704    $results = $query->execute();
 705  
 706    foreach ($results as $record) {
 707      // Filter out instances on unknown entity types (for instance because the
 708      // module exposing them was disabled).
 709      $entity_info = entity_get_info($record['entity_type']);
 710      if ($include_inactive || $entity_info) {
 711        $instance = unserialize($record['data']);
 712        $instance['id'] = $record['id'];
 713        $instance['field_id'] = $record['field_id'];
 714        $instance['field_name'] = $record['field_name'];
 715        $instance['entity_type'] = $record['entity_type'];
 716        $instance['bundle'] = $record['bundle'];
 717        $instance['deleted'] = $record['deleted'];
 718  
 719        module_invoke_all('field_read_instance', $instance);
 720        $instances[] = $instance;
 721      }
 722    }
 723    return $instances;
 724  }
 725  
 726  /**
 727   * Marks a field instance and its data for deletion.
 728   *
 729   * @param $instance
 730   *   An instance structure.
 731   * @param $field_cleanup
 732   *   If TRUE, the field will be deleted as well if its last instance is being
 733   *   deleted. If FALSE, it is the caller's responsibility to handle the case of
 734   *   fields left without instances. Defaults to TRUE.
 735   */
 736  function field_delete_instance($instance, $field_cleanup = TRUE) {
 737    // Mark the field instance for deletion.
 738    db_update('field_config_instance')
 739      ->fields(array('deleted' => 1))
 740      ->condition('field_name', $instance['field_name'])
 741      ->condition('entity_type', $instance['entity_type'])
 742      ->condition('bundle', $instance['bundle'])
 743      ->execute();
 744  
 745    // Clear the cache.
 746    field_cache_clear();
 747  
 748    // Mark instance data for deletion.
 749    $field = field_info_field($instance['field_name']);
 750    module_invoke($field['storage']['module'], 'field_storage_delete_instance', $instance);
 751  
 752    // Let modules react to the deletion of the instance.
 753    module_invoke_all('field_delete_instance', $instance);
 754  
 755    // Delete the field itself if we just deleted its last instance.
 756    if ($field_cleanup && count($field['bundles']) == 0) {
 757      field_delete_field($field['field_name']);
 758    }
 759  }
 760  
 761  /**
 762   * @} End of "defgroup field_crud".
 763   */
 764  
 765  /**
 766   * @defgroup field_purge Field API bulk data deletion
 767   * @{
 768   * Clean up after Field API bulk deletion operations.
 769   *
 770   * Field API provides functions for deleting data attached to individual
 771   * entities as well as deleting entire fields or field instances in a single
 772   * operation.
 773   *
 774   * Deleting field data items for an entity with field_attach_delete() involves
 775   * three separate operations:
 776   * - Invoking the Field Type API hook_field_delete() for each field on the
 777   * entity. The hook for each field type receives the entity and the specific
 778   * field being deleted. A file field module might use this hook to delete
 779   * uploaded files from the filesystem.
 780   * - Invoking the Field Storage API hook_field_storage_delete() to remove
 781   * data from the primary field storage. The hook implementation receives the
 782   * entity being deleted and deletes data for all of the entity's bundle's
 783   * fields.
 784   * - Invoking the global Field Attach API hook_field_attach_delete() for all
 785   * modules that implement it. Each hook implementation receives the entity
 786   * being deleted and can operate on whichever subset of the entity's bundle's
 787   * fields it chooses to.
 788   *
 789   * These hooks are invoked immediately when field_attach_delete() is
 790   * called. Similar operations are performed for field_attach_delete_revision().
 791   *
 792   * When a field, bundle, or field instance is deleted, it is not practical to
 793   * invoke these hooks immediately on every affected entity in a single page
 794   * request; there could be thousands or millions of them. Instead, the
 795   * appropriate field data items, instances, and/or fields are marked as deleted
 796   * so that subsequent load or query operations will not return them. Later, a
 797   * separate process cleans up, or "purges", the marked-as-deleted data by going
 798   * through the three-step process described above and, finally, removing
 799   * deleted field and instance records.
 800   *
 801   * Purging field data is made somewhat tricky by the fact that, while
 802   * field_attach_delete() has a complete entity to pass to the various deletion
 803   * hooks, the Field API purge process only has the field data it has previously
 804   * stored. It cannot reconstruct complete original entities to pass to the
 805   * deletion hooks. It is even possible that the original entity to which some
 806   * Field API data was attached has been itself deleted before the field purge
 807   * operation takes place.
 808   *
 809   * Field API resolves this problem by using "pseudo-entities" during purge
 810   * operations. A pseudo-entity contains only the information from the original
 811   * entity that Field API knows about: entity type, id, revision id, and
 812   * bundle. It also contains the field data for whichever field instance is
 813   * currently being purged. For example, suppose that the node type 'story' used
 814   * to contain a field called 'subtitle' but the field was deleted. If node 37
 815   * was a story with a subtitle, the pseudo-entity passed to the purge hooks
 816   * would look something like this:
 817   *
 818   * @code
 819   *   $entity = stdClass Object(
 820   *     [nid] => 37,
 821   *     [vid] => 37,
 822   *     [type] => 'story',
 823   *     [subtitle] => array(
 824   *       [0] => array(
 825   *         'value' => 'subtitle text',
 826   *       ),
 827   *     ),
 828   *   );
 829   * @endcode
 830   *
 831   * See @link field Field API @endlink for information about the other parts of
 832   * the Field API.
 833   */
 834  
 835  /**
 836   * Purges a batch of deleted Field API data, instances, or fields.
 837   *
 838   * This function will purge deleted field data in batches. The batch size
 839   * is defined as an argument to the function, and once each batch is finished,
 840   * it continues with the next batch until all have completed. If a deleted field
 841   * instance with no remaining data records is found, the instance itself will
 842   * be purged. If a deleted field with no remaining field instances is found, the
 843   * field itself will be purged.
 844   *
 845   * @param $batch_size
 846   *   The maximum number of field data records to purge before returning.
 847   */
 848  function field_purge_batch($batch_size) {
 849    // Retrieve all deleted field instances. We cannot use field_info_instances()
 850    // because that function does not return deleted instances.
 851    $instances = field_read_instances(array('deleted' => 1), array('include_deleted' => 1));
 852  
 853    foreach ($instances as $instance) {
 854      // field_purge_data() will need the field array.
 855      $field = field_info_field_by_id($instance['field_id']);
 856      // Retrieve some entities.
 857      $query = new EntityFieldQuery();
 858      $results = $query
 859        ->fieldCondition($field)
 860        ->entityCondition('bundle', $instance['bundle'])
 861        ->deleted(TRUE)
 862        ->range(0, $batch_size)
 863        ->execute();
 864  
 865      if ($results) {
 866        foreach ($results as $entity_type => $stub_entities) {
 867          field_attach_load($entity_type, $stub_entities, FIELD_LOAD_CURRENT, array('field_id' => $field['id'], 'deleted' => 1));
 868          foreach ($stub_entities as $stub_entity) {
 869            // Purge the data for the entity.
 870            field_purge_data($entity_type, $stub_entity, $field, $instance);
 871          }
 872        }
 873      }
 874      else {
 875        // No field data remains for the instance, so we can remove it.
 876        field_purge_instance($instance);
 877      }
 878    }
 879  
 880    // Retrieve all deleted fields. Any that have no instances can be purged.
 881    $fields = field_read_fields(array('deleted' => 1), array('include_deleted' => 1));
 882    foreach ($fields as $field) {
 883      $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1));
 884      if (empty($instances)) {
 885        field_purge_field($field);
 886      }
 887    }
 888  }
 889  
 890  /**
 891   * Purges the field data for a single field on a single pseudo-entity.
 892   *
 893   * This is basically the same as field_attach_delete() except it only applies
 894   * to a single field. The entity itself is not being deleted, and it is quite
 895   * possible that other field data will remain attached to it.
 896   *
 897   * @param $entity_type
 898   *   The type of $entity; e.g. 'node' or 'user'.
 899   * @param $entity
 900   *   The pseudo-entity whose field data is being purged.
 901   * @param $field
 902   *   The (possibly deleted) field whose data is being purged.
 903   * @param $instance
 904   *   The deleted field instance whose data is being purged.
 905   */
 906  function field_purge_data($entity_type, $entity, $field, $instance) {
 907    // Each field type's hook_field_delete() only expects to operate on a single
 908    // field at a time, so we can use it as-is for purging.
 909    $options = array('field_id' => $instance['field_id'], 'deleted' => TRUE);
 910    _field_invoke('delete', $entity_type, $entity, $dummy, $dummy, $options);
 911  
 912    // Tell the field storage system to purge the data.
 913    module_invoke($field['storage']['module'], 'field_storage_purge', $entity_type, $entity, $field, $instance);
 914  
 915    // Let other modules act on purging the data.
 916    foreach (module_implements('field_attach_purge') as $module) {
 917      $function = $module . '_field_attach_purge';
 918      $function($entity_type, $entity, $field, $instance);
 919    }
 920  }
 921  
 922  /**
 923   * Purges a field instance record from the database.
 924   *
 925   * This function assumes all data for the instance has already been purged, and
 926   * should only be called by field_purge_batch().
 927   *
 928   * @param $instance
 929   *   The instance record to purge.
 930   */
 931  function field_purge_instance($instance) {
 932    db_delete('field_config_instance')
 933      ->condition('id', $instance['id'])
 934      ->execute();
 935  
 936    // Notify the storage engine.
 937    $field = field_info_field_by_id($instance['field_id']);
 938    module_invoke($field['storage']['module'], 'field_storage_purge_instance', $instance);
 939  
 940    // Clear the cache.
 941    field_info_cache_clear();
 942  
 943    // Invoke external hooks after the cache is cleared for API consistency.
 944    module_invoke_all('field_purge_instance', $instance);
 945  }
 946  
 947  /**
 948   * Purges a field record from the database.
 949   *
 950   * This function assumes all instances for the field has already been purged,
 951   * and should only be called by field_purge_batch().
 952   *
 953   * @param $field
 954   *   The field record to purge.
 955   */
 956  function field_purge_field($field) {
 957    $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1));
 958    if (count($instances) > 0) {
 959      throw new FieldException(t('Attempt to purge a field @field_name that still has instances.', array('@field_name' => $field['field_name'])));
 960    }
 961  
 962    db_delete('field_config')
 963      ->condition('id', $field['id'])
 964      ->execute();
 965  
 966    // Notify the storage engine.
 967    module_invoke($field['storage']['module'], 'field_storage_purge_field', $field);
 968  
 969    // Clear the cache.
 970    field_info_cache_clear();
 971  
 972    // Invoke external hooks after the cache is cleared for API consistency.
 973    module_invoke_all('field_purge_field', $field);
 974  }
 975  
 976  /**
 977   * @} End of "defgroup field_purge".
 978   */

title

Description

title

Description

title

Description

title

title

Body