Drupal 7 Field API

Walt Haas's picture

Updated: 

14/03/2016 - 11:52

What Is A Field?

A Drupal "field" is a way to attach additional data to any Drupal entity declared fieldable. An entity is marked as fieldable by returning 'fieldable' => TRUE in the array returned by its hook_enitity_info(). Drupal core entities which are fieldable are: node, user, taxonomy and comment. The default is 'fieldable' => FALSE. Fields can be attached to entities using the Field API.

Terminology Confusion

The use of the word "field" has become confused over the last several Drupal releases. For example, in the definition of hook_schema() we find the following example: function hook_schema() { $schema['node'] = array( // Example (partial) specification for table "node". 'description' => 'The base table for nodes.', 'fields' => array( 'nid' => array( 'description' => 'The primary identifier for a node.', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), ... The fields[] array in the example refers to what are properly called "columns" in the RDBMS world. In the definition of hook_field_schema() we find that columns are, correctly, called columns.

This confusion extends to the Examples for Developers module, where the Field Example provides an example of a field type. You can of course use the example field type to create one or more fields, either in code or through the Field UI.

In this section we will attempt to be clear about three distinct things:

  • column in a table in the database
  • field type as defined in PHP code
  • field created from a field type by either code or the Field UI

When a field is defined to Drupal, the definition is given as the following components:

Field Type
Describes the way the field value data is stored in the Drupal database. This is one or more columns of primitives such as 'string', 'integer', 'boolean' or 'float'
Field Name
Consists of a translatable name for human readers and a machine name for the database.
Widget
Input HTML to allow a human to enter a field value.
Formatter
Output HTML to display a field value
Storage Type
How to store the field data in the Drupal database. This is normally a SQL database such as MariaDB or MySQL. The default storage type is defined as the value of system variable field_storage_default or field_sql_storage if that variable is undefined.

Defining A Field Type

A field type is a particular way of storing field information in the Drupal database. The easiest way to learn how a field type is defined is by examining the Drupal core modules. In modules/field/modules/text.install locate function text_field_schema(). This is an implementation of hook_field_schema() that defines how the data values of field types of the text module are stored in the database. This is only a portion of the database schema for the table in the Drupal database that stores the value. The actual table has, as we will see, seven additional columns used to manage the data.

text_field_schema() defines three field types:

  • text
  • text_long
  • text_with_summary
The schema for the text_with_summary field type is worth a second look. It defines two columns for data, named value and summary. In general, the schema of a field is very flexible in what it can store.

If we examine the Drupal database with a tool such as phpMyAdmin we will not actually see a field type until it has been used to create a field. Until that happens, a field type exists only in PHP code. In fact, a field type can only be defined in PHP code; there is no way to do this through the browser.

The Field Example in the Examples for Developers module is a nice example of creating a field type with several widgets and formatters.

Defining A Field With The Field UI

The easiest way to define a field is with the optional core Field UI module. To use it, go to the Administration > Modules page, check the box for Field UI and click Save configuration. Then go to the Administration > Configuration > People > Account settings page. Under the title Account settings you will see three tabs. The middle tab, Manage fields, shows a form in which you can add fields to the User entity. The selector in the column labeled Field type lets you select any of the field types defined in the enabled modules. The selections offered by this selector are information from hook_field_info() from all the enabled modules. If you examine text_field_info() in modules/field/module/text.module you will see that the text in the selector is from the label element and the keys to the array returned from this hook are text, text_long and text_with_summary. Comparing these keys with the case statement in text_field_info() we find the same strings, so the value returned from the selector selects a schema from text_field_schema().

As a practical example, we'll add a field 'Real name' to the user account settings. Type 'Real name' into the box labeled Add new field in the Label column. Notice that the Machine name column has been filled in with 'field_real_name'. Select Text on the Field type selector. Click the Save button . On the next screen click Save field settings. On the following screen click Save settings.

Now we use phpMyAdmin to examine the Drupal database. We see that table field_config has a new row, with field_real_name in the field_name column, text in the type column, and text in the module column. This shows that the field type is text and that this field type is defined in the text module. In the data column is an entry [BLOB - 795 B]. This contains a serialized PHP structure. Click on [BLOB]. phpMyAdmin will open a modal window allowing you to save the contents of the BLOB to file field_config-data.bin. Do this, then examine the file. You will see a description of how the field is to be stored in the Drupal database. The necessary information is collected and the row is added to the table in field_create_field(). As a by-product, the information gathered about field types is cached in table cache_field in one or more rows with cid beginning field_info_types: in a BLOB in the data column.

Checking the field_config_instance table, we see a new row with a number in the field_id column that matches the the number in the id column of the new row in field_config. The name in the field_name column matches the name in the same column of the field_config table. The entity_type column shows that we attached the field to the user entity. The bundle column shows that this instance of the field is in the user bundle. This table also has a data BLOB that you can save and examine. You will see a description of how the field is to be input and displayed. The information for this row is gathered and the row written in field_create_instance().

In the Drupal database we now see two new tables named field_data_field_real_name and field_revision_field_real_name. They are empty because no field data has been stored in them. When we look at the structure of these tables (click the Structure tab in the phpMyAdmin window) we see that they have the same structure. The design is for the ...data... table to contain the current value of the field, while the ...revision... table contains the revision history of the field. The entity, bundle, deleted, entity_id, revision_id, language and delta columns are added to manage the actual field value. In the normal case of SQL storage, these tables are created in _field_sql_storage_schema().

Defining A Field In Code

It is possible to create a field in code by direct calls to field_create_field() and field_create_instance() after the field type used has been defined. For an example of this, see _comment_body_field_create() in the core comment module. This example uses field types defined in the core text module, which is always enabled.

Saving Field Data

Each fieldable entity implements its own save routine: node_save(), user_save() etc. This calls field_attach_insert() if the entity is new or field_attach_update() if an existing entity is updated. After the field data has been written to the database, hook_field_attach_insert() resp. hook_field_attach_update() is called.

Loading Field Data

An entity is loaded by a call to the entity controller's DrupalEntityController::load() method. This method always calls DrupalEntityController::attachLoad() which checks whether the entity is fieldable. If so, field_attach_load() or field_attach_load_revision() is called to load any fields that are attached to the entity.

Disabling A Module That Provides A Field

When the Administration > Modules form is constructed, _system_rebuild_module_data is called, which calls hook_system_info_alter() for each enabled module, passing an object with information about that module. When field_system_info_alter() is called, it calls field_read_fields() to test whether the module provides a field type that is in currently in use. If the module provides a field type currently in use, the module is marked "required" so that the form will not allow the module to be disabled. It is necessary to delete all fields of this type before the module can be disabled.

Deleting A Field

FIXME

Contributed Modules

The contriburted modules listed below act on fields in some general way. NOTE: The author has not tried most of these and makes NO GUARANTEES they will work. There are also a large number of contributed modules providing specialized field types of every description. You can search Drupal projects for a field type you need.

Data Structure Constraints

Each row in the field_config_instance table MUST reference one existing row in the field_config table. The fci field_id column references the id column of exactly one row that exists in the fc table. If

For each row in the field_config table, there MUST be one or more rows in the fci table with field_id column corresponding to id column of this row in the fc table.

If a table field_data_foo or field_revison_foo exists but there is no field_config row for foo, the table is an orphan.

Persistent Cache

The persistent cache for the field module is stored in the Drupal database in table cache_field. The table contents are rewritten when a module is enabled or disabled. The created column holds the timestamp when each row was written.

Drupal 7 tags: