I defined a new Field Type named country
following this nice tutorial: http://capgemini.github.io/drupal/writing-custom-fields-in-drupal-8/
These are main files from the country
custom Field Type:
modules/custom/country/src/Plugin/Field/FieldType/CountryItem.php
/**
* Plugin implementation of the 'country' field type.
*
* @FieldType(
* id = "country",
* label = @Translation("Country"),
* description = @Translation("Stores the ISO-2 name of a country."),
* category = @Translation("Custom"),
* default_widget = "country_default",
* default_formatter = "country_default"
* )
*/
class CountryItem extends FieldItemBase {
const COUNTRY_ISO2_MAXLENGTH = 2;
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['value'] = DataDefinition::create('string')
->setLabel(t('Country'));
return $properties;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return array(
'columns' => array(
'value' => array(
'type' => 'char',
'length' => static::COUNTRY_ISO2_MAXLENGTH,
'not null' => FALSE,
),
),
'indexes' => array(
'value' => array('value'),
),
);
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value = $this->get('value')->getValue();
return $value === NULL || $value === '';
}
/**
* {@inheritdoc}
*/
public function getConstraints() {
$constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
$constraints = parent::getConstraints();
$constraints[] = $constraint_manager->create('ComplexData', array(
'value' => array(
'Length' => array(
'max' => static::COUNTRY_ISO2_MAXLENGTH,
'maxMessage' => t('%name: the country iso-2 code may not be longer than @max characters.', array('%name' => $this->getFieldDefinition()->getLabel(), '@max' => static::COUNTRY_ISO2_MAXLENGTH)),
)
),
));
return $constraints;
}
}
modules/custom/country/src/Plugin/Field/FieldFormatter/CountryDefaultFormatter.php
/**
* Plugin implementation of the 'country' formatter.
*
* @FieldFormatter(
* id = "country_default",
* module = "country",
* label = @Translation("Country"),
* field_types = {
* "country"
* }
* )
*/
class CountryDefaultFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
$elements = array();
$countries = \Drupal::service('country_manager')->getList();
foreach ($items as $delta => $item) {
if (isset($countries[$item->value])) {
$elements[$delta] = array('#markup' => $countries[$item->value]);
}
}
return $elements;
}
}
modules/custom/country/src/Plugin/Field/FieldWidget/CountryDefaultWidget.php
/**
* Plugin implementation of the 'country_default' widget.
*
* @FieldWidget(
* id = "country_default",
* label = @Translation("Country select"),
* field_types = {
* "country"
* }
* )
*/
class CountryDefaultWidget extends WidgetBase {
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$countries = \Drupal::service('country_manager')->getList();
$element['value'] = $element + array(
'#type' => 'select',
'#options' => $countries,
'#empty_value' => '',
'#default_value' => (isset($items[$delta]->value) && isset($countries[$items[$delta]->value])) ? $items[$delta]->value : NULL,
'#description' => t('Select a country'),
);
return $element;
}
}
All works fine: I'm able to create new fields of type country
and set values on them.
The only problem is when I add a new field of type country
in some Content Type, when I click the "Save and continue" button (after set a value for the field's label) I get a 500 http error page inside the browser and this error in the PHP log:
PHP Fatal error: Declaration of Drupal\country\Plugin\Field\FieldFormatter\CountryDefaultFormatter::viewElements() must be compatible with Drupal\Core\Field\FormatterInterface::viewElements(Drupal\Core\Field\FieldItemListInterface $items, $langcode) in /path/to/drupal/website/modules/custom/country/src/Plugin/Field/FieldFormatter/CountryDefaultFormatter.php on line 0
What is wrong?