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
 *
 * @see field
20
21
22
 */

/**
23
 * Creates a field.
24
25
26
 *
 * This function does not bind the field to any bundle; use
 * field_create_instance() for that.
27
28
 *
 * @param $field
29
 *   A field definition array. The field_name and type properties are required.
30
31
32
33
34
35
36
37
38
 *   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
39
 *     carefully, for it might seriously affect the site's performance.
40
41
 *   - settings: each omitted setting is given the default value defined in
 *     hook_field_info().
42
 *   - storage:
43
 *     - type: the storage backend specified in the 'field_storage_default'
44
45
46
 *       system variable.
 *     - settings: each omitted setting is given the default value specified in
 *       hook_field_storage_info().
47
 *
48
 * @return
49
 *   The $field array with the id property filled in.
50
51
 *
 * @throws FieldException
52
 *
53
 * See: @link field Field API data structures @endlink.
54
55
56
57
58
59
 */
function field_create_field($field) {
  // Field name is required.
  if (empty($field['field_name'])) {
    throw new FieldException('Attempt to create an unnamed field.');
  }
60
61
62
63
  // Field type is required.
  if (empty($field['type'])) {
    throw new FieldException('Attempt to create a field with no type.');
  }
64
  // Field name cannot contain invalid characters.
65
66
  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');
67
68
  }

69
70
71
72
73
74
75
  // 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'])));
  }
76

77
78
79
  // 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));
80
  if (!empty($prior_field)) {
81
82
83
84
    $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);
85
86
  }

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

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

106
107
108
109
110
  // 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'])));
  }
111
112
113
  // 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']);
114
  $field['module'] = $field_type['module'];
115
  $field['active'] = 1;
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
  // 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;
131
  // Collect storage information.
132
  module_load_install($field['module']);
133
  $schema = (array) module_invoke($field['module'], 'field_schema', $field);
134
  $schema += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array());
135
136
  // 'columns' are hardcoded in the field type.
  $field['columns'] = $schema['columns'];
137
138
  // 'foreign keys' are hardcoded in the field type.
  $field['foreign keys'] = $schema['foreign keys'];
139
140
141
142
143
144
145
146
147
148
149
  // '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;
150
  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']);
151
152
153
  // Additionally, do not save the 'bundles' property populated by
  // field_info_field().
  unset($data['bundles']);
154

155
156
157
158
159
160
161
162
163
164
165
  $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'],
166
    'translatable' => $field['translatable'],
167
168
    'deleted' => $field['deleted'],
  );
169

170
171
172
  // Store the field and get the id back.
  drupal_write_record('field_config', $record);
  $field['id'] = $record['id'];
173

174
175
  // Invoke hook_field_storage_create_field after the field is
  // complete (e.g. it has its id).
176
  try {
177
178
179
    // Invoke hook_field_storage_create_field after
    // drupal_write_record() sets the field id.
    module_invoke($storage_type['module'], 'field_storage_create_field', $field);
180
181
182
183
184
185
186
187
188
  }
  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;
  }
189

190
191
  // Clear caches
  field_cache_clear(TRUE);
192

193
194
  // Invoke external hooks after the cache is cleared for API consistency.
  module_invoke_all('field_create_field', $field);
195

196
  return $field;
197
198
}

199
200
/**
 * Updates a field.
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
 *
 * 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.');
  }

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

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

  // Collect the new storage information, since what is in
  // $prior_field may no longer be right.
244
  module_load_install($field['module']);
245
246
247
248
249
250
251
252
253
254
255
  $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'];

256
  $has_data = field_has_data($field);
257
258
259
260
261
262
263
264
265

  // 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.
266
267
  $storage_type = field_info_storage_types($field['storage']['type']);
  module_invoke($storage_type['module'], 'field_storage_update_field', $field, $prior_field, $has_data);
268
269
270
271
272
273
274
275
276

  // 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']);
277
278
279
280
  // Additionally, do not save the 'bundles' property populated by
  // field_info_field().
  unset($data['bundles']);

281
282
283
284
285
286
287
288
  $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);
289

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

294
/**
295
296
297
 * Reads a single field record directly from the database.
 *
 * Generally, you should use the field_info_field() instead.
298
 *
299
300
301
 * This function will not return deleted fields. Use
 * field_read_fields() instead for this purpose.
 *
302
303
304
305
 * @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
306
307
 *   is inactive. Setting
 *   $include_additional['include_inactive'] to TRUE will override this
308
309
 *   behavior.
 * @return
310
 *   A field definition array, or FALSE.
311
312
313
314
315
316
317
 */
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;
}

/**
318
 * Reads in fields that match an array of conditions.
319
320
321
322
323
324
325
326
327
328
 *
 * @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
329
 *   An array of fields matching $params. If
330
 *   $include_additional['include_deleted'] is TRUE, the array is keyed
331
 *   by field id, otherwise it is keyed by field name.
332
333
334
335
336
337
338
339
340
341
 */
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']) {
342
343
344
    $query
      ->condition('fc.active', 1)
      ->condition('fc.storage_active', 1);
345
  }
346
347
  $include_deleted = (isset($include_additional['include_deleted']) && $include_additional['include_deleted']);
  if (!$include_deleted) {
348
349
350
351
352
    $query->condition('fc.deleted', 0);
  }

  $fields = array();
  $results = $query->execute();
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  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'];
367
368
369

    module_invoke_all('field_read_field', $field);

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

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

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

403
404
  // Mark field data for deletion.
  module_invoke($field['storage']['module'], 'field_storage_delete_field', $field);
405
406
407

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

412
413
  // Clear the cache.
  field_cache_clear(TRUE);
414
415

  module_invoke_all('field_delete_field', $field);
416
417
418
419
420
421
}

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

470
471
472
  // Set the field id.
  $instance['field_id'] = $field['id'];

473
474
475
  // 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.
476
477
478

  // 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 ?
479
  // TODO: Check that the display view modes are known for the entity type ?
480
481
482
  // 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.

483
484
485
  // 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.
486
  $prior_instance = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
487
  if (!empty($prior_instance)) {
488
    $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']));
489
    throw new FieldException($message);
490
491
492
493
494
495
  }

  _field_write_instance($instance);

  // Clear caches
  field_cache_clear();
496
497
498
499

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

500
  return $instance;
501
502
}

503
504
/**
 * Updates an instance of a field.
505
506
 *
 * @param $instance
507
 *   An associative array representing an instance structure. The required
508
 *   keys and values are:
509
510
511
 *   - 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.
512
513
514
 *   Read-only_id properties are assigned automatically. Any other
 *   properties specified in $instance overwrite the existing values for
 *   the instance.
515
 *
516
 * @throws FieldException
517
 *
518
519
520
521
522
523
 * @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)) {
524
    throw new FieldException(t('Attempt to update an instance of a nonexistent field @field.', array('@field' => $instance['field_name'])));
525
526
527
528
  }

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

534
535
536
  $instance['id'] = $prior_instance['id'];
  $instance['field_id'] = $prior_instance['field_id'];

537
538
539
540
  _field_write_instance($instance, TRUE);

  // Clear caches.
  field_cache_clear();
541
542

  module_invoke_all('field_update_instance', $instance, $prior_instance);
543
544
545
}

/**
546
 * Stores an instance record in the field configuration database.
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
575
576
 *
 * @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(),
  );
577
578
  // If no weight specified, make sure the field sinks at the bottom.
  if (!isset($instance['widget']['weight'])) {
579
    $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], 'form');
580
    $instance['widget']['weight'] = isset($max_weight) ? $max_weight + 1 : 0;
581
  }
582
583
  // Check widget module.
  $widget_type = field_info_widget_types($instance['widget']['type']);
584
  $instance['widget']['module'] = $widget_type['module'];
585
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,
  // and fill in defaults for each view mode specified in the definition.
589
  $instance['display'] += array(
590
    'default' => array(),
591
  );
592
  foreach ($instance['display'] as $view_mode => $display) {
593
    $display += array(
594
      'label' => 'above',
595
      'type' => isset($field_type['default_formatter']) ? $field_type['default_formatter'] : 'hidden',
596
597
      'settings' => array(),
    );
598
599
600
601
602
603
604
    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'])) {
605
      $max_weight = field_info_max_weight($instance['entity_type'], $instance['bundle'], $view_mode);
606
      $display['weight'] = isset($max_weight) ? $max_weight + 1 : 0;
607
608
    }
    $instance['display'][$view_mode] = $display;
609
610
  }

611
612
613
  // 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.
614
  $data = $instance;
615
  unset($data['id'], $data['field_id'], $data['field_name'], $data['entity_type'], $data['bundle'], $data['deleted']);
616
617

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

/**
638
 * Reads a single instance record from the database.
639
 *
640
641
642
 * 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.
643
 *
644
 * @param $entity_type
645
 *   The type of entity to which the field is bound.
646
647
648
649
650
651
 * @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
652
653
654
 *   has been deleted, or whose field is inactive. Setting
 *   $include_additional['include_inactive'] or
 *   $include_additional['include_deleted'] to TRUE will override this
655
656
657
658
 *   behavior.
 * @return
 *   An instance structure, or FALSE.
 */
659
function field_read_instance($entity_type, $field_name, $bundle, $include_additional = array()) {
660
  $instances = field_read_instances(array('entity_type' => $entity_type, 'field_name' => $field_name, 'bundle' => $bundle), $include_additional);
661
662
663
664
  return $instances ? current($instances) : FALSE;
}

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

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

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

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

  foreach ($results as $record) {
706
    // Filter out instances on unknown entity types (for instance because the
707
    // module exposing them was disabled).
708
    $entity_info = entity_get_info($record['entity_type']);
709
710
711
712
713
    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'];
714
      $instance['entity_type'] = $record['entity_type'];
715
716
717
718
719
720
      $instance['bundle'] = $record['bundle'];
      $instance['deleted'] = $record['deleted'];

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

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

744
745
746
  // Clear the cache.
  field_cache_clear();

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

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

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

/**
 * @} End of "defgroup field_crud".
762
 */
763

764
/**
765
766
767
768
769
 * @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
770
 * entities as well as deleting entire fields or field instances in a single
771
772
 * operation.
 *
773
 * Deleting field data items for an entity with field_attach_delete() involves
774
775
 * three separate operations:
 * - Invoking the Field Type API hook_field_delete() for each field on the
776
 * entity. The hook for each field type receives the entity and the specific
777
778
779
780
 * 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
781
 * entity being deleted and deletes data for all of the entity's bundle's
782
783
 * fields.
 * - Invoking the global Field Attach API hook_field_attach_delete() for all
784
785
 * modules that implement it. Each hook implementation receives the entity
 * being deleted and can operate on whichever subset of the entity's bundle's
786
787
788
789
790
791
 * 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
792
 * invoke these hooks immediately on every affected entity in a single page
793
794
795
796
797
798
799
800
 * 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
801
 * field_attach_delete() has a complete entity to pass to the various deletion
802
 * hooks, the Field API purge process only has the field data it has previously
803
804
 * stored. It cannot reconstruct complete original entities to pass to the
 * deletion hooks. It is even possible that the original entity to which some
805
806
807
 * Field API data was attached has been itself deleted before the field purge
 * operation takes place.
 *
808
809
810
 * 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
811
812
813
 * 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
814
 * was a story with a subtitle, the pseudo-entity passed to the purge hooks
815
816
817
 * would look something like this:
 *
 * @code
818
 *   $entity = stdClass Object(
819
820
821
822
823
824
825
826
827
828
 *     [nid] => 37,
 *     [vid] => 37,
 *     [type] => 'story',
 *     [subtitle] => array(
 *       [0] => array(
 *         'value' => 'subtitle text',
 *       ),
 *     ),
 *   );
 * @endcode
829
830
 *
 * @see field
831
832
833
 */

/**
834
 * Purges a batch of deleted Field API data, instances, or fields.
835
836
 *
 * This function will purge deleted field data on up to a specified maximum
837
 * number of entities and then return. If a deleted field instance with no
838
839
840
841
842
843
844
845
846
847
848
849
850
 * 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) {
851
    // field_purge_data() will need the field array.
852
    $field = field_info_field_by_id($instance['field_id']);
853
    // Retrieve some entities.
854
    $query = new EntityFieldQuery();
855
856
857
858
859
860
    $results = $query
      ->fieldCondition($field)
      ->entityCondition('bundle', $instance['bundle'])
      ->deleted(TRUE)
      ->range(0, $batch_size)
      ->execute();
861

862
863
864
865
    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) {
866
          // Purge the data for the entity.
867
          field_purge_data($entity_type, $stub_entity, $field, $instance);
868
869
870
871
872
873
874
875
876
        }
      }
    }
    else {
      // No field data remains for the instance, so we can remove it.
      field_purge_instance($instance);
    }
  }

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

/**
888
 * Purges the field data for a single field on a single pseudo-entity.
889
890
 *
 * This is basically the same as field_attach_delete() except it only applies
891
 * to a single field. The entity itself is not being deleted, and it is quite
892
893
 * possible that other field data will remain attached to it.
 *
894
895
896
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entity
897
 *   The pseudo-entity whose field data is being purged.
898
899
900
901
902
 * @param $field
 *   The (possibly deleted) field whose data is being purged.
 * @param $instance
 *   The deleted field instance whose data is being purged.
 */
903
function field_purge_data($entity_type, $entity, $field, $instance) {
904
905
906
  // 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);
907
  _field_invoke('delete', $entity_type, $entity, $dummy, $dummy, $options);
908
909

  // Tell the field storage system to purge the data.
910
  module_invoke($field['storage']['module'], 'field_storage_purge', $entity_type, $entity, $field, $instance);
911
912
913
914

  // Let other modules act on purging the data.
  foreach (module_implements('field_attach_purge') as $module) {
    $function = $module . '_field_attach_purge';
915
    $function($entity_type, $entity, $field, $instance);
916
917
918
919
  }
}

/**
920
 * Purges a field instance record from the database.
921
922
923
924
925
926
927
928
929
930
931
932
933
 *
 * 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.
934
935
  $field = field_info_field_by_id($instance['field_id']);
  module_invoke($field['storage']['module'], 'field_storage_purge_instance', $instance);
936
937

  // Clear the cache.
938
  field_info_cache_clear();
939
940
941
942
943
944

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

/**
945
 * Purges a field record from the database.
946
947
948
949
950
951
952
953
954
955
 *
 * 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) {
956
    throw new FieldException(t('Attempt to purge a field @field_name that still has instances.', array('@field_name' => $field['field_name'])));
957
958
959
960
961
962
963
  }

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

  // Notify the storage engine.
964
  module_invoke($field['storage']['module'], 'field_storage_purge_field', $field);
965
966

  // Clear the cache.
967
  field_info_cache_clear();
968
969
970
971
972
973
974
975

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

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