Commit 0daa2b52 authored by Gábor Hojtsy's avatar Gábor Hojtsy

Issue #1818574 by tim.plunkett, alexpott, tedbow, dawehner, EclipseGc, fago,...

Issue #1818574 by tim.plunkett, alexpott, tedbow, dawehner, EclipseGc, fago, Wim Leers, andypost, Berdir, xjm, yched, catch, jibran, effulgentsia: Support config entities in typed data EntityAdapter
parent 81a13c64
<?php
namespace Drupal\Core\Entity\Plugin\DataType;
use Drupal\Core\TypedData\Exception\MissingDataException;
/**
* Enhances EntityAdapter for config entities.
*/
class ConfigEntityAdapter extends EntityAdapter {
/**
* The wrapped entity object.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
public function get($property_name) {
if (!isset($this->entity)) {
throw new MissingDataException("Unable to get property $property_name as no entity has been provided.");
}
return $this->getConfigTypedData()->get($property_name);
}
/**
* {@inheritdoc}
*/
public function set($property_name, $value, $notify = TRUE) {
if (!isset($this->entity)) {
throw new MissingDataException("Unable to set property $property_name as no entity has been provided.");
}
$this->entity->set($property_name, $value, $notify);
return $this;
}
/**
* {@inheritdoc}
*/
public function getProperties($include_computed = FALSE) {
if (!isset($this->entity)) {
throw new MissingDataException('Unable to get properties as no entity has been provided.');
}
return $this->getConfigTypedData()->getProperties($include_computed);
}
/**
* {@inheritdoc}
*/
public function onChange($property_name) {
if (isset($this->entity)) {
// Let the entity know of any changes.
$this->getConfigTypedData()->onChange($property_name);
}
}
/**
* {@inheritdoc}
*/
public function getIterator() {
if (isset($this->entity)) {
return $this->getConfigTypedData()->getIterator();
}
return new \ArrayIterator([]);
}
/**
* Gets the typed data manager.
*
* @return \Drupal\Core\Config\TypedConfigManagerInterface
* The typed data manager.
*/
public function getTypedDataManager() {
if (empty($this->typedDataManager)) {
$this->typedDataManager = \Drupal::service('config.typed');
}
return $this->typedDataManager;
}
/**
* {@inheritdoc}
*/
public function applyDefaultValue($notify = TRUE) {
// @todo Figure out what to do for this method, see
// https://www.drupal.org/project/drupal/issues/2945635.
throw new \BadMethodCallException('Method not supported');
}
/**
* Gets typed data for config entity.
*
* @return \Drupal\Core\TypedData\ComplexDataInterface
* The typed data.
*/
protected function getConfigTypedData() {
return $this->getTypedDataManager()->createFromNameAndData($this->entity->getConfigDependencyName(), $this->entity->toArray());
}
}
......@@ -2,8 +2,11 @@
namespace Drupal\Core\Entity\Plugin\DataType\Deriver;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\Plugin\DataType\ConfigEntityAdapter;
use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -86,7 +89,9 @@ public function getDerivativeDefinitions($base_plugin_definition) {
$this->derivatives[''] = $base_plugin_definition;
// Add definitions for each entity type and bundle.
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
$class = $entity_type->entityClassImplements(ConfigEntityInterface::class) ? ConfigEntityAdapter::class : EntityAdapter::class;
$this->derivatives[$entity_type_id] = [
'class' => $class,
'label' => $entity_type->getLabel(),
'constraints' => $entity_type->getConstraints(),
'internal' => $entity_type->isInternal(),
......@@ -96,6 +101,7 @@ public function getDerivativeDefinitions($base_plugin_definition) {
foreach ($this->bundleInfoService->getBundleInfo($entity_type_id) as $bundle => $bundle_info) {
if ($bundle !== $entity_type_id) {
$this->derivatives[$entity_type_id . ':' . $bundle] = [
'class' => $class,
'label' => $bundle_info['label'],
'constraints' => $this->derivatives[$entity_type_id]['constraints'],
] + $base_plugin_definition;
......
......@@ -78,8 +78,6 @@ public function get($property_name) {
throw new MissingDataException("Unable to get property $property_name as no entity has been provided.");
}
if (!$this->entity instanceof FieldableEntityInterface) {
// @todo: Add support for config entities in
// https://www.drupal.org/node/1818574.
throw new \InvalidArgumentException("Unable to get unknown property $property_name.");
}
// This will throw an exception for unknown fields.
......@@ -94,8 +92,6 @@ public function set($property_name, $value, $notify = TRUE) {
throw new MissingDataException("Unable to set property $property_name as no entity has been provided.");
}
if (!$this->entity instanceof FieldableEntityInterface) {
// @todo: Add support for config entities in
// https://www.drupal.org/node/1818574.
throw new \InvalidArgumentException("Unable to set unknown property $property_name.");
}
// This will throw an exception for unknown fields.
......@@ -111,8 +107,6 @@ public function getProperties($include_computed = FALSE) {
throw new MissingDataException('Unable to get properties as no entity has been provided.');
}
if (!$this->entity instanceof FieldableEntityInterface) {
// @todo: Add support for config entities in
// https://www.drupal.org/node/1818574.
return [];
}
return $this->entity->getFields($include_computed);
......
<?php
namespace Drupal\KernelTests\Core\Entity;
use Drupal\Core\Config\Schema\Mapping;
use Drupal\Core\Entity\Plugin\DataType\ConfigEntityAdapter;
use Drupal\Core\TypedData\Plugin\DataType\BooleanData;
use Drupal\Core\TypedData\Plugin\DataType\IntegerData;
use Drupal\Core\TypedData\Plugin\DataType\StringData;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests entity adapter for configuration entities.
*
* @see \Drupal\Core\Entity\Plugin\DataType\ConfigEntityAdapter
*
* @group Entity
*
* @coversDefaultClass \Drupal\Core\Entity\Plugin\DataType\ConfigEntityAdapter
*/
class ConfigEntityAdapterTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['config_test'];
/**
* The config entity.
*
* @var \Drupal\config_test\Entity\ConfigTest
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(static::$modules);
// ConfigTest::create doesn't work with the following exception:
// "Multiple entity types found for Drupal\config_test\Entity\ConfigTest."
$this->entity = \Drupal::entityTypeManager()->getStorage('config_test')->create([
'id' => 'system',
'label' => 'foobar',
'weight' => 1,
]);
}
/**
* @covers \Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver::getDerivativeDefinitions
*/
public function testEntityDeriver() {
$definition = \Drupal::typedDataManager()->getDefinition('entity:config_test');
$this->assertEquals(ConfigEntityAdapter::class, $definition['class']);
}
/**
* @covers ::validate
*/
public function testValidate() {
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
$violations = $adapter->validate();
$this->assertEmpty($violations);
$this->entity = \Drupal::entityTypeManager()->getStorage('config_test')->create([
'id' => 'system',
'label' => 'foobar',
// Set weight to be a string which should not validate.
'weight' => 'very heavy',
]);
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
$violations = $adapter->validate();
$this->assertCount(1, $violations);
$violation = $violations->get(0);
$this->assertEquals('This value should be of the correct primitive type.', $violation->getMessage());
$this->assertEquals('weight', $violation->getPropertyPath());
}
/**
* @covers ::getProperties
*/
public function testGetProperties() {
$expected_properties = [
'uuid' => StringData::class,
'langcode' => StringData::class,
'status' => BooleanData::class,
'dependencies' => Mapping::class,
'id' => StringData::class,
'label' => StringData::class,
'weight' => IntegerData::class,
'style' => StringData::class,
'size' => StringData::class,
'size_value' => StringData::class,
'protected_property' => StringData::class,
];
$properties = ConfigEntityAdapter::createFromEntity($this->entity)->getProperties();
$keys = [];
foreach ($properties as $key => $property) {
$keys[] = $key;
$this->assertInstanceOf($expected_properties[$key], $property);
}
$this->assertSame(array_keys($expected_properties), $keys);
}
/**
* @covers ::getValue
*/
public function testGetValue() {
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
$this->assertEquals($this->entity->weight, $adapter->get('weight')->getValue());
$this->assertEquals($this->entity->id(), $adapter->get('id')->getValue());
$this->assertEquals($this->entity->label, $adapter->get('label')->getValue());
}
/**
* @covers ::set
*/
public function testSet() {
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
// Get the value via typed data to ensure that the typed representation is
// updated correctly when the value is set.
$this->assertEquals(1, $adapter->get('weight')->getValue());
$return = $adapter->set('weight', 2);
$this->assertSame($adapter, $return);
$this->assertEquals(2, $this->entity->weight);
// Ensure the typed data is updated via the set too.
$this->assertEquals(2, $adapter->get('weight')->getValue());
}
/**
* @covers ::getString
*/
public function testGetString() {
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
$this->assertEquals('foobar', $adapter->getString());
}
/**
* @covers ::applyDefaultValue
*/
public function testApplyDefaultValue() {
$this->setExpectedException(\BadMethodCallException::class, 'Method not supported');
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
$adapter->applyDefaultValue();
}
/**
* @covers ::getIterator
*/
public function testGetIterator() {
$adapter = ConfigEntityAdapter::createFromEntity($this->entity);
$iterator = $adapter->getIterator();
$fields = iterator_to_array($iterator);
$expected_fields = [
'uuid',
'langcode',
'status',
'dependencies',
'id',
'label',
'weight',
'style',
'size',
'size_value',
'protected_property',
];
$this->assertEquals($expected_fields, array_keys($fields));
$this->assertEquals($this->entity->id(), $fields['id']->getValue());
$adapter->setValue(NULL);
$this->assertEquals(new \ArrayIterator([]), $adapter->getIterator());
}
}
......@@ -2,6 +2,7 @@
namespace Drupal\KernelTests\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\TypedData\EntityDataDefinition;
......@@ -149,6 +150,7 @@ public function testEntityDefinitionIsInternal($internal, $expected) {
$entity_type_id = $this->randomMachineName();
$entity_type = $this->prophesize(EntityTypeInterface::class);
$entity_type->entityClassImplements(ConfigEntityInterface::class)->willReturn(FALSE);
$entity_type->getLabel()->willReturn($this->randomString());
$entity_type->getConstraints()->willReturn([]);
$entity_type->isInternal()->willReturn($internal);
......
......@@ -35,13 +35,6 @@ class EntityAdapterUnitTest extends UnitTestCase {
*/
protected $entity;
/**
* The config entity used for testing.
*
* @var \Drupal\Core\Entity\ConfigtEntityBase|\PHPUnit_Framework_MockObject_MockObject
*/
protected $configEntity;
/**
* The content entity adapter under test.
*
......@@ -49,13 +42,6 @@ class EntityAdapterUnitTest extends UnitTestCase {
*/
protected $entityAdapter;
/**
* The config entity adapter under test.
*
* @var \Drupal\Core\Entity\Plugin\DataType\EntityAdapter
*/
protected $configEntityAdapter;
/**
* The entity type used for testing.
*
......@@ -242,10 +228,6 @@ protected function setUp() {
$this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\ContentEntityBase', [$values, $this->entityTypeId, $this->bundle]);
$this->entityAdapter = EntityAdapter::createFromEntity($this->entity);
$this->configEntity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [$values, $this->entityTypeId, $this->bundle]);
$this->configEntityAdapter = EntityAdapter::createFromEntity($this->configEntity);
}
/**
......@@ -455,11 +437,6 @@ public function testGetIterator() {
$this->entityAdapter->setValue(NULL);
$this->assertEquals(new \ArrayIterator([]), $this->entityAdapter->getIterator());
// Config entity test.
$iterator = $this->configEntityAdapter->getIterator();
$this->configEntityAdapter->setValue(NULL);
$this->assertEquals(new \ArrayIterator([]), $this->entityAdapter->getIterator());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment