Commit 9d5d866f authored by catch's avatar catch

Issue #2083803 by andypost, Berdir: Convert field type to typed data plugin...

Issue #2083803 by andypost, Berdir: Convert field type to typed data plugin for field_test() module.
parent ccd257a9
......@@ -50,9 +50,9 @@ function testFieldAttachSaveLoad() {
$this->createFieldWithInstance('', $entity_type);
$cardinality = $this->field->getFieldCardinality();
// Configure the instance so that we test hook_field_load() (see
// field_test_field_load() in field_test.module).
$this->instance->settings['test_hook_field_load'] = TRUE;
// Configure the instance so that we test
// \Drupal\field_test\Plugin\field\field_type\TestItem::getCacheData().
$this->instance->settings['test_cached_data'] = TRUE;
$this->instance->save();
// TODO : test empty values filtering and "compression" (store consecutive deltas).
......@@ -79,7 +79,9 @@ function testFieldAttachSaveLoad() {
for ($delta = 0; $delta < $cardinality; $delta++) {
// The field value loaded matches the one inserted or updated.
$this->assertEqual($entity->{$this->field_name}[$delta]->value , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
// The value added in hook_field_load() is found.
// The value added in
// \Drupal\field_test\Plugin\field\field_type\TestItem::getCacheData() is
// found.
$this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
}
......@@ -131,10 +133,10 @@ function testFieldAttachLoadMultiple() {
'field_name' => $field_names[$i],
'entity_type' => $entity_type,
'bundle' => $bundles[$bundle],
// Configure the instance so that we test
// \Drupal\field_test\Plugin\field\field_type\TestItem::getCacheData().
'settings' => array(
// Configure the instance so that we test hook_field_load()
// (see field_test_field_load() in field_test.module).
'test_hook_field_load' => TRUE,
'test_cached_data' => TRUE,
),
))->save();
}
......
......@@ -23,7 +23,7 @@ public static function getInfo() {
function testFieldInfo() {
// Test that field_test module's fields, widgets, and formatters show up.
$field_test_info = field_test_field_info();
$field_test_info = $this->getExpectedFieldTypeDefinition();
$info = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions();
foreach ($field_test_info as $t_key => $field_type) {
foreach ($field_type as $key => $val) {
......@@ -283,7 +283,7 @@ function testFieldMap() {
* Test that the field_info settings convenience functions work.
*/
function testSettingsInfo() {
$info = field_test_field_info();
$info = $this->getExpectedFieldTypeDefinition();
foreach ($info as $type => $data) {
$field_type_manager = \Drupal::service('plugin.manager.entity.field.field_type');
$this->assertIdentical($field_type_manager->getDefaultSettings($type), $data['settings'], format_string("field settings service returns %type's field settings", array('%type' => $type)));
......@@ -327,4 +327,50 @@ function testWidgetDefinition() {
$this->assertTrue(in_array('test_field', $widget_definition['field_types']), "The 'test_field_widget_multiple' widget is enabled for the 'test_field' field type in field_test_field_widget_info_alter().");
}
/**
* Returns field info definition.
*/
protected function getExpectedFieldTypeDefinition() {
return array(
'test_field' => array(
'label' => t('Test field'),
'description' => t('Dummy field type used for tests.'),
'settings' => array(
'test_field_setting' => 'dummy test string',
'changeable' => 'a changeable field setting',
'unchangeable' => 'an unchangeable field setting',
),
'instance_settings' => array(
'test_instance_setting' => 'dummy test string',
'test_cached_data' => FALSE,
),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
'class' => 'Drupal\field_test\Plugin\field\field_type\TestItem',
),
'shape' => array(
'label' => t('Shape'),
'description' => t('Another dummy field type.'),
'settings' => array(
'foreign_key_name' => 'shape',
),
'instance_settings' => array(),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
'class' => 'Drupal\field_test\Plugin\field\field_type\ShapeItem',
),
'hidden_test_field' => array(
'no_ui' => TRUE,
'label' => t('Hidden from UI test field'),
'description' => t('Dummy hidden field type used for tests.'),
'settings' => array(),
'instance_settings' => array(),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
'class' => 'Drupal\field_test\Plugin\field\field_type\HiddenTestItem',
),
);
}
}
......@@ -11,51 +11,6 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\field\FieldException;
/**
* Implements hook_field_info().
*/
function field_test_field_info() {
return array(
'test_field' => array(
'label' => t('Test field'),
'description' => t('Dummy field type used for tests.'),
'settings' => array(
'test_field_setting' => 'dummy test string',
'changeable' => 'a changeable field setting',
'unchangeable' => 'an unchangeable field setting',
),
'instance_settings' => array(
'test_instance_setting' => 'dummy test string',
'test_hook_field_load' => FALSE,
),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
'class' => 'Drupal\field_test\Type\TestItem',
),
'shape' => array(
'label' => t('Shape'),
'description' => t('Another dummy field type.'),
'settings' => array(
'foreign_key_name' => 'shape',
),
'instance_settings' => array(),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
'class' => 'Drupal\field_test\Type\ShapeItem',
),
'hidden_test_field' => array(
'no_ui' => TRUE,
'label' => t('Hidden from UI test field'),
'description' => t('Dummy hidden field type used for tests.'),
'settings' => array(),
'instance_settings' => array(),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
'class' => 'Drupal\field_test\Type\HiddenTestItem',
),
);
}
/**
* Implements hook_field_widget_info_alter().
*/
......@@ -72,128 +27,6 @@ function field_test_field_update_forbid($field, $prior_field) {
}
}
/**
* Implements hook_field_load().
*/
function field_test_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
foreach ($items as $id => $item) {
// To keep the test non-intrusive, only act for instances with the
// test_hook_field_load setting explicitly set to TRUE.
$test_hook_field_load = $instances[$id]->getFieldSetting('test_hook_field_load');
if (!empty($test_hook_field_load)) {
foreach ($item as $delta => $value) {
// Don't add anything on empty values.
if ($value) {
$items[$id][$delta]['additional_key'] = 'additional_value';
}
}
}
}
}
/**
* Implements hook_field_insert().
*/
function field_test_field_insert(EntityInterface $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_field_update().
*/
function field_test_field_update(EntityInterface $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_field_delete().
*/
function field_test_field_delete(EntityInterface $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_field_validate().
*
* Possible error codes:
* - 'field_test_invalid': The value is invalid.
*/
function field_test_field_validate(EntityInterface $entity = NULL, $field, $instance, $langcode, $items, &$errors) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
foreach ($items as $delta => $item) {
if ($item['value'] == -1) {
$errors[$field->getFieldName()][$langcode][$delta][] = array(
'error' => 'field_test_invalid',
'message' => t('%name does not accept the value -1.', array('%name' => $instance->getFieldLabel())),
);
}
}
}
/**
* Implements hook_field_is_empty().
*/
function field_test_field_is_empty($item, $field_type) {
if ($field_type == 'test_field') {
return empty($item['value']);
}
return empty($item['shape']) && empty($item['color']);
}
/**
* Implements hook_field_settings_form().
*/
function field_test_field_settings_form($field, $instance) {
$settings = $field->getFieldSettings();
$form['test_field_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field setting'),
'#default_value' => $settings['test_field_setting'],
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field setting.'),
);
return $form;
}
/**
* Implements hook_field_instance_settings_form().
*/
function field_test_field_instance_settings_form($field, $instance) {
$settings = $instance->getFieldSettings();
$form['test_instance_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field instance setting'),
'#default_value' => $settings['test_instance_setting'],
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field instance setting.'),
);
return $form;
}
/**
* Form element validation handler for 'test_field_widget_multiple' widget.
*/
function field_test_widget_multiple_validate($element, &$form_state) {
$values = array_map('trim', explode(',', $element['#value']));
$items = array();
foreach ($values as $value) {
$items[] = array('value' => $value);
}
form_set_value($element, $items, $form_state);
}
/**
* Sample 'default value' callback.
*/
......
......@@ -12,52 +12,3 @@ function field_test_install() {
// hook_entity_info_alter() needs to be executed as last.
module_set_weight('field_test', 1);
}
/**
* Implements hook_field_schema().
*/
function field_test_field_schema($field) {
if ($field->getFieldType() == 'test_field') {
return array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'medium',
'not null' => FALSE,
),
),
'indexes' => array(
'value' => array('value'),
),
);
}
else {
$foreign_keys = array();
// The 'foreign keys' key is not always used in tests.
$foreign_key_name = $field->getFieldSetting('foreign_key_name');
if (!empty($foreign_key_name)) {
$foreign_keys['foreign keys'] = array(
// This is a dummy foreign key definition, references a table that
// doesn't exist, but that's not a problem.
$foreign_key_name => array(
'table' => $foreign_key_name,
'columns' => array($foreign_key_name => 'id'),
),
);
}
return array(
'columns' => array(
'shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
'color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
),
) + $foreign_keys;
}
}
<?php
/**
* @file
* Contains \Drupal\field_test\Plugin\Validation\Constraint\TestFieldConstraint.
*/
namespace Drupal\field_test\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraints\NotEqualTo;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
/**
* Checks if a value is not equal.
*
* @Plugin(
* id = "TestField",
* label = @Translation("Test Field", context = "Validation"),
* type = { "integer" }
* )
*/
class TestFieldConstraint extends NotEqualTo {
/**
* {@inheritdoc}
*/
public function getRequiredOptions() {
return array('value');
}
/**
* {@inheritdoc}
*/
public function validatedBy() {
return '\Symfony\Component\Validator\Constraints\NotEqualToValidator';
}
}
......@@ -2,13 +2,25 @@
/**
* @file
* Contains \Drupal\field_test\Type\HiddenTestItem.
* Contains \Drupal\field_test\Plugin\field\field_type\HiddenTestItem.
*/
namespace Drupal\field_test\Type;
namespace Drupal\field_test\Plugin\field\field_type;
use Drupal\Core\Entity\Annotation\FieldType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the 'test_field' entity field item.
* Defines the 'hidden_test' entity field item.
*
* @FieldType(
* id = "hidden_test_field",
* label = @Translation("Hidden from UI test field"),
* description = @Translation("Dummy hidden field type used for tests."),
* no_ui = TRUE,
* default_widget = "test_field_widget",
* default_formatter = "field_test_default"
* )
*/
class HiddenTestItem extends TestItem {
......
<?php
/**
* @file
* Contains \Drupal\field_test\Plugin\field\field_type\ShapeItem.
*/
namespace Drupal\field_test\Plugin\field\field_type;
use Drupal\Core\Entity\Annotation\FieldType;
use Drupal\Core\Annotation\Translation;
use Drupal\field\FieldInterface;
use Drupal\field\Plugin\Type\FieldType\ConfigFieldItemBase;
/**
* Defines the 'shape_field' entity field item.
*
* @FieldType(
* id = "shape",
* label = @Translation("Shape"),
* description = @Translation("Another dummy field type."),
* settings = {
* "foreign_key_name" = "shape"
* },
* default_widget = "test_field_widget",
* default_formatter = "field_test_default"
* )
*/
class ShapeItem extends ConfigFieldItemBase {
/**
* Property definitions of the contained properties.
*
* @see ShapeItem::getPropertyDefinitions()
*
* @var array
*/
static $propertyDefinitions;
/**
* {@inheritdoc}
*/
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['shape'] = array(
'type' => 'string',
'label' => t('Shape'),
);
static::$propertyDefinitions['color'] = array(
'type' => 'string',
'label' => t('Color'),
);
}
return static::$propertyDefinitions;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldInterface $field) {
$foreign_keys = array();
// The 'foreign keys' key is not always used in tests.
if ($field->getFieldSetting('foreign_key_name')) {
$foreign_keys['foreign keys'] = array(
// This is a dummy foreign key definition, references a table that
// doesn't exist, but that's not a problem.
$field->getFieldSetting('foreign_key_name') => array(
'table' => $field->getFieldSetting('foreign_key_name'),
'columns' => array($field->getFieldSetting('foreign_key_name') => 'id'),
),
);
}
return array(
'columns' => array(
'shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
'color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
),
) + $foreign_keys;
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$item = $this->getValue();
return empty($item['shape']) && empty($item['color']);
}
}
<?php
/**
* @file
* Contains \Drupal\field_test\Plugin\field\field_type\TestItem.
*/
namespace Drupal\field_test\Plugin\field\field_type;
use Drupal\Core\Entity\Annotation\FieldType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\Field\PrepareCacheInterface;
use Drupal\field\FieldInterface;
use Drupal\field\Plugin\Type\FieldType\ConfigFieldItemBase;
/**
* Defines the 'test_field' entity field item.
*
* @FieldType(
* id = "test_field",
* label = @Translation("Test field"),
* description = @Translation("Dummy field type used for tests."),
* settings = {
* "test_field_setting" = "dummy test string",
* "changeable" = "a changeable field setting",
* "unchangeable" = "an unchangeable field setting"
* },
* instance_settings = {
* "test_instance_setting" = "dummy test string",
* "test_cached_data" = FALSE
* },
* default_widget = "test_field_widget",
* default_formatter = "field_test_default"
* )
*/
class TestItem extends ConfigFieldItemBase implements PrepareCacheInterface {
/**
* Property definitions of the contained properties.
*
* @see TestItem::getPropertyDefinitions()
*
* @var array
*/
static $propertyDefinitions;
/**
* {@inheritdoc}
*/
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['value'] = array(
'type' => 'integer',
'label' => t('Test integer value'),
);
}
return static::$propertyDefinitions;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldInterface $field) {
return array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'medium',
'not null' => FALSE,
),
),
'indexes' => array(
'value' => array('value'),
),
);
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, array &$form_state, $has_data) {
$form['test_field_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field setting'),
'#default_value' => $this->getFieldSetting('test_field_setting'),
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field setting.'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function instanceSettingsForm(array $form, array &$form_state) {
$form['test_instance_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field instance setting'),
'#default_value' => $this->getFieldSetting('test_instance_setting'),
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field instance setting.'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function getCacheData() {
// To keep the test non-intrusive, only act for instances with the
// 'test_cached_data' setting explicitly set to TRUE. Also don't add
// anything on empty values.
if ($this->getFieldSetting('test_cached_data') && !$this->isEmpty()) {
// Set the additional value so that getValue() will return it.
$this->additional_key = 'additional_value';
}
return $this->getValue();
}
/**
* {@inheritdoc}
*/
public function delete() {
// Reports that delete() method is executed for testing purposes.
field_test_memorize('field_test_field_delete', array($this->getEntity()));
}
/**
* {@inheritdoc}
*/
public function getConstraints() {
$constraint_manager = \Drupal::typedData()->getValidationConstraintManager();
$constraints = parent::getConstraints();
$constraints[] = $constraint_manager->create('ComplexData', array(
'value' => array(
'TestField' => array(
'value' => -1,
'message' => t('%name does not accept the value @value.', array('%name' => $this->getFieldDefinition()->getFieldLabel(), '@value' => -1)),
)
),
));
return $constraints;
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
return empty($this->value);
}
}
......@@ -66,7 +66,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
$element += array(
'#type' => 'textfield',
'#default_value' => implode(', ', $values),
'#element_validate' => array('field_test_widget_multiple_validate'),
'#element_validate' => array(array(get_class($this), 'multipleValidate')),
);
return $element;
}
......@@ -78,4 +78,16 @@ public function errorElement(array $element, ConstraintViolationInterface $error
return $element;
}
/**
* Element validation helper.
*/
public static function multipleValidate($element, &$form_state) {
$values = array_map('trim', explode(',', $element['#value']));
$items = array();