diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php index c5fa8e8888..ae91ae181e 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php @@ -2,9 +2,91 @@ namespace Drupal\Core\Entity\Plugin\DataType; +use Drupal\Core\TypedData\Exception\MissingDataException; + /** * Enhances EntityAdapter for config entities. */ class ConfigEntityAdapter extends EntityAdapter { + /** + * @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); + } + + /** + * {@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; + } + + /** + * Get 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()); + } + } diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php index 98be20e04e..d02d2a8a66 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php @@ -2,8 +2,11 @@ namespace Drupal\Core\Entity\Plugin\DataType\Deriver; +use Drupal\Core\Config\Entity\ConfigEntityTypeInterface; 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 instanceof ConfigEntityTypeInterface ? ConfigEntityAdapter::class : EntityAdapter::class; $this->derivatives[$entity_type_id] = [ + 'class' => $class, 'label' => $entity_type->getLabel(), 'constraints' => $entity_type->getConstraints(), ] + $base_plugin_definition; @@ -95,6 +100,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; diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php index 8577f25c98..537bc63c72 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityAdapter.php @@ -2,7 +2,6 @@ namespace Drupal\Core\Entity\Plugin\DataType; -use Drupal\Core\Config\Entity\ConfigEntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\TypedData\EntityDataDefinition; @@ -79,7 +78,9 @@ 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) { - return $this->getConfigTypedData()->get($property_name); + // @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. return $this->entity->get($property_name); @@ -92,14 +93,11 @@ 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."); } - if ($this->entity instanceof ConfigEntityInterface) { - $this->entity->set($property_name, $value, $notify); - } - else { - // This will throw an exception for unknown fields. - $this->entity->set($property_name, $value, $notify); + if (!$this->entity instanceof FieldableEntityInterface) { + throw new \InvalidArgumentException("Unable to set unknown property $property_name."); } - + // This will throw an exception for unknown fields. + $this->entity->set($property_name, $value, $notify); return $this; } @@ -111,7 +109,7 @@ public function getProperties($include_computed = FALSE) { throw new MissingDataException('Unable to get properties as no entity has been provided.'); } if (!$this->entity instanceof FieldableEntityInterface) { - return $this->getConfigTypedData()->getProperties($include_computed); + return []; } return $this->entity->getFields($include_computed); } @@ -165,57 +163,7 @@ public function applyDefaultValue($notify = TRUE) { * {@inheritdoc} */ public function getIterator() { - if (isset($this->entity)) { - if ($this->entity instanceof ConfigEntityInterface) { - return $this->getConfigTypedData()->getIterator(); - } - else { - return $this->entity->getIterator(); - } - } - return new \ArrayIterator([]); - } - - /** - * Gets the typed data manager. - * - * @return \Drupal\Core\TypedData\TypedDataManagerInterface - * The typed data manager. - */ - public function getTypedDataManager() { - if (empty($this->typedDataManager)) { - if ($this->entity instanceof ConfigEntityInterface) { - $this->typedDataManager = \Drupal::service('config.typed'); - } - else { - $this->typedDataManager = \Drupal::typedDataManager(); - } - } - - return $this->typedDataManager; + return isset($this->entity) ? $this->entity->getIterator() : new \ArrayIterator([]); } - /** - * Get typed data for config entity. - * - * @return \Drupal\Core\TypedData\TraversableTypedDataInterface - * The typed data. - */ - protected function getConfigTypedData() { - /** @var \Drupal\Core\Config\TypedConfigManagerInterface $type_config_manager */ - $type_config_manager = \Drupal::service('config.typed'); - return $type_config_manager->createFromNameAndData($this->entity->getConfigDependencyName(), $this->entity->toArray()); - } - - /** - * {@inheritdoc} - */ - public function validate() { - if ($this->entity instanceof ConfigEntityInterface) { - return $this->getConfigTypedData()->validate(); - } - return parent::validate(); - } - - } diff --git a/core/tests/Drupal/KernelTests/Core/Entity/ConfigEntityAdapterTest.php b/core/tests/Drupal/KernelTests/Core/Entity/ConfigEntityAdapterTest.php index 5da54c513b..6ac0b15e7b 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/ConfigEntityAdapterTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/ConfigEntityAdapterTest.php @@ -1,10 +1,14 @@ installConfig(static::$modules); - $this->entity = entity_create('config_test', [ + // 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, ]); } + public function testEntityDeriver() { + $definition = \Drupal::typedDataManager()->getDefinition('entity:config_test'); + $this->assertEquals(ConfigEntityAdapter::class, $definition['class']); + } + public function testValidate() { - $adapter = EntityAdapter::createFromEntity($this->entity); + $adapter = ConfigEntityAdapter::createFromEntity($this->entity); $violations = $adapter->validate(); $this->assertEmpty($violations); - $this->entity = entity_create('config_test', [ + $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", + 'weight' => 'very heavy', ]); - $adapter = EntityAdapter::createFromEntity($this->entity); + $adapter = ConfigEntityAdapter::createFromEntity($this->entity); $violations = $adapter->validate(); $this->assertCount(1, $violations); $violation = $violations->get(0); @@ -61,36 +70,36 @@ public function testValidate() { public function testGetProperties() { $expected_properties = [ - 'uuid' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'langcode' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'status' => 'Drupal\Core\TypedData\Plugin\DataType\BooleanData', - 'dependencies' => 'Drupal\Core\Config\Schema\Mapping', - 'id' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'label' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'weight' => 'Drupal\Core\TypedData\Plugin\DataType\IntegerData', - 'style' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'size' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'size_value' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', - 'protected_property' => 'Drupal\Core\TypedData\Plugin\DataType\StringData', + '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 = EntityAdapter::createFromEntity($this->entity)->getProperties(); + $properties = ConfigEntityAdapter::createFromEntity($this->entity)->getProperties(); $keys = []; foreach ($properties as $key => $property) { $keys[] = $key; - $this->assertEquals($expected_properties[$key], get_class($property)); + $this->assertInstanceOf($expected_properties[$key], $property); } $this->assertSame(array_keys($expected_properties), $keys); } public function testGetProperty() { - $adapter = EntityAdapter::createFromEntity($this->entity); + $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()); } public function testSetProperty() { - $adapter = EntityAdapter::createFromEntity($this->entity); + $adapter = ConfigEntityAdapter::createFromEntity($this->entity); $adapter->set('weight', 2); $this->assertEquals(2, $this->entity->weight); }