diff --git a/core/lib/Drupal/Core/TypedData/Resolver/ReflectionResolver.php b/core/lib/Drupal/Core/TypedData/Resolver/ReflectionResolver.php index dd20fe2..3b52659 100644 --- a/core/lib/Drupal/Core/TypedData/Resolver/ReflectionResolver.php +++ b/core/lib/Drupal/Core/TypedData/Resolver/ReflectionResolver.php @@ -9,7 +9,6 @@ use Drupal\Core\TypedData\TypedDataManager; use Symfony\Component\Routing\Route; -use Symfony\Component\Routing\RouteCollection; /** * Generates typed data definitions based on a controller's type hints. @@ -114,11 +113,52 @@ protected function getParameterType(\ReflectionParameter $parameter) { } // Try to find a typed data type that matches the type hint. - foreach ($this->typedDataManager->getDefinitions() as $definition) { - if ($definition['class'] == $name) { + return $class->isInterface() ? $this->getParameterTypeFromInterface($name) : $this->getParameterTypeFromClass($name); + } + + /** + * Tries to determine the typed data type that matches a given interface. + * + * @param string $name + * An interface name for which to find the matching typed data type. + * + * @return array|null + * The typed data definition that matches the given interface or NULL if it + * it is ambiguous or does not match any. + */ + protected function getParameterTypeFromInterface($name) { + foreach ($this->typedDataManager->getDefinitions() as $type => $definition) { + // Check if the defined typed data class implements the given interface. + if (is_subclass_of($definition['class'], $name)) { + // Make sure that the type hint is not ambiguous. + if (isset($match)) { + return; + } + + $match = $type; + } + } + + // Return the matched typed data type if any. + return isset($match) ? array('type' => $match) : NULL; + } + + /** + * Tries to determine the typed data type that matches a given class. + * + * @param string $name + * A class name for which to find the matching typed data type. + * + * @return array|null + * The typed data definition that matches the given interface or NULL if it + * did not match any. + */ + protected function getParameterTypeFromClass($name) { + foreach ($this->typedDataManager->getDefinitions() as $type => $definition) { + if ($definition['class'] === $name) { // Return the first match. return array( - 'type' => $definition['id'], + 'type' => $type, ); } } diff --git a/core/tests/Drupal/Tests/Core/TypedData/ReflectionResolverTest.php b/core/tests/Drupal/Tests/Core/TypedData/ReflectionResolverTest.php index 7301a7d..5378f77 100644 --- a/core/tests/Drupal/Tests/Core/TypedData/ReflectionResolverTest.php +++ b/core/tests/Drupal/Tests/Core/TypedData/ReflectionResolverTest.php @@ -69,6 +69,17 @@ public function providerTestParameters() { 'user' => array('type' => 'entity:user'), 'node' => array('type' => 'entity:node'), )), + array(new Route('/test-3/{block}', array( + '_controller' => 'Drupal\Tests\Core\TypedData\ReflectionTestController::blockController', + )), array( + 'block' => array('type' => 'entity:block'), + )), + array(new Route('/test-4/{block}/{node}', array( + '_controller' => 'Drupal\Tests\Core\TypedData\ReflectionTestController::blockNodeController', + )), array( + 'block' => array('type' => 'entity:block'), + 'node' => array('type' => 'entity:node'), + )), ); } @@ -91,6 +102,10 @@ protected function setupReflectionResolver() { 'id' => 'entity:user', 'class' => 'Drupal\user\Plugin\Core\Entity\User', ), + 'entity:block' => array( + 'id' => 'entity:block', + 'class' => 'Drupal\block\Plugin\Core\Entity\Block', + ), ); $property = new \ReflectionProperty('Drupal\Core\TypedData\TypedDataManager', 'definitions'); diff --git a/core/tests/Drupal/Tests/Core/TypedData/ReflectionTestController.php b/core/tests/Drupal/Tests/Core/TypedData/ReflectionTestController.php index 7cb61b1..2a14b61 100644 --- a/core/tests/Drupal/Tests/Core/TypedData/ReflectionTestController.php +++ b/core/tests/Drupal/Tests/Core/TypedData/ReflectionTestController.php @@ -6,6 +6,7 @@ namespace Drupal\Tests\Core\TypedData; +use Drupal\block\BlockInterface; use Drupal\node\Plugin\Core\Entity\Node; use Drupal\user\Plugin\Core\Entity\User; @@ -26,4 +27,16 @@ public function nodeController(Node $node) { public function nodeUserController(Node $node, User $user) { } + /** + * Controller with a block interface type hint. + */ + public function blockController(BlockInterface $block) { + } + + /** + * Controller with a block interface and a node class type hint. + */ + public function blockNodeController(Node $node, BlockInterface $block) { + } + }