| Drupal | PHP Cross Reference | Content Management Systems |
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
Body
title
Description
Body
title
Description
Body
title
Body
title