Issue #2227227 by mpdonadio, amateescu, yched, larowlan, swentel, tstoeckler, fago: FieldTypePluginManager cannot instantiate FieldType plugins, good thing TypedDataManager can instantiate just about anything
parent
e40099fd39
commit
b0f4b418ca
|
@ -382,7 +382,7 @@ services:
|
|||
parent: default_plugin_manager
|
||||
plugin.manager.field.field_type:
|
||||
class: Drupal\Core\Field\FieldTypePluginManager
|
||||
arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
|
||||
arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@typed_data_manager']
|
||||
plugin.manager.field.widget:
|
||||
class: Drupal\Core\Field\WidgetPluginManager
|
||||
arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@plugin.manager.field.field_type']
|
||||
|
|
|
@ -184,15 +184,6 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the typed data manager.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataManager
|
||||
*/
|
||||
protected function typedDataManager() {
|
||||
return \Drupal::typedDataManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -378,8 +369,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
if (isset($this->values[$name][$langcode])) {
|
||||
$value = $this->values[$name][$langcode];
|
||||
}
|
||||
$entity_adapter = $this->getTypedData();
|
||||
$field = \Drupal::typedDataManager()->getPropertyInstance($entity_adapter, $name, $value);
|
||||
$field = \Drupal::service('plugin.manager.field.field_type')->createFieldItemList($this, $name, $value);
|
||||
if ($default) {
|
||||
// $this->defaultLangcode might not be set if we are initializing the
|
||||
// default language code cache, in which case there is no valid
|
||||
|
@ -894,7 +884,8 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
// Avoid deep-cloning when we are initializing a translation object, since
|
||||
// it will represent the same entity, only with a different active language.
|
||||
if (!$this->translationInitialize) {
|
||||
// The translation is a different object, and needs its own TypedData object.
|
||||
// The translation is a different object, and needs its own TypedData
|
||||
// adapter object.
|
||||
$this->typedData = NULL;
|
||||
$definitions = $this->getFieldDefinitions();
|
||||
foreach ($this->fields as $name => $values) {
|
||||
|
|
|
@ -515,7 +515,7 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
|
|||
// without modifying the entity being worked on.
|
||||
if (is_subclass_of($this->getFieldItemClass(), '\Drupal\Core\TypedData\OptionsProviderInterface')) {
|
||||
$items = $entity->get($this->getName());
|
||||
return \Drupal::typedDataManager()->getPropertyInstance($items, 0);
|
||||
return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
|
||||
}
|
||||
// @todo: Allow setting custom options provider, see
|
||||
// https://www.drupal.org/node/2002138.
|
||||
|
|
|
@ -78,7 +78,7 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldDefinition() {
|
||||
return $this->getParent()->getFieldDefinition();
|
||||
return $this->definition->getFieldDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,6 +40,13 @@ class FieldItemList extends ItemList implements FieldItemListInterface {
|
|||
*/
|
||||
protected $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createItem($offset = 0, $value = NULL) {
|
||||
return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($this, $offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -9,8 +9,10 @@ namespace Drupal\Core\Field;
|
|||
|
||||
use Drupal\Component\Plugin\Factory\DefaultFactory;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\Core\TypedData\TypedDataManager;
|
||||
|
||||
/**
|
||||
* Plugin manager for 'field type' plugins.
|
||||
|
@ -19,6 +21,13 @@ use Drupal\Core\Plugin\DefaultPluginManager;
|
|||
*/
|
||||
class FieldTypePluginManager extends DefaultPluginManager implements FieldTypePluginManagerInterface {
|
||||
|
||||
/**
|
||||
* The typed data manager.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataManager
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
/**
|
||||
* Constructs the FieldTypePluginManager object
|
||||
*
|
||||
|
@ -29,11 +38,50 @@ class FieldTypePluginManager extends DefaultPluginManager implements FieldTypePl
|
|||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
|
||||
* The typed data manager.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, TypedDataManager $typed_data_manager) {
|
||||
parent::__construct('Plugin/Field/FieldType', $namespaces, $module_handler, 'Drupal\Core\Field\FieldItemInterface', 'Drupal\Core\Field\Annotation\FieldType');
|
||||
$this->alterInfo('field_info');
|
||||
$this->setCacheBackend($cache_backend, 'field_types_plugins');
|
||||
$this->typedDataManager = $typed_data_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Creates a field item, which is not part of an entity or field item list.
|
||||
*
|
||||
* @param string $field_type
|
||||
* The field type, for which a field item should be created.
|
||||
* @param array $configuration
|
||||
* The plugin configuration array, i.e. an array with the following keys:
|
||||
* - field_definition: The field definition object, i.e. an instance of
|
||||
* Drupal\Core\Field\FieldDefinitionInterface.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldItemInterface
|
||||
* The instantiated object.
|
||||
*/
|
||||
public function createInstance($field_type, array $configuration = array()) {
|
||||
$configuration['data_definition'] = $configuration['field_definition']->getItemDefinition();
|
||||
return $this->typedDataManager->createInstance("field_item:$field_type", $configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createFieldItemList(FieldableEntityInterface $entity, $field_name, $values = NULL) {
|
||||
// Leverage prototyping of the Typed Data API for fast instantiation.
|
||||
return $this->typedDataManager->getPropertyInstance($entity->getTypedData(), $field_name, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createFieldItem(FieldItemListInterface $items, $index, $values = NULL) {
|
||||
// Leverage prototyping of the Typed Data API for fast instantiation.
|
||||
return $this->typedDataManager->getPropertyInstance($items, $index, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Core\Field;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
|
||||
/**
|
||||
* Defines an interface for the field type plugin manager.
|
||||
|
@ -16,6 +17,45 @@ use Drupal\Component\Plugin\PluginManagerInterface;
|
|||
*/
|
||||
interface FieldTypePluginManagerInterface extends PluginManagerInterface {
|
||||
|
||||
/**
|
||||
* Creates a new field item list.
|
||||
*
|
||||
* The provided entity is assigned as the parent of the created item list.
|
||||
* However, it is the responsibility of the caller (usually the parent entity
|
||||
* itself) to make the parent aware of the field as a new child.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
||||
* The entity this field item list will be part of.
|
||||
* @param string $field_name
|
||||
* The name of the field.
|
||||
* @param mixed $values
|
||||
* (optional) The data value. If set, it has to match one of the supported
|
||||
* data type format as documented for the data type classes.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldItemListInterface
|
||||
* The instantiated object.
|
||||
*/
|
||||
public function createFieldItemList(FieldableEntityInterface $entity, $field_name, $values = NULL);
|
||||
|
||||
/**
|
||||
* Creates a new field item as part of a field item list.
|
||||
*
|
||||
* The provided item list is assigned as the parent of the created item. It
|
||||
* However, it is the responsibility of the caller (usually the parent list
|
||||
* itself) to have the parent aware of the item as a new child.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldItemListInterface $items
|
||||
* The field item list, for which to create a new item.
|
||||
* @param int $index
|
||||
* The list index at which the item is created.
|
||||
* @param array|null $values
|
||||
* (optional) The values to assign to the field item properties.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldItemInterface
|
||||
* The instantiated object.
|
||||
*/
|
||||
public function createFieldItem(FieldItemListInterface $items, $index, $values = NULL);
|
||||
|
||||
/**
|
||||
* Returns the default field-level settings for a field type.
|
||||
*
|
||||
|
|
|
@ -78,4 +78,14 @@ class FieldItemDataDefinition extends DataDefinition implements ComplexDataDefin
|
|||
return $this->fieldDefinition->getFieldStorageDefinition()->getMainPropertyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field item's field definition.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldDefinitionInterface
|
||||
* The field definition for this field item.
|
||||
*/
|
||||
public function getFieldDefinition() {
|
||||
return $this->fieldDefinition;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -630,7 +630,7 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
|
|||
// without modifying the entity being worked on.
|
||||
if (is_subclass_of($this->getFieldItemClass(), '\Drupal\Core\TypedData\OptionsProviderInterface')) {
|
||||
$items = $entity->get($this->getName());
|
||||
return \Drupal::typedDataManager()->getPropertyInstance($items, 0);
|
||||
return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
|
||||
}
|
||||
// @todo: Allow setting custom options provider, see
|
||||
// https://www.drupal.org/node/2002138.
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
namespace Drupal\field\Tests;
|
||||
|
||||
use Drupal\Component\Utility\String;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
|
||||
/**
|
||||
* Tests the field type manager.
|
||||
*
|
||||
|
@ -26,4 +30,63 @@ class FieldTypePluginManagerTest extends FieldUnitTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creation of field item instances.
|
||||
*/
|
||||
public function testCreateInstance() {
|
||||
/** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
foreach (array('test_field', 'shape', 'hidden_test_field') as $type) {
|
||||
$definition = $field_type_manager->getDefinition($type);
|
||||
|
||||
$class = $definition['class'];
|
||||
$field_name = 'field_' . $type;
|
||||
|
||||
$field_definition = BaseFieldDefinition::create($type);
|
||||
|
||||
$configuration = array(
|
||||
'field_definition' => $field_definition,
|
||||
'name' => $field_name,
|
||||
'parent' => NULL,
|
||||
);
|
||||
|
||||
$instance = $field_type_manager->createInstance($type, $configuration);
|
||||
|
||||
$this->assertTrue($instance instanceof $class, String::format('Created a @class instance', array('@class' => $class)));
|
||||
$this->assertEqual($field_name, $instance->getName(), String::format('Instance name is @name', array('@name' => $field_name)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creation of field item instances.
|
||||
*/
|
||||
public function testCreateInstanceWithConfig() {
|
||||
/** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
$type = 'test_field';
|
||||
$definition = $field_type_manager->getDefinition($type);
|
||||
|
||||
$class = $definition['class'];
|
||||
$field_name = 'field_' . $type;
|
||||
|
||||
$field_definition = BaseFieldDefinition::create($type)
|
||||
->setLabel('Jenny')
|
||||
->setDefaultValue(8675309);
|
||||
|
||||
$configuration = array(
|
||||
'field_definition' => $field_definition,
|
||||
'name' => $field_name,
|
||||
'parent' => NULL,
|
||||
);
|
||||
|
||||
$entity = EntityTest::create();
|
||||
|
||||
$instance = $field_type_manager->createInstance($type, $configuration);
|
||||
|
||||
$this->assertTrue($instance instanceof $class, String::format('Created a @class instance', array('@class' => $class)));
|
||||
$this->assertEqual($field_name, $instance->getName(), String::format('Instance name is @name', array('@name' => $field_name)));
|
||||
$this->assertEqual($instance->getFieldDefinition()->getLabel(), 'Jenny', 'Instance label is Jenny');
|
||||
$this->assertEqual($instance->getFieldDefinition()->getDefaultValue($entity), [['value' => 8675309]], 'Instance default_value is 8675309');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -229,9 +229,9 @@ class ContentEntityBaseUnitTest extends UnitTestCase {
|
|||
->disableOriginalConstructor()
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$this->typedDataManager->expects($this->any())
|
||||
->method('getPropertyInstance')
|
||||
->with($this->entity->getTypedData(), 'revision_id', NULL)
|
||||
$this->fieldTypePluginManager->expects($this->any())
|
||||
->method('createFieldItemList')
|
||||
->with($this->entity, 'revision_id', NULL)
|
||||
->will($this->returnValue($field_item_list));
|
||||
|
||||
$this->fieldDefinitions['revision_id']->getItemDefinition()->setClass(get_class($field_item));
|
||||
|
|
|
@ -164,11 +164,6 @@ class EntityAdapterUnitTest extends UnitTestCase {
|
|||
->method('getValidationConstraintManager')
|
||||
->willReturn($validation_constraint_manager);
|
||||
|
||||
$this->fieldItemList = $this->getMock('\Drupal\Core\Field\FieldItemListInterface');
|
||||
$this->typedDataManager->expects($this->any())
|
||||
->method('getPropertyInstance')
|
||||
->willReturn($this->fieldItemList);
|
||||
|
||||
$not_specified = new Language(array('id' => LanguageInterface::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE));
|
||||
$this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
|
||||
$this->languageManager->expects($this->any())
|
||||
|
@ -190,6 +185,11 @@ class EntityAdapterUnitTest extends UnitTestCase {
|
|||
->method('getDefaultFieldSettings')
|
||||
->will($this->returnValue(array()));
|
||||
|
||||
$this->fieldItemList = $this->getMock('\Drupal\Core\Field\FieldItemListInterface');
|
||||
$this->fieldTypePluginManager->expects($this->any())
|
||||
->method('createFieldItemList')
|
||||
->willReturn($this->fieldItemList);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('entity.manager', $this->entityManager);
|
||||
$container->set('uuid', $this->uuid);
|
||||
|
|
|
@ -40,10 +40,14 @@ abstract class BaseFieldDefinitionTestBase extends UnitTestCase {
|
|||
->method('moduleExists')
|
||||
->with($module_name)
|
||||
->will($this->returnValue(TRUE));
|
||||
$typed_data_manager = $this->getMockBuilder('\Drupal\Core\TypedData\TypedDataManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$plugin_manager = new FieldTypePluginManager(
|
||||
$namespaces,
|
||||
$this->getMock('Drupal\Core\Cache\CacheBackendInterface'),
|
||||
$module_handler
|
||||
$module_handler,
|
||||
$typed_data_manager
|
||||
);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
|
|
Loading…
Reference in New Issue