Drupal 8: Creating a custom field - Part 1: Field type
Jo Fitzgerald
I have been experimenting with the Alpha release of Drupal 8 and so I'm sharing some of my experiences so that you can avoid the pitfalls I have encountered.
First I would like to give credit to the two articles I used during the exercise:
- Upgrading Code Snippets Module to Drupal 8: Creating a Custom Field
- D7 to D8 upgrade: fields, widgets and formatters
Hopefully this article will provide a third point-of-view to make your task easier.
a) Create the file
In D8 the location of files is very important. The field type must be located as follows:
/lib/Drupal//Plugin/field/field_type/.php
N.B. The field type name should be in CamelCase.
b) Add Contains
, namespace
and use
In the newly created field type file add a brief comment to explain what it consists of:
```php
/**
- @file
- Contains \Drupal<module_name>\Plugin\field\field_type<field_type_name>.
*/
N.B. The "Contains..." line should match the location and name of this file.
Then add the <code>namespace</code> as follows:
```php
namespace Drupal\<module_name>\Plugin\field\field_type;
N.B. It is vital that the namespace matches the location of the file otherwise it will not work.
Then add the following use
s:
use Drupal\field\Plugin\Type\FieldType\ConfigFieldItemBase;
This provides the class that the field item will extend.
use Drupal\field\FieldInterface;
This provides a variable type required within the field item class.
c) Add field details annotation
Annotations are an important part of Drupal 8 and must not be treated as simple comments! :o) The annotation should appear as follows:
/**
* Plugin implementation of the '<field_type_name>' field type.
*
* @FieldType(
* id = "<field_type_id>",
* label = @Translation("<field_type_label>"),
* description = @Translation("<field_type_description>"),
* default_widget = "<field_type_default_widget>",
* default_formatter = "<field_type_default_formatter>"
* )
*/
N.B. All text represented by a <placeholder> should be appropriately replaced according to requirements. The default_widget
and default_formatter
must match the ids of a widget and a formatter (see Part 2 and Part 3 of this article).
d) Add field item class
Create the field item class as follows:
class <field_type_name> extends ConfigFieldItemBase {
}
N.B. The <field_type_name> must match the name of this file (case-sensitive).
The class should contain the following:
i. schema()
The schema() function defines the sub-field(s) that make up the field item. Here is an example:
/**
* {@inheritdoc}
*/
public static function schema(FieldInterface $field) {
return array(
'columns' => array(
'forename' => array(
'type' => 'varchar',
'length' => 256,
'not null' => TRUE,
),
'surname' => array(
'type' => 'varchar',
'length' => 256,
'not null' => TRUE,
),
'age' => array(
'type' => 'int',
'not null' => TRUE,
),
),
);
}
ii. isEmpty()
The isEmpty() function defines what constitutes an empty field item, e.g.
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value = $this->get('forename')->getValue();
return $value === NULL || $value === '';
}
iii. getPropertyDefinitions()
The getPropertyDefinitions() function defines the data types of the fields, e.g.
/**
* {@inheritdoc}
*/
static $propertyDefinitions;
/**
* {@inheritdoc}
*/
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['forename'] = array(
'type' => 'string',
'label' => t('Forename'),
);
static::$propertyDefinitions['surname'] = array(
'type' => 'string',
'label' => t('Surname'),
);
static::$propertyDefinitions['age'] = array(
'type' => 'integer',
'label' => t('Age'),
);
}
return static::$propertyDefinitions;
}
Here is a simple example, similar to that described above.
Click Part 2: Field widget to continue creating a custom field.