field.crud.inc 36.9 KB
Newer Older
1 2
<?php

3 4
/**
 * @file
5
 * Field CRUD API, handling field and field instance creation and deletion.
6 7
 */

8 9 10 11 12 13
/**
 * @defgroup field_crud Field CRUD API
 * @{
 * Create, update, and delete Field API fields, bundles, and instances.
 *
 * 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 20
 */

/**
21
 * Creates a field.
22 23 24
 *
 * This function does not bind the field to any bundle; use
 * field_create_instance() for that.
25 26
 *
 * @param $field
27
 *   A field definition array. The field_name and type properties are required.
28 29 30 31 32 33 34 35 36
 *   Other properties, if omitted, will be given the following default values:
 *   - cardinality: 1
 *   - locked: FALSE
 *   - indexes: the field-type indexes, specified by the field type's
 *     hook_field_schema(). The indexes specified in $field are added
 *     to those default indexes. It is possible to override the
 *     definition of a field-type index by providing an index with the
 *     same name, or to remove it by redefining it as an empty array
 *     of columns. Overriding field-type indexes should be done
37
 *     carefully, for it might seriously affect the site's performance.
38 39
 *   - settings: each omitted setting is given the default value defined in
 *     hook_field_info().
40
 *   - storage:
41
 *     - type: the storage backend specified in the 'field_storage_default'
42 43 44
 *       system variable.
 *     - settings: each omitted setting is given the default value specified in
 *       hook_field_storage_info().
45
 * @return
46
 *   The $field array with the id property filled in.
47 48
 * @throw
 *   FieldException
49
 *
50
 * See: @link field Field API data structures @endlink.
51 52 53 54 55 56
 */
function field_create_field($field) {
  // Field name is required.
  if (empty($field['field_name'])) {
    throw new FieldException('Attempt to create an unnamed field.');
  }
57 58 59 60
  // Field type is required.
  if (empty($field['type'])) {
    throw new FieldException('Attempt to create a field with no type.');
  }
61
  // Field name cannot contain invalid characters.
62 63
  if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $field['field_name'])) {
    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');
64 65
  }

66 67 68 69 70 71 72
  // Field name cannot be longer than 32 characters. We use drupal_strlen()
  // because the DB layer assumes that column widths are given in characters,
  // not bytes.
  if (drupal_strlen($field['field_name']) > 32) {
    throw new FieldException(t('Attempt to create a field with a name longer than 32 characters: %name',
      array('%name' => $field['field_name'])));
  }
73

74 75 76
  // Ensure the field name is unique over active and disabled fields.
  // We do not care about deleted fields.
  $prior_field = field_read_field($field['field_name'], array('include_inactive' => TRUE));
77
  if (!empty($prior_field)) {
78 79 80 81
    $message = $prior_field['active']?
      t('Attempt to create field name %name which already exists and is active.', array('%name' => $field['field_name'])):
      t('Attempt to create field name %name which already exists, although it is inactive.', array('%name' => $field['field_name']));
    throw new FieldException($message);
82 83
  }

84
  // Disallow reserved field names. This can't prevent all field name
85
  // collisions with existing entity properties, but some is better
86
  // than none.
87
  foreach (entity_get_info() as $type => $info) {
88
    if (in_array($field['field_name'], $info['entity keys'])) {
89 90 91 92
      throw new FieldException(t('Attempt to create field name %name which is reserved by entity type %type.', array('%name' => $field['field_name'], '%type' => $type)));
    }
  }

93
  $field += array(
94
    'entity_types' => array(),
95
    'cardinality' => 1,
96
    'translatable' => FALSE,
97 98
    'locked' => FALSE,
    'settings' => array(),
99 100
    'storage' => array(),
    'deleted' => 0,
101
  );
102

103 104 105 106 107
  // Check that the field type is known.
  $field_type = field_info_field_types($field['type']);
  if (!$field_type) {
    throw new FieldException(t('Attempt to create a field of unknown type %type.', array('%type' => $field['type'])));
  }
108 109 110
  // Create all per-field-type properties (needed here as long as we have
  // settings that impact column definitions).
  $field['settings'] += field_info_field_settings($field['type']);
111
  $field['module'] = $field_type['module'];
112
  $field['active'] = 1;
113

114 115 116 117 118 119 120 121 122 123 124 125 126 127
  // Provide default storage.
  $field['storage'] += array(
    'type' => variable_get('field_storage_default', 'field_sql_storage'),
    'settings' => array(),
  );
  // Check that the storage type is known.
  $storage_type = field_info_storage_types($field['storage']['type']);
  if (!$storage_type) {
    throw new FieldException(t('Attempt to create a field with unknown storage type %type.', array('%type' => $field['storage']['type'])));
  }
  // Provide default storage settings.
  $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
  $field['storage']['module'] = $storage_type['module'];
  $field['storage']['active'] = 1;
128
  // Collect storage information.
129
  module_load_install($field['module']);
130
  $schema = (array) module_invoke($field['module'], 'field_schema', $field);
131
  $schema += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array());
132 133
  // 'columns' are hardcoded in the field type.
  $field['columns'] = $schema['columns'];
134 135
  // 'foreign keys' are hardcoded in the field type.
  $field['foreign keys'] = $schema['foreign keys'];
136 137 138 139 140 141 142 143 144 145 146
  // 'indexes' can be both hardcoded in the field type, and specified in the
  // incoming $field definition.
  $field += array(
    'indexes' => array(),
  );
  $field['indexes'] += $schema['indexes'];

  // The serialized 'data' column contains everything from $field that does not
  // have its own column and is not automatically populated when the field is
  // read.
  $data = $field;
147
  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']);
148 149 150
  // Additionally, do not save the 'bundles' property populated by
  // field_info_field().
  unset($data['bundles']);
151

152 153 154 155 156 157 158 159 160 161 162
  $record = array(
    'field_name' => $field['field_name'],
    'type' => $field['type'],
    'module' => $field['module'],
    'active' => $field['active'],
    'storage_type' => $field['storage']['type'],
    'storage_module' => $field['storage']['module'],
    'storage_active' => $field['storage']['active'],
    'locked' => $field['locked'],
    'data' => $data,
    'cardinality' => $field['cardinality'],
163
    'translatable' => $field['translatable'],
164 165
    'deleted' => $field['deleted'],
  );
166

167 168 169
  // Store the field and get the id back.
  drupal_write_record('field_config', $record);
  $field['id'] = $record['id'];
170

171 172
  // Invoke hook_field_storage_create_field after the field is
  // complete (e.g. it has its id).
173
  try {
174 175 176
    // Invoke hook_field_storage_create_field after
    // drupal_write_record() sets the field id.
    module_invoke($storage_type['module'], 'field_storage_create_field', $field);
177 178 179 180 181 182 183 184 185
  }
  catch (Exception $e) {
    // If storage creation failed, remove the field_config record before
    // rethrowing the exception.
    db_delete('field_config')
      ->condition('id', $field['id'])
      ->execute();
    throw $e;
  }
186

187 188
  // Clear caches
  field_cache_clear(TRUE);
189

190 191
  // Invoke external hooks after the cache is cleared for API consistency.
  module_invoke_all('field_create_field', $field);
192

193
  return $field;
194 195
}

196 197
/**
 * Updates a field.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
 *
 * Any module may forbid any update for any reason. For example, the
 * field's storage module might forbid an update if it would change
 * the storage schema while data for the field exists. A field type
 * module might forbid an update if it would change existing data's
 * semantics, or if there are external dependencies on field settings
 * that cannot be updated.
 *
 * @param $field
 *   A field structure. $field['field_name'] must provided; it
 *   identifies the field that will be updated to match this
 *   structure. Any other properties of the field that are not
 *   specified in $field will be left unchanged, so it is not
 *   necessary to pass in a fully populated $field structure.
 * @return
 *   Throws a FieldException if the update cannot be performed.
 * @see field_create_field()
 */
function field_update_field($field) {
  // Check that the specified field exists.
  $prior_field = field_read_field($field['field_name']);
  if (empty($prior_field)) {
    throw new FieldException('Attempt to update a non-existent field.');
  }

223
  // Use the prior field values for anything not specifically set by the new
224 225 226 227
  // field to be sure that all values are set.
  $field += $prior_field;
  $field['settings'] += $prior_field['settings'];

228
  // Some updates are always disallowed.
229 230 231
  if ($field['type'] != $prior_field['type']) {
    throw new FieldException("Cannot change an existing field's type.");
  }
232 233
  if ($field['entity_types'] != $prior_field['entity_types']) {
    throw new FieldException("Cannot change an existing field's entity_types property.");
234
  }
235 236 237
  if ($field['storage']['type'] != $prior_field['storage']['type']) {
    throw new FieldException("Cannot change an existing field's storage type.");
  }
238 239 240

  // Collect the new storage information, since what is in
  // $prior_field may no longer be right.
241
  module_load_install($field['module']);
242 243 244 245 246 247 248 249 250 251 252
  $schema = (array) module_invoke($field['module'], 'field_schema', $field);
  $schema += array('columns' => array(), 'indexes' => array());
  // 'columns' are hardcoded in the field type.
  $field['columns'] = $schema['columns'];
  // 'indexes' can be both hardcoded in the field type, and specified in the
  // incoming $field definition.
  $field += array(
    'indexes' => array(),
  );
  $field['indexes'] += $schema['indexes'];

253
  $has_data = field_has_data($field);
254 255 256 257 258 259 260 261 262

  // See if any module forbids the update by throwing an exception.
  foreach (module_implements('field_update_forbid') as $module) {
    $function = $module . '_field_update_forbid';
    $function($field, $prior_field, $has_data);
  }

  // Tell the storage engine to update the field. Do this before
  // saving the new definition since it still might fail.
263 264
  $storage_type = field_info_storage_types($field['storage']['type']);
  module_invoke($storage_type['module'], 'field_storage_update_field', $field, $prior_field, $has_data);
265 266 267 268 269 270 271 272 273

  // Save the new field definition. @todo: refactor with
  // field_create_field.

  // The serialized 'data' column contains everything from $field that does not
  // have its own column and is not automatically populated when the field is
  // read.
  $data = $field;
  unset($data['columns'], $data['field_name'], $data['type'], $data['locked'], $data['module'], $data['cardinality'], $data['active'], $data['deleted']);
274 275 276 277
  // Additionally, do not save the 'bundles' property populated by
  // field_info_field().
  unset($data['bundles']);

278 279 280 281 282 283 284 285
  $field['data'] = $data;

  // Store the field and create the id.
  $primary_key = array('id');
  drupal_write_record('field_config', $field, $primary_key);

  // Clear caches
  field_cache_clear(TRUE);
286

287
  // Invoke external hooks after the cache is cleared for API consistency.
288
  module_invoke_all('field_update_field', $field, $prior_field, $has_data);
289 290
}

291
/**
292 293 294
 * Reads a single field record directly from the database.
 *
 * Generally, you should use the field_info_field() instead.
295
 *
296 297 298
 * This function will not return deleted fields. Use
 * field_read_fields() instead for this purpose.
 *
299 300 301 302
 * @param $field_name
 *   The field name to read.
 * @param array $include_additional
 *   The default behavior of this function is to not return a field that
303 304
 *   is inactive. Setting
 *   $include_additional['include_inactive'] to TRUE will override this
305 306
 *   behavior.
 * @return
307
 *   A field definition array, or FALSE.
308 309 310 311 312 313 314
 */
function field_read_field($field_name, $include_additional = array()) {
  $fields = field_read_fields(array('field_name' => $field_name), $include_additional);
  return $fields ? current($fields) : FALSE;
}

/**
315
 * Reads in fields that match an array of conditions.
316 317 318 319 320 321 322 323 324 325
 *
 * @param array $params
 *   An array of conditions to match against.
 * @param array $include_additional
 *   The default behavior of this function is to not return fields that
 *   are inactive or have been deleted. Setting
 *   $include_additional['include_inactive'] or
 *   $include_additional['include_deleted'] to TRUE will override this
 *   behavior.
 * @return
326
 *   An array of fields matching $params. If
327
 *   $include_additional['include_deleted'] is TRUE, the array is keyed
328
 *   by field id, otherwise it is keyed by field name.
329 330 331 332 333 334 335 336 337 338
 */
function field_read_fields($params = array(), $include_additional = array()) {
  $query = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC));
  $query->fields('fc');

  // Turn the conditions into a query.
  foreach ($params as $key => $value) {
    $query->condition($key, $value);
  }
  if (!isset($include_additional['include_inactive']) || !$include_additional['include_inactive']) {
339 340 341
    $query
      ->condition('fc.active', 1)
      ->condition('fc.storage_active', 1);
342
  }
343 344
  $include_deleted = (isset($include_additional['include_deleted']) && $include_additional['include_deleted']);
  if (!$include_deleted) {
345 346 347 348 349
    $query->condition('fc.deleted', 0);
  }

  $fields = array();
  $results = $query->execute();
350 351 352 353 354 355 356 357 358 359 360 361 362 363
  foreach ($results as $record) {
    $field = unserialize($record['data']);
    $field['id'] = $record['id'];
    $field['field_name'] = $record['field_name'];
    $field['type'] = $record['type'];
    $field['module'] = $record['module'];
    $field['active'] = $record['active'];
    $field['storage']['type'] = $record['storage_type'];
    $field['storage']['module'] = $record['storage_module'];
    $field['storage']['active'] = $record['storage_active'];
    $field['locked'] = $record['locked'];
    $field['cardinality'] = $record['cardinality'];
    $field['translatable'] = $record['translatable'];
    $field['deleted'] = $record['deleted'];
364 365 366

    module_invoke_all('field_read_field', $field);

367
    // Populate storage information.
368
    module_load_install($field['module']);
369 370 371
    $schema = (array) module_invoke($field['module'], 'field_schema', $field);
    $schema += array('columns' => array(), 'indexes' => array());
    $field['columns'] = $schema['columns'];
372

373 374 375 376 377
    $field_name = $field['field_name'];
    if ($include_deleted) {
      $field_name = $field['id'];
    }
    $fields[$field_name] = $field;
378 379 380 381 382
  }
  return $fields;
}

/**
383
 * Marks a field and its instances and data for deletion.
384 385 386 387 388
 *
 * @param $field_name
 *   The field name to delete.
 */
function field_delete_field($field_name) {
389 390 391
  // Delete all non-deleted instances.
  $field = field_info_field($field_name);
  if (isset($field['bundles'])) {
392
    foreach ($field['bundles'] as $entity_type => $bundles) {
393
      foreach ($bundles as $bundle) {
394
        $instance = field_info_instance($entity_type, $field_name, $bundle);
395
        field_delete_instance($instance, FALSE);
396
      }
397 398 399
    }
  }

400 401
  // Mark field data for deletion.
  module_invoke($field['storage']['module'], 'field_storage_delete_field', $field);
402 403 404

  // Mark the field for deletion.
  db_update('field_config')
405 406 407
    ->fields(array('deleted' => 1))
    ->condition('field_name', $field_name)
    ->execute();
408

409 410
  // Clear the cache.
  field_cache_clear(TRUE);
411 412

  module_invoke_all('field_delete_field', $field);
413 414 415 416 417 418
}

/**
 * Creates an instance of a field, binding it to a bundle.
 *
 * @param $instance
419
 *   A field instance definition array. The field_name, entity_type and
420 421
 *   bundle properties are required. Other properties, if omitted,
 *   will be given the following default values:
422 423 424 425 426 427 428 429 430 431 432
 *   - label: the field name
 *   - description: empty string
 *   - required: FALSE
 *   - default_value_function: empty string
 *   - settings: each omitted setting is given the default value specified in
 *     hook_field_info().
 *   - widget:
 *     - type: the default widget specified in hook_field_info().
 *     - settings: each omitted setting is given the default value specified in
 *       hook_field_widget_info().
 *   - display:
433 434 435
 *     Settings for the 'default' view mode will be added if not present, and
 *     each view mode in the definition will be completed with the following
 *     default values:
436 437 438 439
 *     - label: 'above'
 *     - type: the default formatter specified in hook_field_info().
 *     - settings: each omitted setting is given the default value specified in
 *       hook_field_formatter_info().
440 441 442
 *     View modes not present in the definition are left empty, and the field
 *     will not be displayed in this mode.
 *
443
 * @return
444
 *   The $instance array with the id property filled in.
445 446
 * @throw
 *   FieldException
447
 *
448
 * See: @link field Field API data structures @endlink.
449 450 451 452
 */
function field_create_instance($instance) {
  $field = field_read_field($instance['field_name']);
  if (empty($field)) {
453
    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'])));
454
  }
455
  // Check that the required properties exists.
456
  if (empty($instance['entity_type'])) {
457
    throw new FieldException(t('Attempt to create an instance of field @field_name without an entity type.', array('@field_name' => $instance['field_name'])));
458 459 460 461
  }
  if (empty($instance['bundle'])) {
    throw new FieldException(t('Attempt to create an instance of field @field_name without a bundle.', array('@field_name' => $instance['field_name'])));
  }
462
  // Check that the field can be attached to this entity type.
463
  if (!empty($field['entity_types']) && !in_array($instance['entity_type'], $field['entity_types'])) {
464
    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'])));
465
  }
466

467 468 469
  // Set the field id.
  $instance['field_id'] = $field['id'];

470 471 472
  // Note that we do *not* prevent creating a field on non-existing bundles,
  // because that would break the 'Body as field' upgrade for contrib
  // node types.
473 474 475

  // TODO: Check that the widget type is known and can handle the field type ?
  // TODO: Check that the formatters are known and can handle the field type ?
476
  // TODO: Check that the display view modes are known for the entity type ?
477 478 479
  // Those checks should probably happen in _field_write_instance() ?
  // Problem : this would mean that a UI module cannot update an instance with a disabled formatter.

480 481 482
  // Ensure the field instance is unique within the bundle.
  // We only check for instances of active fields, since adding an instance of
  // a disabled field is not supported.
483
  $prior_instance = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
484
  if (!empty($prior_instance)) {
485
    $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']));
486
    throw new FieldException($message);
487 488 489 490 491 492
  }

  _field_write_instance($instance);

  // Clear caches
  field_cache_clear();
493 494 495 496

  // Invoke external hooks after the cache is cleared for API consistency.
  module_invoke_all('field_create_instance', $instance);

497
  return $instance;
498 499
}

500 501
/**
 * Updates an instance of a field.
502 503
 *
 * @param $instance
504
 *   An associative array representing an instance structure. The required
505
 *   keys and values are:
506 507 508
 *   - entity_type: The type of the entity the field is attached to.
 *   - bundle: The bundle this field belongs to.
 *   - field_name: The name of an existing field.
509 510 511
 *   Read-only_id properties are assigned automatically. Any other
 *   properties specified in $instance overwrite the existing values for
 *   the instance.
512
 *
513 514
 * @throw
 *   FieldException
515
 *
516 517 518 519 520 521
 * @see field_create_instance()
 */
function field_update_instance($instance) {
  // Check that the specified field exists.
  $field = field_read_field($instance['field_name']);
  if (empty($field)) {
522
    throw new FieldException(t('Attempt to update an instance of a nonexistent field @field.', array('@field' => $instance['field_name'])));
523 524 525 526
  }

  // Check that the field instance exists (even if it is inactive, since we
  // want to be able to replace inactive widgets with new ones).
527
  $prior_instance = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle'], array('include_inactive' => TRUE));
528
  if (empty($prior_instance)) {
529
    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'])));
530 531
  }

532 533 534
  $instance['id'] = $prior_instance['id'];
  $instance['field_id'] = $prior_instance['field_id'];

535 536 537 538
  _field_write_instance($instance, TRUE);

  // Clear caches.
  field_cache_clear();
539 540

  module_invoke_all('field_update_instance', $instance, $prior_instance);
541 542 543
}

/**
544
 * Stores an instance record in the field configuration database.
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
 *
 * @param $instance
 *   An instance structure.
 * @param $update
 *   Whether this is a new or existing instance.
 */
function _field_write_instance($instance, $update = FALSE) {
  $field = field_read_field($instance['field_name']);
  $field_type = field_info_field_types($field['type']);

  // Set defaults.
  $instance += array(
    'settings' => array(),
    'display' => array(),
    'widget' => array(),
    'required' => FALSE,
    'label' => $instance['field_name'],
    'description' => '',
    'deleted' => 0,
  );

  // Set default instance settings.
  $instance['settings'] += field_info_instance_settings($field['type']);

  // Set default widget and settings.
  $instance['widget'] += array(
    // TODO: what if no 'default_widget' specified ?
    'type' => $field_type['default_widget'],
    'settings' => array(),
  );
575 576
  // If no weight specified, make sure the field sinks at the bottom.
  if (!isset($instance['widget']['weight'])) {
577
    $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], 'form');
578
    $instance['widget']['weight'] = isset($max_weight) ? $max_weight + 1 : 0;
579
  }
580 581
  // Check widget module.
  $widget_type = field_info_widget_types($instance['widget']['type']);
582
  $instance['widget']['module'] = $widget_type['module'];
583 584
  $instance['widget']['settings'] += field_info_widget_settings($instance['widget']['type']);

585 586
  // Make sure there are at least display settings for the 'default' view mode,
  // and fill in defaults for each view mode specified in the definition.
587
  $instance['display'] += array(
588
    'default' => array(),
589
  );
590
  foreach ($instance['display'] as $view_mode => $display) {
591
    $display += array(
592
      'label' => 'above',
593
      'type' => isset($field_type['default_formatter']) ? $field_type['default_formatter'] : 'hidden',
594 595
      'settings' => array(),
    );
596 597 598 599 600 601 602
    if ($display['type'] != 'hidden') {
      $formatter_type = field_info_formatter_types($display['type']);
      $display['module'] = $formatter_type['module'];
      $display['settings'] += field_info_formatter_settings($display['type']);
    }
    // If no weight specified, make sure the field sinks at the bottom.
    if (!isset($display['weight'])) {
603
      $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], $view_mode);
604
      $display['weight'] = isset($max_weight) ? $max_weight + 1 : 0;
605 606
    }
    $instance['display'][$view_mode] = $display;
607 608
  }

609 610 611
  // The serialized 'data' column contains everything from $instance that does
  // not have its own column and is not automatically populated when the
  // instance is read.
612
  $data = $instance;
613
  unset($data['id'], $data['field_id'], $data['field_name'], $data['entity_type'], $data['bundle'], $data['deleted']);
614 615

  $record = array(
616
    'field_id' => $instance['field_id'],
617
    'field_name' => $instance['field_name'],
618
    'entity_type' => $instance['entity_type'],
619 620 621 622 623 624
    'bundle' => $instance['bundle'],
    'data' => $data,
    'deleted' => $instance['deleted'],
  );
  // We need to tell drupal_update_record() the primary keys to trigger an
  // update.
625 626 627
  if ($update) {
    $record['id'] = $instance['id'];
    $primary_key = array('id');
628 629
  }
  else {
630 631 632
    $primary_key = array();
  }
  drupal_write_record('field_config_instance', $record, $primary_key);
633 634 635
}

/**
636
 * Reads a single instance record from the database.
637
 *
638 639 640
 * Generally, you should use field_info_instance() instead, as it
 * provides caching and allows other modules the opportunity to
 * append additional formatters, widgets, and other information.
641
 *
642
 * @param $entity_type
643
 *   The type of entity to which the field is bound.
644 645 646 647 648 649
 * @param $field_name
 *   The field name to read.
 * @param $bundle
 *   The bundle to which the field is bound.
 * @param array $include_additional
 *   The default behavior of this function is to not return an instance that
650 651 652
 *   has been deleted, or whose field is inactive. Setting
 *   $include_additional['include_inactive'] or
 *   $include_additional['include_deleted'] to TRUE will override this
653 654 655 656
 *   behavior.
 * @return
 *   An instance structure, or FALSE.
 */
657
function field_read_instance($entity_type, $field_name, $bundle, $include_additional = array()) {
658
  $instances = field_read_instances(array('entity_type' => $entity_type, 'field_name' => $field_name, 'bundle' => $bundle), $include_additional);
659 660 661 662
  return $instances ? current($instances) : FALSE;
}

/**
663
 * Reads in field instances that match an array of conditions.
664 665 666 667
 *
 * @param $param
 *   An array of properties to use in selecting a field
 *   instance. Valid keys include any column of the
668
 *   field_config_instance table. If NULL, all instances will be returned.
669 670
 * @param $include_additional
 *   The default behavior of this function is to not return field
671 672
 *   instances that have been marked deleted, or whose field is inactive.
 *   Setting $include_additional['include_inactive'] or
673 674 675 676 677 678
 *   $include_additional['include_deleted'] to TRUE will override this
 *   behavior.
 * @return
 *   An array of instances matching the arguments.
 */
function field_read_instances($params = array(), $include_additional = array()) {
679 680 681
  $include_inactive = isset($include_additional['include_inactive']) && $include_additional['include_inactive'];
  $include_deleted = isset($include_additional['include_deleted']) && $include_additional['include_deleted'];

682
  $query = db_select('field_config_instance', 'fci', array('fetch' => PDO::FETCH_ASSOC));
683
  $query->join('field_config', 'fc', 'fc.id = fci.field_id');
684 685 686 687 688 689
  $query->fields('fci');

  // Turn the conditions into a query.
  foreach ($params as $key => $value) {
    $query->condition('fci.' . $key, $value);
  }
690
  if (!$include_inactive) {
691 692
    $query
      ->condition('fc.active', 1)
693
      ->condition('fc.storage_active', 1);
694
  }
695
  if (!$include_deleted) {
696 697 698 699 700 701 702 703
    $query->condition('fc.deleted', 0);
    $query->condition('fci.deleted', 0);
  }

  $instances = array();
  $results = $query->execute();

  foreach ($results as $record) {
704
    // Filter out instances on unknown entity types (for instance because the
705
    // module exposing them was disabled).
706
    $entity_info = entity_get_info($record['entity_type']);
707 708 709 710 711
    if ($include_inactive || $entity_info) {
      $instance = unserialize($record['data']);
      $instance['id'] = $record['id'];
      $instance['field_id'] = $record['field_id'];
      $instance['field_name'] = $record['field_name'];
712
      $instance['entity_type'] = $record['entity_type'];
713 714 715 716 717 718
      $instance['bundle'] = $record['bundle'];
      $instance['deleted'] = $record['deleted'];

      module_invoke_all('field_read_instance', $instance);
      $instances[] = $instance;
    }
719 720 721 722 723
  }
  return $instances;
}

/**
724
 * Marks a field instance and its data for deletion.
725
 *
726 727
 * @param $instance
 *   An instance structure.
728 729
 * @param $field_cleanup
 *   If TRUE, the field will be deleted as well if its last instance is being
730
 *   deleted. If FALSE, it is the caller's responsibility to handle the case of
731
 *   fields left without instances. Defaults to TRUE.
732
 */
733
function field_delete_instance($instance, $field_cleanup = TRUE) {
734 735 736
  // Mark the field instance for deletion.
  db_update('field_config_instance')
    ->fields(array('deleted' => 1))
737
    ->condition('field_name', $instance['field_name'])
738
    ->condition('entity_type', $instance['entity_type'])
739
    ->condition('bundle', $instance['bundle'])
740 741
    ->execute();

742 743 744
  // Clear the cache.
  field_cache_clear();

745
  // Mark instance data for deletion.
746
  $field = field_info_field($instance['field_name']);
747 748
  module_invoke($field['storage']['module'], 'field_storage_delete_instance', $instance);

749
  // Let modules react to the deletion of the instance.
750
  module_invoke_all('field_delete_instance', $instance);
751 752 753 754 755

  // Delete the field itself if we just deleted its last instance.
  if ($field_cleanup && count($field['bundles']) == 0) {
    field_delete_field($field['field_name']);
  }
756 757 758 759
}

/**
 * @} End of "defgroup field_crud".
760
 */
761

762
/**
763 764 765 766 767
 * @defgroup field_purge Field API bulk data deletion
 * @{
 * Clean up after Field API bulk deletion operations.
 *
 * Field API provides functions for deleting data attached to individual
768
 * entities as well as deleting entire fields or field instances in a single
769 770
 * operation.
 *
771
 * Deleting field data items for an entity with field_attach_delete() involves
772 773
 * three separate operations:
 * - Invoking the Field Type API hook_field_delete() for each field on the
774
 * entity. The hook for each field type receives the entity and the specific
775 776 777 778
 * field being deleted. A file field module might use this hook to delete
 * uploaded files from the filesystem.
 * - Invoking the Field Storage API hook_field_storage_delete() to remove
 * data from the primary field storage. The hook implementation receives the
779
 * entity being deleted and deletes data for all of the entity's bundle's
780 781
 * fields.
 * - Invoking the global Field Attach API hook_field_attach_delete() for all
782 783
 * modules that implement it. Each hook implementation receives the entity
 * being deleted and can operate on whichever subset of the entity's bundle's
784 785 786 787 788 789
 * fields it chooses to.
 *
 * These hooks are invoked immediately when field_attach_delete() is
 * called. Similar operations are performed for field_attach_delete_revision().
 *
 * When a field, bundle, or field instance is deleted, it is not practical to
790
 * invoke these hooks immediately on every affected entity in a single page
791 792 793 794 795 796 797 798
 * request; there could be thousands or millions of them. Instead, the
 * appropriate field data items, instances, and/or fields are marked as deleted
 * so that subsequent load or query operations will not return them. Later, a
 * separate process cleans up, or "purges", the marked-as-deleted data by going
 * through the three-step process described above and, finally, removing
 * deleted field and instance records.
 *
 * Purging field data is made somewhat tricky by the fact that, while
799
 * field_attach_delete() has a complete entity to pass to the various deletion
800
 * hooks, the Field API purge process only has the field data it has previously
801 802
 * stored. It cannot reconstruct complete original entities to pass to the
 * deletion hooks. It is even possible that the original entity to which some
803 804 805
 * Field API data was attached has been itself deleted before the field purge
 * operation takes place.
 *
806 807 808
 * Field API resolves this problem by using "pseudo-entities" during purge
 * operations. A pseudo-entity contains only the information from the original
 * entity that Field API knows about: entity type, id, revision id, and
809 810 811
 * bundle. It also contains the field data for whichever field instance is
 * currently being purged. For example, suppose that the node type 'story' used
 * to contain a field called 'subtitle' but the field was deleted. If node 37
812
 * was a story with a subtitle, the pseudo-entity passed to the purge hooks
813 814 815
 * would look something like this:
 *
 * @code
816
 *   $entity = stdClass Object(
817 818 819 820 821 822 823 824 825 826 827 828 829
 *     [nid] => 37,
 *     [vid] => 37,
 *     [type] => 'story',
 *     [subtitle] => array(
 *       [0] => array(
 *         'value' => 'subtitle text',
 *       ),
 *     ),
 *   );
 * @endcode
 */

/**
830
 * Purges a batch of deleted Field API data, instances, or fields.
831 832
 *
 * This function will purge deleted field data on up to a specified maximum
833
 * number of entities and then return. If a deleted field instance with no
834 835 836 837 838 839 840 841 842 843 844 845 846
 * remaining data records is found, the instance itself will be purged.
 * If a deleted field with no remaining field instances is found, the field
 * itself will be purged.
 *
 * @param $batch_size
 *   The maximum number of field data records to purge before returning.
 */
function field_purge_batch($batch_size) {
  // Retrieve all deleted field instances. We cannot use field_info_instances()
  // because that function does not return deleted instances.
  $instances = field_read_instances(array('deleted' => 1), array('include_deleted' => 1));

  foreach ($instances as $instance) {
847
    // field_purge_data() will need the field array.
848
    $field = field_info_field_by_id($instance['field_id']);
849
    // Retrieve some entities.
850
    $query = new EntityFieldQuery();
851 852 853 854 855 856
    $results = $query
      ->fieldCondition($field)
      ->entityCondition('bundle', $instance['bundle'])
      ->deleted(TRUE)
      ->range(0, $batch_size)
      ->execute();
857

858 859 860 861
    if ($results) {
      foreach ($results as $entity_type => $stub_entities) {
        field_attach_load($entity_type, $stub_entities, FIELD_LOAD_CURRENT, array('field_id' => $field['id'], 'deleted' => 1));
        foreach ($stub_entities as $stub_entity) {
862
          // Purge the data for the entity.
863
          field_purge_data($entity_type, $stub_entity, $field, $instance);
864 865 866 867 868 869 870 871 872
        }
      }
    }
    else {
      // No field data remains for the instance, so we can remove it.
      field_purge_instance($instance);
    }
  }

873
  // Retrieve all deleted fields. Any that have no instances can be purged.
874 875
  $fields = field_read_fields(array('deleted' => 1), array('include_deleted' => 1));
  foreach ($fields as $field) {
876 877
    $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1));
    if (empty($instances)) {
878 879 880 881 882 883
      field_purge_field($field);
    }
  }
}

/**
884
 * Purges the field data for a single field on a single pseudo-entity.
885 886
 *
 * This is basically the same as field_attach_delete() except it only applies
887
 * to a single field. The entity itself is not being deleted, and it is quite
888 889
 * possible that other field data will remain attached to it.
 *
890 891 892
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entity
893
 *   The pseudo-entity whose field data is being purged.
894 895 896 897 898
 * @param $field
 *   The (possibly deleted) field whose data is being purged.
 * @param $instance
 *   The deleted field instance whose data is being purged.
 */
899
function field_purge_data($entity_type, $entity, $field, $instance) {
900 901 902
  // Each field type's hook_field_delete() only expects to operate on a single
  // field at a time, so we can use it as-is for purging.
  $options = array('field_id' => $instance['field_id'], 'deleted' => TRUE);
903
  _field_invoke('delete', $entity_type, $entity, $dummy, $dummy, $options);
904 905

  // Tell the field storage system to purge the data.
906
  module_invoke($field['storage']['module'], 'field_storage_purge', $entity_type, $entity, $field, $instance);
907 908 909 910

  // Let other modules act on purging the data.
  foreach (module_implements('field_attach_purge') as $module) {
    $function = $module . '_field_attach_purge';
911
    $function($entity_type, $entity, $field, $instance);
912 913 914 915
  }
}

/**
916
 * Purges a field instance record from the database.
917 918 919 920 921 922 923 924 925 926 927 928 929
 *
 * This function assumes all data for the instance has already been purged, and
 * should only be called by field_purge_batch().
 *
 * @param $instance
 *   The instance record to purge.
 */
function field_purge_instance($instance) {
  db_delete('field_config_instance')
    ->condition('id', $instance['id'])
    ->execute();

  // Notify the storage engine.
930 931
  $field = field_info_field_by_id($instance['field_id']);
  module_invoke($field['storage']['module'], 'field_storage_purge_instance', $instance);
932 933

  // Clear the cache.
934
  field_info_cache_clear();
935 936 937 938 939 940

  // Invoke external hooks after the cache is cleared for API consistency.
  module_invoke_all('field_purge_instance', $instance);
}

/**
941
 * Purges a field record from the database.
942 943 944 945 946 947 948 949 950 951
 *
 * This function assumes all instances for the field has already been purged,
 * and should only be called by field_purge_batch().
 *
 * @param $field
 *   The field record to purge.
 */
function field_purge_field($field) {
  $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1));
  if (count($instances) > 0) {
952
    throw new FieldException(t('Attempt to purge a field @field_name that still has instances.', array('@field_name' => $field['field_name'])));
953 954 955 956 957 958 959
  }

  db_delete('field_config')
    ->condition('id', $field['id'])
    ->execute();

  // Notify the storage engine.
960
  module_invoke($field['storage']['module'], 'field_storage_purge_field', $field);
961 962

  // Clear the cache.
963
  field_info_cache_clear();
964 965 966 967 968 969 970 971

  // Invoke external hooks after the cache is cleared for API consistency.
  module_invoke_all('field_purge_field', $field);
}

/**
 * @} End of "defgroup field_purge".
 */