Creating a custom field type

Fields are powered through the plugin system in Drupal. Field types are defined using the plugin system. Each field type has its own class. A new field type can be defined through a custom class that will provide schema and property information.

In this example, we will create a simple field type called "real name" to store the first and last names.

Note

Field types just define ways in which data can be stored and handled through the Field API. Field widgets provide means for editing a field type in the user interface. Field formatters provide means for displaying the field data to users. Both are plugins and will be covered in later recipes.

Getting ready

Create a new module like the one existing in the first recipe. We will refer to the module as mymodule throughout the recipe. Use your module's appropriate name.

How to do it…

  1. We need to create the src/Plugin/Field/FieldType directory in the module's base location. The Field module discovers field types in the PluginFieldFieldType namespace.
  2. Create a RealName.php file in the newly created directory so that we can define the RealName class. This will provide our real name field for the first and last names:
    How to do it…
  3. The RealName class will extend the DrupalCoreFieldFieldItemBase class:
    <?php
    /**
     * @file
     * Contains DrupalmymodulePluginFieldFieldTypeRealName.
     */
    
    namespace DrupalmymodulePluginFieldFieldType;
    
    use DrupalCoreFieldFieldItemBase;
    use DrupalCoreFieldFieldStorageDefinitionInterface;
    use DrupalCoreTypedDataDataDefinition;
    
    
    class RealName extends FieldItemBase {
        
    }

    The DrupalCoreFieldFieldItemBase satisfies methods defined by inherited interfaces except for schema and propertyDefinitions.

  4. Field types are annotated plugins. Annotated plugins use documentation blocks to provide details of the plugin. We will provide the field type's identifier, label, description, category, and default widget and formatter:
    <?php
    
    /**
     * @file
     * Contains DrupalmymodulePluginFieldFieldTypeRealName.
     */
    
    namespace DrupalmymodulePluginFieldFieldType;
    
    use DrupalCoreFieldFieldItemBase;
    use DrupalCoreFieldFieldStorageDefinitionInterface;
    use DrupalCoreTypedDataDataDefinition;
    
    /**
     * Plugin implementation of the 'realname' field type.
     *
     * @FieldType(
     *   id = "realname",
     *   label = @Translation("Real name"),
     *   description = @Translation("This field stores a first and last name."),
     *   category = @Translation("General"),
     *   default_widget = "string_textfield",
     *   default_formatter = "string"
     * )
     */
    class RealName extends FieldItemBase {
    
    }

    The @FieldType tells Drupal that this is a FieldType plugin. The following properties are defined:

    • Id: This is the plugin's machine name
    • Label: This is the human-readable name for the field
    • description: This is the human-readable description of the field
    • category: This is the category where the field shows up in the user interface
    • default_widget: This is the default form widget to be used for editing
    • default_formatter: This is the default formatter with which you can display the field
  5. The RealName class needs to implement the schema method defined in the DrupalCoreFieldFieldItemInterface. This returns an array of the database API schema information:
      /**
       * {@inheritdoc}
       */
      public static function schema(DrupalCoreFieldFieldStorageDefinitionInterface $field_definition) {
        return array(
          'columns' => array(
            'first_name' => array(
              'description' => 'First name.',
              'type' => 'varchar',
              'length' => '255',
              'not null' => TRUE,
              'default' => '',
            ),
            'last_name' => array(
              'description' => 'Last name.',
              'type' => 'varchar',
              'length' => '255',
              'not null' => TRUE,
              'default' => '',
            ),
          ),
          'indexes' => array(
            'first_name' => array('first_name'),
            'last_name' => array('last_name'),
          ),
        );
      }

    The schema method defines the columns in the field's data table. We will define a column to hold the first_name and last_name values.

  6. We also need to implement the propertySchema method to satisfy DrupalCoreTypedDataComplexDataDefinitionInterface. This returns a typed definition of the values defined in the schema method:
      /**
       * {@inheritdoc}
       */
      public static function propertyDefinitions(DrupalCoreFieldFieldStorageDefinitionInterface $field_definition) {
        $properties['first_name'] = DrupalCoreTypedDataDataDefinition::create('string')
          ->setLabel(t('First name'));
        $properties['last_name'] = DrupalCoreTypedDataDataDefinition::create('string')
          ->setLabel(t('Last name'));
    
        return $properties;
      }

    This method returns an array that is keyed with the same column names provided in schema. It returns a typed data definition to handle the field type's values.

  7. Rebuild Drupal's cache so that the plugin system can discover the new field type.
  8. The field will now appear on the field type management screen:
    How to do it…

How it works…

Drupal core defines a plugin.manager.field.field_type service. By default, this is handled through the DrupalCoreFieldFieldTypePluginManager class. This plugin manager defines the field type plugins that should be in the Plugin/Field/FieldType namespace, and all the classes in this namespace will be loaded and assumed to be field type plugins.

The manager's definition also sets DrupalCoreFieldFieldItemInterface as the expected interface that all the field type plugins will implement. This is why most field types extend DrupalCoreFieldFieldItemBase to meet these method requirements.

As field types are annotated plugins, the manager provides DrupalCoreFieldAnnotationFieldType as the class that fulfills the annotation definition.

When the user interface defines the available fields, the plugin.manager.field.field_type service is invoked to retrieve a list of available field types.

There's more…

Altering field types

The DrupalCoreFieldFieldTypePluginManager class defines the alter method as field_info. Modules that implement hook_field_info_alter in their .module files have the ability to modify field type definitions discovered by the manager:

/**
 * Implements hook_field_info_alter().
 */
function mymodule_field_info_alter(&$info) {
  $info['email']['label'] = t('E-mail address');
}

The preceding alter method will change the human-readable label for the Email field to the e-mail address.

Defining whether a field is empty

The DrupalCoreTypedDateComplexDataInterface interface provides an isEmpty method. This method is used to check whether the field's value is empty, for example, when verifying that the required field has data. The DrupalCoreTypedDataPluginDataTypeMap class implements the method. By default, the method ensures that the values are not empty.

Field types can provide their own implementations to provide a more robust verification. For instance, the field can validate that the first name can be entered but not the last name, or the field can require both the first and the last name.

See also

  • The Creating blocks using plugins recipe of this chapter
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset