logo
Submitted by Mikhail Ismajlov on Tue, 10/01/2019 - 11:41

mysql

In this article we will understand how fields in Drupal work, why they are needed and how fields help to quickly develop sites in Drupal.

We have already worked with fields in previous articles:

7.5. Typing up the services block with bootstrap columns

7.6. Isotope Gallery for Drupal 8

7.7. Block with youtube video Drupal 8

Now we're gonna figure out how it works. Let's go to the editing of the Article type content fields and add a new Link type field:

/admin/structure/types/manage/article/fields

add field

When you create a new article, you will have two input URLs and text links:

link

Each time you create a new field through the admin, two tables are created in the database:

{entity_type}___field_name}
{entity_type}_revision___field_name}

Drupal 8 supports revisions, so all data will be duplicated at least once, because the only revision is the current revision of your article. Thus, the fields and the entire Drupal Fields API are needed to simplify the work with the database. We simply create fields through the admin, and drupal already creates tables in the database.

From the name of MySQL tables it should be clear that the same field can be used for one type of entity. So for example, we can now use the Link field in the content of the Basic Page type as already existing:

/admin/structure/types/manage/page/fields/add-field

add field

But if you want to create a Link field in a block, you will need to create a new field. It is not possible to use the same field in Entity of different types. Let's create a Link field for the Basic Block type:

/admin/structure/block/block-content/manage/basic/fields/add-field

As you can see when creating a field, there is no choice of the Link field from the existing fields, because Block and Node are different types of Entity.

And just like for nodes we will have two tables to store data in the Link field for blocks:

tables and views

block_content_revision__field_link и block_content__field_link.

Now let's understand how drupal stores data from the same field for different bundle nodes. We created the Link field for the Article node type, but then reused this field in the Basic Page node type. For convenience, it's best to upload the site configuration to a folder and see the files, but you can also find the configuration you need through adminer or phpmyadmin in the config table:

select config

If you search for all the configures that contain the word link:

SELECT * FROM `config` WHERE CONVERT(`name` USING utf8mb4) LIKE '%link%' LIMIT 50

We'll find the following configures for our field_link field:

field.field.block.block_content.basic.field_link
field.field.node.article.field_link
field.field.node.page.field_link
field.storage.block_content.field_link
field.storage.node.field_link

For each Entity type, each field creates its own Field Storage config. This config responds to how to store data in tables {entity_type}__{field_name}, {entity_type}_revision__{field_name}. In our case, these are block_content_field_link, block_content_revision_field_link, node__field_link, node_revision__field_link tables. Next, we will examine how the Link module stores the data. Let's open the Field Storage config for the Link field:

uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6
langcode: en
status: true
dependencies:
  module:
    - block_content
    - link
id: block_content.field_link
field_name: field_link
entity_type: block_content
type: link
settings: {  }
module: link
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

Let's take a look at each of these lines so that it is clear what exactly is stored in the Field Storage config.

uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6

This is where the Config ID is stored, unique to each Config. There is no need to create the field manually on staging if you have created the field locally and uploaded the configures. The field will be automatically created. If you delete the field and delete the configuration locally, you will also delete all data after importing it to staging. Therefore, if you have created a field on staging, upload the configures and add them to git so that you don't waste your changes.

langcode: en

In multi-lingual sites for different versions of nodes for different languages in the table of fields stored all data for all languages, indicating which language uses certain data:

select

I have the same language, so the default language in the config is the same.

status: true

Common to all configuration entities is the status field that shows whether this entity is enabled or disabled. The Field Storage config uses the created configuration entity in the drupal, see the FieldStorageConfig class, which is inherited from ConfigEntityBase:

https://api.drupal.org/api/drupal/core!modules!field!src!Entity!

dependencies:
  module:
    - block_content
    - link

Dependence on add-on modules. Since we used the Link field in blocks, we have a mandatory Block content module.

id: block_content.field_link

The unique name of our configue.

field_name: field_link

The machine name of the field we created uses Drupal, so this machine name can be used for example when accessing the node object $node->field_link->uri. How to refer to the Entity field we will understand in detail in the next articles.

Entity_type: block_content

What type of Entity is our Field Storage Configure

type: link

Drupal 8 field type, we will create our own type of field, now we just need to know that this type of field link is created by the Link module. You can see the class

core/modules/link/src/Plugin/Field/FieldType/LinkItem.php

Which are used in our confectionery.

settings: { }

Here we store the settings for the field type, now they are empty, but for example for the body field there is a setting to display the teaser or not:

config/sync/field.field.block_content.basic.body.yml

settings:
display_summary: false

module: link

A module that has a link field type. Now we have the same module name and field type link, but they can be different, for example, in one module can be implemented several types of fields, as it is done in the module DateTime:

core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php

locked: false

Shows whether the field is available for editing. This means setting up the field. Some time ago, for example, the Billing Information and Shipping Information field in the Commerce module was blocked because the existence of this field was mandatory when using delivery and tax calculation.

cardinality: 1

The number of values for one Entity that can be entered for this field. We have selected one value, but here maybe another number is 2, 3, 5, etc. For an unlimited number of values cardinality: -1 is used.

translatable: true

Is this field translatable into other languages

indexes: { }

Additional SQL indexes for better search in this field. Usually it is necessary for configuring and optimizing database queries.

persist_with_no_fields: false

Indicates whether to delete the Field Storage if the fields have been removed from all Entity. For example, if we delete the field from Article and Basic Page, the Field Storage will not be deleted.

custom_storage: false

Custom storage implies that we have a special table for storing field data, not {entity_type}__{field_name}. We won't use anything like this, but sometimes it's convenient for integration with other systems.

Now let's open the link field type file:

core/modules/link/src/Plugin/Field/FieldType/LinkItem.php

And let's see what data this field stores in the database. This can be seen in the propertyDefinitions() method:

public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
  $properties['uri'] = DataDefinition::create('uri')
    ->setLabel(t('URI'));
 
  $properties['title'] = DataDefinition::create('string')
    ->setLabel(t('Link text'));
 
  $properties['options'] = MapDataDefinition::create()
    ->setLabel(t('Options'));
 
  return $properties;
}

As you can see we store URI, Title, Options data. If you open the node__field_link table, you will see the same fields:

select

Now we have come to the topic of Fields API in Drupal 8. We create a field type through a module in a PHP file with the LinkItem class. This allows us to create a field for Entity and then we can use it to enter data and store this data in the database. This is the case with data entry. The Fields API also configures the form for data entry and output for our fields.

Let's get back to the moment when we create the fields to the Article and Basic Page content types. We have one configuration file for the Field Storage in the Node: field.storage.node.field_link.yml, but also when creating the field, we create one more configuration file for each bundle in the Entity, so for example, we now have three configuration files for the field

field.field.node.article.field_link.yml
field.field.node.page.field_link.yml
field.field.block.block_content.basic.field_link.yml

These configures store data from the field settings form:

link

In this way we can customize the form of data entry for the field in different ways for different Bundles. Every single field config in Bundle is called Field Instance in Drupal, so we first create a Field Storage field that can be used in Field Instance separately in each bandle. In the 8th Drupal, unlike in the 7th Drupal, there are no more functions for working with Field Instances, and the functionality for working with instances migrated to the CRUD API:

https://www.drupal.org/node/2054619

Examples of working with fields through the code you can see in the official documentation:

https://www.drupal.org/node/2012896

We only looked at the part of the Fields API that concerns the storage of field data in the database. In the next few lessons we will look at how the Fields API works with data entry and field data output, as well as make our own full-fledged field type.