diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php index 093c77dd16..cf9a98c2be 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php @@ -16,6 +16,13 @@ class ConfigEntityAdapter extends EntityAdapter { */ protected $entity; + /** + * The typed config manager. + * + * @var \Drupal\Core\Config\TypedConfigManagerInterface + */ + protected $typedConfigManager; + /** * {@inheritdoc} */ @@ -73,12 +80,12 @@ public function getIterator() { * @return \Drupal\Core\Config\TypedConfigManagerInterface * The typed data manager. */ - public function getTypedDataManager() { - if (empty($this->typedDataManager)) { - $this->typedDataManager = \Drupal::service('config.typed'); + public function getTypedConfigManager() { + if (empty($this->typedConfigManager)) { + $this->typedConfigManager = \Drupal::service('config.typed'); } - return $this->typedDataManager; + return $this->typedConfigManager; } /** @@ -97,7 +104,7 @@ public function applyDefaultValue($notify = TRUE) { * The typed data. */ protected function getConfigTypedData() { - return $this->getTypedDataManager()->createFromNameAndData($this->entity->getConfigDependencyName(), $this->entity->toArray()); + return $this->getTypedConfigManager()->createFromNameAndData($this->entity->getConfigDependencyName(), $this->entity->toArray()); } } diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php index 9d8c81f588..2744f1158f 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php @@ -312,6 +312,29 @@ public function getDataDefinition() { return $definition; } + /** + * Checks if this definition's data type matches that of another context. + * + * @param \Drupal\Core\Plugin\Context\ContextInterface $context + * The context to test against. + * + * @return bool + * TRUE if the data types match, otherwise FALSE. + */ + protected function dataTypeMatches(ContextInterface $context) { + $this_type = $this->getDataType(); + $that_type = $context->getContextDefinition()->getDataType(); + + return ( + $this_type === 'any' || + $this_type === $that_type || + // Allow a more generic data type like 'entity' to be fulfilled by a more + // specific data type like 'entity:user'. However, if this type is more + // specific, do not consider a more generic type to be a match. + strpos($that_type, "$this_type:") === 0 + ); + } + /** * {@inheritdoc} */ @@ -319,7 +342,7 @@ public function isSatisfiedBy(ContextInterface $context) { $definition = $context->getContextDefinition(); // If the data types do not match, this context is invalid unless the // expected data type is any, which means all data types are supported. - if ($this->getDataType() != 'any' && $definition->getDataType() != $this->getDataType()) { + if (!$this->dataTypeMatches($context)) { return FALSE; } diff --git a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php index a5d453ae58..43646661df 100644 --- a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php +++ b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php @@ -129,7 +129,7 @@ protected function validateNode(TypedDataInterface $data, $constraints = NULL, $ // Pass the canonical representation of the data as validated value to // constraint validators, such that they do not have to care about Typed // Data. - $value = $this->typedDataManager->getCanonicalRepresentation($data); + $value = $data->getTypedDataManager()->getCanonicalRepresentation($data); $this->context->setNode($value, $data, $metadata, $property_path); if (isset($constraints) || !$this->context->isGroupValidated($cache_key, Constraint::DEFAULT_GROUP)) { diff --git a/core/modules/layout_builder/src/LayoutEntityHelperTrait.php b/core/modules/layout_builder/src/LayoutEntityHelperTrait.php index 907b8018f3..4c2862cff6 100644 --- a/core/modules/layout_builder/src/LayoutEntityHelperTrait.php +++ b/core/modules/layout_builder/src/LayoutEntityHelperTrait.php @@ -6,6 +6,8 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Plugin\Context\Context; use Drupal\Core\Plugin\Context\ContextDefinition; +use Drupal\Core\Plugin\Context\EntityContext; +use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface; /** * Methods to help with entities using the layout builder. @@ -65,9 +67,7 @@ private function getSectionStorageFromEntity(EntityInterface $entity, $view_mode return \Drupal::service('plugin.manager.layout_builder.section_storage') ->loadFromContext([ 'view_mode' => new Context(ContextDefinition::create('string'), $view_mode), - // @todo Use EntityContext::fromEntity() after - // https://www.drupal.org/project/drupal/issues/3008431 is fixed. - 'entity' => new Context(ContextDefinition::create('entity'), $entity), + 'entity' => EntityContext::fromEntity($entity), ]); } diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php index c93e77de9f..661ee2ee04 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php @@ -29,6 +29,7 @@ protected function setUp() { $namespaces = new \ArrayObject([ 'Drupal\\Core\\TypedData' => $this->root . '/core/lib/Drupal/Core/TypedData', 'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation', + 'Drupal\\Tests\\Core\\Plugin\\Fixtures' => $this->root . '/core/tests/Drupal/Tests/Core/Plugin/Fixtures', ]); $cache_backend = new NullBackend('cache'); $module_handler = $this->prophesize(ModuleHandlerInterface::class); @@ -60,6 +61,7 @@ protected function setUp() { * (optional) The value to set on the context, defaults to NULL. * * @covers ::isSatisfiedBy + * @covers ::dataTypeMatches * @covers ::getSampleValues * @covers ::getConstraintObjects * @@ -116,6 +118,16 @@ public function providerTestIsSatisfiedBy() { new InheritedContextDefinition('any'), new ContextDefinition('any'), ]; + $data['specific definition, generic requirement'] = [ + TRUE, + new ContextDefinition('test_data_type'), + new ContextDefinition('test_data_type:a_variant'), + ]; + $data['generic definition, specific requirement'] = [ + FALSE, + new ContextDefinition('test_data_type:a_variant'), + new ContextDefinition('test_data_type'), + ]; return $data; } diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php index 69adfdd271..8e9b259a4f 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php @@ -13,6 +13,7 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Plugin\Context\EntityContext; use Drupal\Core\Plugin\Context\EntityContextDefinition; use Drupal\Core\TypedData\TypedDataManager; @@ -95,19 +96,20 @@ protected function setUp() { * @param mixed $value * (optional) The value to set on the context, defaults to NULL. */ - protected function assertRequirementIsSatisfied($expected, EntityContextDefinition $requirement, EntityContextDefinition $definition, $value = NULL) { + protected function assertRequirementIsSatisfied($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) { $context = new EntityContext($definition, $value); $this->assertSame($expected, $requirement->isSatisfiedBy($context)); } /** * @covers ::isSatisfiedBy + * @covers ::dataTypeMatches * @covers ::getSampleValues * @covers ::getConstraintObjects * * @dataProvider providerTestIsSatisfiedBy */ - public function testIsSatisfiedBy($expected, EntityContextDefinition $requirement, EntityContextDefinition $definition, $value = NULL) { + public function testIsSatisfiedBy($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) { $entity_storage = $this->prophesize(EntityStorageInterface::class); $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class); $this->entityTypeManager->getStorage('test_config')->willReturn($entity_storage->reveal()); @@ -169,12 +171,23 @@ public function providerTestIsSatisfiedBy() { EntityContextDefinition::fromEntityType($config), EntityContextDefinition::fromEntityType($config), ]; + $data['generic entity requirement, specific context'] = [ + TRUE, + new ContextDefinition('entity'), + EntityContextDefinition::fromEntityType($config), + ]; + $data['specific requirement, generic entity context'] = [ + FALSE, + EntityContextDefinition::fromEntityType($content), + new ContextDefinition('entity'), + ]; return $data; } /** * @covers ::isSatisfiedBy + * @covers ::dataTypeMatches * @covers ::getSampleValues * @covers ::getConstraintObjects * @@ -271,6 +284,7 @@ public function providerTestIsSatisfiedByGenerateBundledEntity() { /** * @covers ::isSatisfiedBy + * @covers ::dataTypeMatches * @covers ::getSampleValues * @covers ::getConstraintObjects * diff --git a/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataType.php b/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataType.php new file mode 100644 index 0000000000..f647238acc --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataType.php @@ -0,0 +1,25 @@ +derivatives[$item] = $base_plugin_definition; + $this->derivatives[$item]['provider'] = 'core'; + } + return $this->derivatives; + } + +}