diff --git a/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php b/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php index 7213f16..17dedd1 100644 --- a/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php +++ b/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php @@ -64,8 +64,18 @@ public function __construct(EntityManagerInterface $entity_manager, ConfigFactor * {@inheritdoc} */ public function convert($value, $definition, $name, array $defaults, Request $request) { - $entity_type = substr($definition['type'], strlen('entity:')); - if ($storage = $this->entityManager->getStorage($entity_type)) { + $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults); + + // If the entity type is dynamic, confirm it to be a config entity. Static + // entity types will have performed this check in self::applies(). + if (strpos($definition['type'], 'entity:{') === 0) { + $entity_type = $this->entityManager->getDefinition($entity_type_id); + if (!$entity_type->isSubclassOf('\Drupal\Core\Config\Entity\ConfigEntityInterface')) { + return NULL; + } + } + + if ($storage = $this->entityManager->getStorage($entity_type_id)) { // Make sure no overrides are loaded. $old_state = $this->configFactory->getOverrideState(); $this->configFactory->setOverrideState(FALSE); @@ -80,9 +90,13 @@ public function convert($value, $definition, $name, array $defaults, Request $re */ public function applies($definition, $name, Route $route) { if (parent::applies($definition, $name, $route)) { + $entity_type_id = substr($definition['type'], strlen('entity:')); + // If the entity type is dynamic, defer checking to self::convert(). + if (strpos($entity_type_id, '{') === 0) { + return TRUE; + } // As we only want to override EntityConverter for ConfigEntities, find // out whether the current entity is a ConfigEntity. - $entity_type_id = substr($definition['type'], strlen('entity:')); $entity_type = $this->entityManager->getDefinition($entity_type_id); if ($entity_type->isSubclassOf('\Drupal\Core\Config\Entity\ConfigEntityInterface')) { return $this->adminContext->isAdminRoute($route); diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php index ebce1b3..d225106 100644 --- a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php +++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php @@ -26,7 +26,7 @@ class EntityConverter implements ParamConverterInterface { /** * Constructs a new EntityConverter. * - * @param \Drupal\Core\Entity\EntityManagerInterface $entityManager + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. */ public function __construct(EntityManagerInterface $entity_manager) { @@ -37,14 +37,8 @@ public function __construct(EntityManagerInterface $entity_manager) { * {@inheritdoc} */ public function convert($value, $definition, $name, array $defaults, Request $request) { - $entity_type = substr($definition['type'], strlen('entity:')); - - if (strpos($entity_type, '{') === 0) { - $entity_type = substr($entity_type, 1, -1); - $entity_type = $defaults[$entity_type]; - } - - if ($storage = $this->entityManager->getStorage($entity_type)) { + $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults); + if ($storage = $this->entityManager->getStorage($entity_type_id)) { return $storage->load($value); } } @@ -54,15 +48,44 @@ public function convert($value, $definition, $name, array $defaults, Request $re */ public function applies($definition, $name, Route $route) { if (!empty($definition['type']) && strpos($definition['type'], 'entity:') === 0) { + $entity_type_id = substr($definition['type'], strlen('entity:')); if (strpos($definition['type'], '{') !== FALSE) { - $entity_type = substr($definition['type'], strlen('entity:')); - $entity_type_slug = substr($entity_type, 1, -1); + $entity_type_slug = substr($entity_type_id, 1, -1); return $name != $entity_type_slug && in_array($entity_type_slug, $route->compile()->getVariables(), TRUE); } - $entity_type = substr($definition['type'], strlen('entity:')); - return $this->entityManager->hasDefinition($entity_type); + return $this->entityManager->hasDefinition($entity_type_id); } return FALSE; } + /** + * Determines the entity type ID given a route definition and route defaults. + * + * @param mixed $definition + * The parameter definition provided in the route options. + * @param string $name + * The name of the parameter. + * @param array $defaults + * The route defaults array. + * + * @throws \Drupal\Core\ParamConverter\ParamNotConvertedException + * Thrown when the dynamic entity type is not found in the route defaults. + * + * @return string + * The entity type ID. + */ + protected function getEntityTypeFromDefaults($definition, $name, array $defaults) { + $entity_type_id = substr($definition['type'], strlen('entity:')); + + // If the entity type is dynamic, it will be pulled from the route defaults. + if (strpos($entity_type_id, '{') === 0) { + $entity_type_slug = substr($entity_type_id, 1, -1); + if (!isset($defaults[$entity_type_slug])) { + throw new ParamNotConvertedException(sprintf('The "%s" parameter was not converted because the "%s" parameter is missing', $name, $entity_type_slug)); + } + $entity_type_id = $defaults[$entity_type_slug]; + } + return $entity_type_id; + } + } diff --git a/core/modules/editor/editor.routing.yml b/core/modules/editor/editor.routing.yml index 8b5e5c1..dc41d18 100644 --- a/core/modules/editor/editor.routing.yml +++ b/core/modules/editor/editor.routing.yml @@ -11,6 +11,9 @@ editor.field_untransformed_text: _controller: '\Drupal\editor\EditorController::getUntransformedText' options: _theme: ajax_base_page + parameters: + entity: + type: entity:{entity_type} requirements: _permission: 'access in-place editing' _access_quickedit_entity_field: 'TRUE' diff --git a/core/modules/quickedit/quickedit.routing.yml b/core/modules/quickedit/quickedit.routing.yml index 83b2c04..0a13988 100644 --- a/core/modules/quickedit/quickedit.routing.yml +++ b/core/modules/quickedit/quickedit.routing.yml @@ -21,6 +21,9 @@ quickedit.field_form: options: _access_mode: 'ALL' _theme: ajax_base_page + parameters: + entity: + type: entity:{entity_type} requirements: _permission: 'access in-place editing' _access_quickedit_entity_field: 'TRUE' @@ -31,7 +34,8 @@ quickedit.entity_save: _controller: '\Drupal\quickedit\QuickEditController::entitySave' requirements: _permission: 'access in-place editing' - _access_quickedit_entity: 'TRUE' + _entity_access: 'entity.update' + options: parameters: entity: type: entity:{entity_type} diff --git a/core/modules/quickedit/quickedit.services.yml b/core/modules/quickedit/quickedit.services.yml index 933f255..692ba2f 100644 --- a/core/modules/quickedit/quickedit.services.yml +++ b/core/modules/quickedit/quickedit.services.yml @@ -4,14 +4,8 @@ services: parent: default_plugin_manager access_check.quickedit.entity_field: class: Drupal\quickedit\Access\EditEntityFieldAccessCheck - arguments: ['@entity.manager'] tags: - { name: access_check, applies_to: _access_quickedit_entity_field } - access_check.quickedit.entity: - class: Drupal\quickedit\Access\EditEntityAccessCheck - arguments: ['@entity.manager'] - tags: - - { name: access_check, applies_to: _access_quickedit_entity } quickedit.editor.selector: class: Drupal\quickedit\EditorSelector arguments: ['@plugin.manager.quickedit.editor', '@plugin.manager.field.formatter'] diff --git a/core/modules/quickedit/src/Access/EditEntityAccessCheck.php b/core/modules/quickedit/src/Access/EditEntityAccessCheck.php deleted file mode 100644 index a80aa2e..0000000 --- a/core/modules/quickedit/src/Access/EditEntityAccessCheck.php +++ /dev/null @@ -1,90 +0,0 @@ -entityManager = $entity_manager; - } - - /** - * Checks Quick Edit access to the entity. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request object. - * @param \Drupal\Core\Session\AccountInterface $account - * The currently logged in account. - * - * @return string - * A \Drupal\Core\Access\AccessInterface constant value. - * - * @todo Replace $request parameter with $entity once - * https://drupal.org/node/1837388 is fixed. - */ - public function access(Request $request, AccountInterface $account) { - if (!$this->validateAndUpcastRequestAttributes($request)) { - return static::KILL; - } - - return $this->accessEditEntity($request->attributes->get('entity'), $account) ? static::ALLOW : static::DENY; - } - - /** - * {@inheritdoc} - */ - protected function accessEditEntity(EntityInterface $entity, $account) { - return $entity->access('update', $account); - } - - /** - * Validates and upcasts request attributes. - * - * @todo Remove once https://drupal.org/node/1837388 is fixed. - */ - protected function validateAndUpcastRequestAttributes(Request $request) { - // Load the entity. - if (!is_object($entity = $request->attributes->get('entity'))) { - $entity_id = $entity; - $entity_type = $request->attributes->get('entity_type'); - if (!$entity_type || !$this->entityManager->getDefinition($entity_type)) { - return FALSE; - } - $entity = $this->entityManager->getStorage($entity_type)->load($entity_id); - if (!$entity) { - return FALSE; - } - $request->attributes->set('entity', $entity); - } - - return TRUE; - } - -} diff --git a/core/modules/quickedit/src/Access/EditEntityFieldAccessCheck.php b/core/modules/quickedit/src/Access/EditEntityFieldAccessCheck.php index 23c9541..9edb49e 100644 --- a/core/modules/quickedit/src/Access/EditEntityFieldAccessCheck.php +++ b/core/modules/quickedit/src/Access/EditEntityFieldAccessCheck.php @@ -7,10 +7,8 @@ namespace Drupal\quickedit\Access; -use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Routing\Access\AccessInterface; use Drupal\Core\Session\AccountInterface; -use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Entity\EntityInterface; /** @@ -19,46 +17,28 @@ class EditEntityFieldAccessCheck implements AccessInterface, EditEntityFieldAccessCheckInterface { /** - * The entity manager. - * - * @var \Drupal\Core\Entity\EntityManagerInterface - */ - protected $entityManager; - - /** - * Constructs a EditEntityFieldAccessCheck object. - * - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager. - */ - public function __construct(EntityManagerInterface $entity_manager) { - $this->entityManager = $entity_manager; - } - - /** * Checks Quick Edit access to the field. * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request object. - * @param string $field_name. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity containing the field. + * @param string $field_name * The field name. + * @param string $langcode + * The langcode. * @param \Drupal\Core\Session\AccountInterface $account * The currently logged in account. * * @return string * A \Drupal\Core\Access\AccessInterface constant value. * - * @todo Replace $request parameter with $entity once - * https://drupal.org/node/1837388 is fixed. - * * @todo Use the $account argument: https://drupal.org/node/2266809. */ - public function access(EntityInterface $entity, Request $request, $field_name, AccountInterface $account) { - if (!$this->validateAndUpcastRequestAttributes($entity, $request)) { + public function access(EntityInterface $entity, $field_name, $langcode, AccountInterface $account) { + if (!$this->validateRequestAttributes($entity, $field_name, $langcode)) { return static::KILL; } - return $this->accessEditEntityField($request->attributes->get('entity'), $field_name) ? static::ALLOW : static::DENY; + return $this->accessEditEntityField($entity, $field_name) ? static::ALLOW : static::DENY; } /** @@ -69,15 +49,13 @@ public function accessEditEntityField(EntityInterface $entity, $field_name) { } /** - * Validates and upcasts request attributes. + * Validates request attributes. */ - protected function validateAndUpcastRequestAttributes(EntityInterface $entity, Request $request) { + protected function validateRequestAttributes(EntityInterface $entity, $field_name, $langcode) { // Validate the field name and language. - $field_name = $request->attributes->get('field_name'); if (!$field_name || !$entity->hasField($field_name)) { return FALSE; } - $langcode = $request->attributes->get('langcode'); if (!$langcode || !$entity->hasTranslation($langcode)) { return FALSE; } diff --git a/core/modules/quickedit/tests/src/Access/EditEntityAccessCheckTest.php b/core/modules/quickedit/tests/src/Access/EditEntityAccessCheckTest.php deleted file mode 100644 index 33d4ed4..0000000 --- a/core/modules/quickedit/tests/src/Access/EditEntityAccessCheckTest.php +++ /dev/null @@ -1,142 +0,0 @@ -entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface'); - - $this->entityStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface'); - - $this->entityManager->expects($this->any()) - ->method('getStorage') - ->will($this->returnValue($this->entityStorage)); - - $this->editAccessCheck = new EditEntityAccessCheck($this->entityManager); - } - - /** - * Provides test data for testAccess(). - * - * @see \Drupal\quickedit\Tests\quickedit\Access\EditEntityAccessCheckTest::testAccess() - */ - public function providerTestAccess() { - $editable_entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest') - ->disableOriginalConstructor() - ->getMock(); - $editable_entity->expects($this->any()) - ->method('access') - ->will($this->returnValue(TRUE)); - - $non_editable_entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest') - ->disableOriginalConstructor() - ->getMock(); - $non_editable_entity->expects($this->any()) - ->method('access') - ->will($this->returnValue(FALSE)); - - $data = array(); - $data[] = array($editable_entity, AccessCheckInterface::ALLOW); - $data[] = array($non_editable_entity, AccessCheckInterface::DENY); - - return $data; - } - - /** - * Tests the method for checking access to routes. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * A mocked entity. - * @param bool|null $expected_result - * The expected result of the access call. - * - * @dataProvider providerTestAccess - */ - public function testAccess(EntityInterface $entity, $expected_result) { - $request = new Request(); - - // Prepare the request to be valid. - $request->attributes->set('entity', $entity); - $request->attributes->set('entity_type', 'test_entity'); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $access = $this->editAccessCheck->access($request, $account); - $this->assertSame($expected_result, $access); - } - - /** - * Tests the access method with an undefined entity type. - */ - public function testAccessWithUndefinedEntityType() { - $request = new Request(); - $request->attributes->set('entity_type', 'non_valid'); - - $this->entityManager->expects($this->once()) - ->method('getDefinition') - ->with('non_valid') - ->will($this->returnValue(NULL)); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, $account)); - } - - /** - * Tests the access method with a non existing entity. - */ - public function testAccessWithNotExistingEntity() { - $request = new Request(); - $request->attributes->set('entity_type', 'entity_test'); - $request->attributes->set('entity', 1); - - $this->entityManager->expects($this->once()) - ->method('getDefinition') - ->with('entity_test') - ->will($this->returnValue(array('id' => 'entity_test'))); - - $this->entityStorage->expects($this->once()) - ->method('load') - ->with(1) - ->will($this->returnValue(NULL)); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, $account)); - } - -} diff --git a/core/modules/quickedit/tests/src/Access/EditEntityFieldAccessCheckTest.php b/core/modules/quickedit/tests/src/Access/EditEntityFieldAccessCheckTest.php index 5a97dd2..a863046 100644 --- a/core/modules/quickedit/tests/src/Access/EditEntityFieldAccessCheckTest.php +++ b/core/modules/quickedit/tests/src/Access/EditEntityFieldAccessCheckTest.php @@ -7,7 +7,6 @@ namespace Drupal\quickedit\Tests\Access; -use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Access\AccessCheckInterface; use Drupal\quickedit\Access\EditEntityFieldAccessCheck; use Drupal\Tests\UnitTestCase; @@ -29,29 +28,10 @@ class EditEntityFieldAccessCheckTest extends UnitTestCase { protected $editAccessCheck; /** - * The mocked entity manager. - * - * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject + * {@inheritdoc} */ - protected $entityManager; - - /** - * The mocked entity storage. - * - * @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $entityStorage; - protected function setUp() { - $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface'); - - $this->entityStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface'); - - $this->entityManager->expects($this->any()) - ->method('getStorage') - ->will($this->returnValue($this->entityStorage)); - - $this->editAccessCheck = new EditEntityFieldAccessCheck($this->entityManager); + $this->editAccessCheck = new EditEntityFieldAccessCheck(); } /** @@ -105,8 +85,6 @@ public function providerTestAccess() { * @dataProvider providerTestAccess */ public function testAccess(EntityInterface $entity, FieldStorageConfigInterface $field_storage = NULL, $expected_result) { - $request = new Request(); - $field_name = 'valid'; $entity_with_field = clone $entity; $entity_with_field->expects($this->any()) @@ -118,118 +96,42 @@ public function testAccess(EntityInterface $entity, FieldStorageConfigInterface ->with(LanguageInterface::LANGCODE_NOT_SPECIFIED) ->will($this->returnValue(TRUE)); - // Prepare the request to be valid. - $request->attributes->set('entity_type', 'test_entity'); - $request->attributes->set('entity', $entity_with_field); - $request->attributes->set('field_name', $field_name); - $request->attributes->set('langcode', LanguageInterface::LANGCODE_NOT_SPECIFIED); - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $access = $this->editAccessCheck->access($request, $field_name, $account); + $access = $this->editAccessCheck->access($entity_with_field, $field_name, LanguageInterface::LANGCODE_NOT_SPECIFIED, $account); $this->assertSame($expected_result, $access); } /** - * Tests the access method with an undefined entity type. + * Tests checking access to routes that result in AccessCheckInterface::KILL. + * + * @dataProvider providerTestAccessKill */ - public function testAccessWithUndefinedEntityType() { - $request = new Request(); - $request->attributes->set('entity_type', 'non_valid'); - - $this->entityManager->expects($this->once()) - ->method('getDefinition') - ->with('non_valid') - ->will($this->returnValue(NULL)); - + public function testAccessKill($field_name, $langcode) { $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, NULL, $account)); - } - - /** - * Tests the access method with a non existing entity. - */ - public function testAccessWithNotExistingEntity() { - $request = new Request(); - $request->attributes->set('entity_type', 'entity_test'); - $request->attributes->set('entity', 1); - - $this->entityManager->expects($this->once()) - ->method('getDefinition') - ->with('entity_test') - ->will($this->returnValue(array('id' => 'entity_test'))); - - $this->entityStorage->expects($this->once()) - ->method('load') - ->with(1) - ->will($this->returnValue(NULL)); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, NULL, $account)); - } - - /** - * Tests the access method with a forgotten passed field_name. - */ - public function testAccessWithNotPassedFieldName() { - $request = new Request(); - $request->attributes->set('entity_type', 'entity_test'); - $request->attributes->set('entity', $this->createMockEntity()); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, NULL, $account)); - } - - /** - * Tests the access method with a non existing field. - */ - public function testAccessWithNonExistingField() { - $request = new Request(); - $field_name = 'not_valid'; - $request->attributes->set('entity_type', 'entity_test'); - $request->attributes->set('entity', $this->createMockEntity()); - $request->attributes->set('field_name', $field_name); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, $field_name, $account)); - } - - /** - * Tests the access method with a forgotten passed language. - */ - public function testAccessWithNotPassedLanguage() { - $request = new Request(); - $field_name = 'valid'; - $request->attributes->set('entity_type', 'entity_test'); - $request->attributes->set('entity', $this->createMockEntity()); - $request->attributes->set('field_name', $field_name); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, $field_name, $account)); - } - - /** - * Tests the access method with an invalid language. - */ - public function testAccessWithInvalidLanguage() { $entity = $this->createMockEntity(); - $entity->expects($this->once()) - ->method('hasTranslation') - ->with('xx-lolspeak') - ->will($this->returnValue(FALSE)); + $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($entity, $field_name, $langcode, $account)); + } - $request = new Request(); - $field_name = 'valid'; - $request->attributes->set('entity_type', 'entity_test'); - $request->attributes->set('entity', $entity); - $request->attributes->set('field_name', $field_name); - $request->attributes->set('langcode', 'xx-lolspeak'); - - $account = $this->getMock('Drupal\Core\Session\AccountInterface'); - $this->assertSame(AccessCheckInterface::KILL, $this->editAccessCheck->access($request, $field_name, $account)); + /** + * Provides test data for testAccessKill. + */ + public function providerTestAccessKill() { + $data = array(); + // Tests the access method without a field_name. + $data[] = array(NULL, LanguageInterface::LANGCODE_NOT_SPECIFIED); + // Tests the access method with a non-existent field. + $data[] = array('not_valid', LanguageInterface::LANGCODE_NOT_SPECIFIED); + // Tests the access method without a langcode. + $data[] = array('valid', NULL); + // Tests the access method with an invalid langcode. + $data[] = array('valid', 'xx-lolspeak'); + return $data; } /** * Returns a mock entity. + * + * @return \Drupal\Core\Entity\EntityInterface|\PHPUnit_Framework_MockObject_MockObject */ protected function createMockEntity() { $entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest') @@ -237,6 +139,12 @@ protected function createMockEntity() { ->getMock(); $entity->expects($this->any()) + ->method('hasTranslation') + ->will($this->returnValueMap(array( + array(LanguageInterface::LANGCODE_NOT_SPECIFIED, TRUE), + array('xx-lolspeak', FALSE), + ))); + $entity->expects($this->any()) ->method('hasField') ->will($this->returnValueMap(array( array('valid', TRUE), diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php index 816779e..baeb0c4 100644 --- a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php +++ b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php @@ -70,6 +70,7 @@ public function providerTestApplies() { $data[] = [['type' => 'entity:entity_test'], 'entity_test', new Route('/test/{entity_test}/bar'), TRUE]; $data[] = [['type' => 'entity:{entity_test}'], 'entity_test', new Route('/test/{entity_test}/bar'), FALSE]; $data[] = [['type' => 'entity:{entity_type}'], 'entity_test', new Route('/test/{entity_type}/{entity_test}/bar'), TRUE]; + $data[] = [['type' => 'foo'], 'entity_test', new Route('/test/{entity_type}/{entity_test}/bar'), FALSE]; return $data; } @@ -123,7 +124,17 @@ public function testConvertWithInvalidEntityType() { ->with('invalid_id') ->willThrowException(new \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException('invalid_id')); - $this->entityConverter->convert('id', ['entity_type:invalid_id'], 'foo', ['foo' => 'id'], new Request()); + $this->entityConverter->convert('id', ['type' => 'entity:invalid_id'], 'foo', ['foo' => 'id'], new Request()); + } + + /** + * Tests the convert() method with an invalid dynamic entity type. + * + * @expectedException \Drupal\Core\ParamConverter\ParamNotConvertedException + * @expectedExceptionMessage The "foo" parameter was not converted because the "invalid_id" parameter is missing + */ + public function testConvertWithInvalidDynamicEntityType() { + $this->entityConverter->convert('id', ['type' => 'entity:{invalid_id}'], 'foo', ['foo' => 'id'], new Request()); } }