Issue #2596095 by tstoeckler, bojanz, dawehner: Provide a route provider for add-form of entities

8.1.x
Nathaniel Catchpole 2016-02-24 14:20:32 +09:00
parent ffa6d37e49
commit 71bdc7bb54
11 changed files with 407 additions and 118 deletions

View File

@ -7,7 +7,9 @@
namespace Drupal\Core\Entity\Controller;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
@ -19,6 +21,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* Provides generic entity title callbacks for use in routing.
*
* It provides:
* - An add title callback for entities without bundles.
* - An add title callback for entities with bundles.
* - A view title callback.
* - An edit title callback.
* - A delete title callback.
@ -30,20 +34,40 @@ class EntityController implements ContainerInjectionInterface {
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityManager;
protected $entityTypeManager;
/**
* The entity type bundle info.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The entity repository.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* Constructs a new EntityController.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
* The entity type bundle info.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation.
*/
public function __construct(EntityManagerInterface $entity_manager, TranslationInterface $string_translation) {
$this->entityManager = $entity_manager;
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityRepositoryInterface $entity_repository, TranslationInterface $string_translation) {
$this->entityTypeManager = $entity_type_manager;
$this->entityTypeBundleInfo = $entity_type_bundle_info;
$this->entityRepository = $entity_repository;
$this->stringTranslation = $string_translation;
}
@ -52,11 +76,56 @@ class EntityController implements ContainerInjectionInterface {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('entity_type.manager'),
$container->get('entity_type.bundle.info'),
$container->get('entity.repository'),
$container->get('string_translation')
);
}
/**
* Provides a generic add title callback for entities without bundles.
*
* @param string $entity_type_id
* The entity type ID.
*
* @return string
* The title for the entity add page.
*/
public function addTitle($entity_type_id) {
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
return $this->t('Add @entity-type', ['@entity-type' => $entity_type->getLowercaseLabel()]);
}
/**
* Provides a generic add title callback for entities with bundles.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match.
* @param string $entity_type_id
* The entity type ID.
* @param string $bundle_parameter
* The name of the route parameter that holds the bundle.
*
* @return string
* The title for the entity add page, if the bundle was found.
*/
public function addBundleTitle(RouteMatchInterface $route_match, $entity_type_id, $bundle_parameter) {
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
// If the entity has bundle entities, the parameter might have been upcasted
// so fetch the raw parameter.
$bundle = $route_match->getRawParameter($bundle_parameter);
if ((count($bundles) > 1) && isset($bundles[$bundle])) {
return $this->t('Add @bundle', ['@bundle' => $bundles[$bundle]['label']]);
}
// If the entity supports bundles generally, but only has a single bundle,
// the bundle is probably something like 'Default' so that it preferable to
// use the entity type label.
else {
return $this->addTitle($entity_type_id);
}
}
/**
* Provides a generic title callback for a single entity.
*
@ -65,8 +134,8 @@ class EntityController implements ContainerInjectionInterface {
* @param \Drupal\Core\Entity\EntityInterface $_entity
* (optional) An entity, passed in directly from the request attributes.
*
* @return string
* The title for the entity view page.
* @return string|null
* The title for the entity view page, if an entity was found.
*/
public function title(RouteMatchInterface $route_match, EntityInterface $_entity = NULL) {
if ($entity = $this->doGetEntity($route_match, $_entity)) {
@ -82,8 +151,8 @@ class EntityController implements ContainerInjectionInterface {
* @param \Drupal\Core\Entity\EntityInterface $_entity
* (optional) An entity, passed in directly from the request attributes.
*
* @return string
* The title for the entity edit page.
* @return string|null
* The title for the entity edit page, if an entity was found.
*/
public function editTitle(RouteMatchInterface $route_match, EntityInterface $_entity = NULL) {
if ($entity = $this->doGetEntity($route_match, $_entity)) {
@ -101,7 +170,7 @@ class EntityController implements ContainerInjectionInterface {
* set in \Drupal\Core\Entity\Enhancer\EntityRouteEnhancer.
*
* @return string
* The title for the delete entity page.
* The title for the entity delete page.
*/
public function deleteTitle(RouteMatchInterface $route_match, EntityInterface $_entity = NULL) {
if ($entity = $this->doGetEntity($route_match, $_entity)) {
@ -135,8 +204,8 @@ class EntityController implements ContainerInjectionInterface {
}
}
}
if ($entity) {
return $this->entityManager->getTranslationFromContext($entity);
if (isset($entity)) {
return $this->entityRepository->getTranslationFromContext($entity);
}
}

View File

@ -21,6 +21,16 @@ use Drupal\Core\Entity\EntityTypeInterface;
*/
class AdminHtmlRouteProvider extends DefaultHtmlRouteProvider {
/**
* {@inheritdoc}
*/
protected function getAddFormRoute(EntityTypeInterface $entity_type) {
if ($route = parent::getAddFormRoute($entity_type)) {
$route->setOption('_admin_route', TRUE);
return $route;
}
}
/**
* {@inheritdoc}
*/

View File

@ -7,9 +7,12 @@
namespace Drupal\Core\Entity\Routing;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\Controller\EntityController;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Route;
@ -31,20 +34,30 @@ use Symfony\Component\Routing\RouteCollection;
class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHandlerInterface {
/**
* The entity manager.
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
protected $entityTypeManager;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* Constructs a new DefaultHtmlRouteProvider.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
*/
public function __construct(EntityManagerInterface $entity_manager) {
$this->entityManager = $entity_manager;
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
}
/**
@ -52,7 +65,8 @@ class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHa
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$container->get('entity.manager')
$container->get('entity_type.manager'),
$container->get('entity_field.manager')
);
}
@ -64,14 +78,18 @@ class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHa
$entity_type_id = $entity_type->id();
if ($edit_route = $this->getEditFormRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.edit_form", $edit_route);
if ($add_route = $this->getAddFormRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.add_form", $add_route);
}
if ($canonical_route = $this->getCanonicalRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.canonical", $canonical_route);
}
if ($edit_route = $this->getEditFormRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.edit_form", $edit_route);
}
if ($delete_route = $this->getDeleteFormRoute($entity_type)) {
$collection->add("entity.{$entity_type_id}.delete_form", $delete_route);
}
@ -79,6 +97,78 @@ class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHa
return $collection;
}
/**
* Gets the add-form route.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
protected function getAddFormRoute(EntityTypeInterface $entity_type) {
if ($entity_type->hasLinkTemplate('add-form')) {
$entity_type_id = $entity_type->id();
$route = new Route($entity_type->getLinkTemplate('add-form'));
// Use the add form handler, if available, otherwise default.
$operation = 'default';
if ($entity_type->getFormClass('add')) {
$operation = 'add';
}
$route->setDefaults([
'_entity_form' => "{$entity_type_id}.{$operation}",
'entity_type_id' => $entity_type_id,
]);
// If the entity has bundles, we can provide a bundle-specific title
// and access requirements.
if ($bundle_key = $entity_type->getKey('bundle')) {
$route->setDefault('_title_callback', EntityController::class . '::addBundleTitle');
// If the bundles are entities themselves, we can add parameter
// information to the route options.
if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) {
$bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
$route
// The title callback uses the value of the bundle parameter to
// fetch the respective bundle at runtime.
->setDefault('bundle_parameter', $bundle_entity_type_id)
->setRequirement('_entity_create_access', "{$entity_type_id}:{$bundle_entity_type_id}");
// Entity types with serial IDs can specify this in their route
// requirements, improving the matching process.
if ($this->getEntityTypeIdKeyType($bundle_entity_type) === 'integer') {
$route->setRequirement($entity_type_id, '\d+');
}
$bundle_entity_parameter = ['type' => 'entity:' . $bundle_entity_type_id];
if ($bundle_entity_type instanceof ConfigEntityTypeInterface) {
// The add page might be displayed on an admin path. Even then, we
// need to load configuration overrides so that, for example, the
// bundle label gets translated correctly.
// @see \Drupal\Core\ParamConverter\AdminPathConfigEntityConverter
$bundle_entity_parameter['with_config_overrides'] = TRUE;
}
$route->setOption('parameters', [$bundle_entity_type_id => $bundle_entity_parameter]);
}
else {
// If the bundles are not entities, the bundle key is used as the
// route parameter name directly.
$route
->setDefault('bundle_parameter', $bundle_key)
->setRequirement('_entity_create_access', "{$entity_type_id}:{$bundle_key}");
}
}
else {
$route
->setDefault('_title_callback', EntityController::class . '::addTitle')
->setRequirement('_entity_create_access', $entity_type_id);
}
return $route;
}
}
/**
* Gets the canonical route.
*
@ -195,7 +285,7 @@ class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHa
return NULL;
}
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type->id());
$field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type->id());
return $field_storage_definitions[$entity_type->getKey('id')]->getType();
}

View File

@ -38,6 +38,7 @@ namespace Drupal\entity_test\Entity;
* "langcode" = "langcode",
* },
* links = {
* "add-form" = "/entity_test_mul/add",
* "canonical" = "/entity_test_mul/manage/{entity_test_mul}",
* "edit-form" = "/entity_test_mul/manage/{entity_test_mul}/edit",
* "delete-form" = "/entity_test/delete/entity_test_mul/{entity_test_mul}",

View File

@ -42,6 +42,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
* "langcode" = "langcode"
* },
* links = {
* "add-form" = "/entity_test_mul_changed/add",
* "canonical" = "/entity_test_mul_changed/manage/{entity_test_mul_changed}",
* "edit-form" = "/entity_test_mul_changed/manage/{entity_test_mul_changed}/edit",
* "delete-form" = "/entity_test/delete/entity_test_mul_changed/{entity_test_mul_changed}",

View File

@ -41,6 +41,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
* "default_langcode" = "custom_default_langcode_key",
* },
* links = {
* "add-form" = "/entity_test_mul_langcode_key/add",
* "canonical" = "/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}",
* "edit-form" = "/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}/edit",
* "delete-form" = "/entity_test/delete/entity_test_mul_langcode_key/{entity_test_mul_langcode_key}",

View File

@ -41,6 +41,7 @@ namespace Drupal\entity_test\Entity;
* "langcode" = "langcode",
* },
* links = {
* "add-form" = "/entity_test_mulrev/add",
* "canonical" = "/entity_test_mulrev/manage/{entity_test_mulrev}",
* "delete-form" = "/entity_test/delete/entity_test_mulrev/{entity_test_mulrev}",
* "edit-form" = "/entity_test_mulrev/manage/{entity_test_mulrev}/edit",

View File

@ -43,6 +43,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
* "langcode" = "langcode",
* },
* links = {
* "add-form" = "/entity_test_mulrev_changed/add",
* "canonical" = "/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}",
* "delete-form" = "/entity_test/delete/entity_test_mulrev_changed/{entity_test_mulrev_changed}",
* "edit-form" = "/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}/edit",

View File

@ -42,6 +42,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
* "langcode" = "langcode",
* },
* links = {
* "add-form" = "/entity_test_rev/add",
* "canonical" = "/entity_test_rev/manage/{entity_test_rev}",
* "delete-form" = "/entity_test/delete/entity_test_rev/{entity_test_rev}",
* "edit-form" = "/entity_test_rev/manage/{entity_test_rev}/edit",

View File

@ -30,7 +30,6 @@ class EntityTestRoutes {
array('_entity_form' => "$entity_type_id.default"),
array('_permission' => 'administer entity_test content')
);
$routes["entity.$entity_type_id.admin_form"] = new Route(
"$entity_type_id/structure/{bundle}",
array('_controller' => '\Drupal\entity_test\Controller\EntityTestController::testAdmin'),

View File

@ -7,13 +7,16 @@
namespace Drupal\Tests\Core\Entity\Routing;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Symfony\Component\Routing\Route;
/**
@ -22,24 +25,203 @@ use Symfony\Component\Routing\Route;
*/
class DefaultHtmlRouteProviderTest extends UnitTestCase {
/**
* The entity type manager prophecy used in the test.
*
* @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity field manager prophecy used in the test.
*
* @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* The HTML route provider used in the test.
*
* @var \Drupal\Tests\Core\Entity\Routing\TestDefaultHtmlRouteProvider
*/
protected $routeProvider;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
$this->entityFieldManager = $this->prophesize(EntityFieldManagerInterface::class);
$this->routeProvider = new TestDefaultHtmlRouteProvider($this->entityTypeManager->reveal(), $this->entityFieldManager->reveal());
}
/**
* @covers ::getAddFormRoute
* @dataProvider providerTestGetAddFormRoute
*/
public function testGetAddFormRoute(Route $expected = NULL, EntityTypeInterface $entity_type, EntityTypeInterface $bundle_entity_type = NULL, FieldStorageDefinitionInterface $field_storage_definition = NULL) {
if ($bundle_entity_type) {
$this->entityTypeManager->getDefinition('the_bundle_entity_type_id')->willReturn($bundle_entity_type);
if ($field_storage_definition) {
$this->entityFieldManager->getFieldStorageDefinitions('the_bundle_entity_type_id')
->willReturn(['id' => $field_storage_definition]);
}
}
$route = $this->routeProvider->getAddFormRoute($entity_type);
$this->assertEquals($expected, $route);
}
public function providerTestGetAddFormRoute() {
$data = [];
$entity_type1 = $this->getEntityType();
$entity_type1->hasLinkTemplate('add-form')->willReturn(FALSE);
$data['no_add_form_link_template'] = [NULL, $entity_type1->reveal()];
$entity_type2 = $this->getEntityType();
$entity_type2->hasLinkTemplate('add-form')->willReturn(TRUE);
$entity_type2->id()->willReturn('the_entity_type_id');
$entity_type2->getLinkTemplate('add-form')->willReturn('/the/add/form/link/template');
$entity_type2->getFormClass('add')->willReturn(NULL);
$entity_type2->getKey('bundle')->willReturn(NULL);
$route = (new Route('/the/add/form/link/template'))
->setDefaults([
'_entity_form' => 'the_entity_type_id.default',
'entity_type_id' => 'the_entity_type_id',
'_title_callback' => 'Drupal\Core\Entity\Controller\EntityController::addTitle',
])
->setRequirement('_entity_create_access', 'the_entity_type_id')
;
$data['no_add_form_no_bundle'] = [clone $route, $entity_type2->reveal()];
$entity_type3 = $this->getEntityType($entity_type2);
$entity_type3->getFormClass('add')->willReturn('Drupal\Core\Entity\EntityForm');
$route->setDefault('_entity_form', 'the_entity_type_id.add');
$data['add_form_no_bundle'] = [clone $route, $entity_type3->reveal()];
$entity_type4 = $this->getEntityType($entity_type3);
$entity_type4->getKey('bundle')->willReturn('the_bundle_key');
$entity_type4->getBundleEntityType()->willReturn(NULL);
$route
->setDefault('_title_callback', 'Drupal\Core\Entity\Controller\EntityController::addBundleTitle')
->setDefault('bundle_parameter', 'the_bundle_key')
->setRequirement('_entity_create_access', 'the_entity_type_id:the_bundle_key');
$data['add_form_bundle_static'] = [clone $route, $entity_type4->reveal()];
$entity_type5 = $this->getEntityType($entity_type4);
$entity_type5->getBundleEntityType()->willReturn('the_bundle_entity_type_id');
$bundle_entity_type = $this->getEntityType();
$bundle_entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(FALSE);
$route
->setDefault('bundle_parameter', 'the_bundle_entity_type_id')
->setRequirement('_entity_create_access', 'the_entity_type_id:the_bundle_entity_type_id')
->setOption('parameters', ['the_bundle_entity_type_id' => [
'type' => 'entity:the_bundle_entity_type_id',
]]);
$data['add_form_bundle_entity_id_key_type_null'] = [clone $route, $entity_type5->reveal(), $bundle_entity_type->reveal()];
$entity_type6 = $this->getEntityType($entity_type5);
$bundle_entity_type = $this->getEntityType();
$bundle_entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(TRUE);
$field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
$field_storage_definition->getType()->willReturn('integer');
$route->setRequirement('the_entity_type_id', '\d+');
$data['add_form_bundle_entity_id_key_type_integer'] = [clone $route, $entity_type6->reveal(), $bundle_entity_type->reveal(), $field_storage_definition->reveal()];
$entity_type7 = $this->getEntityType($entity_type6);
$bundle_entity_type = $this->prophesize(ConfigEntityTypeInterface::class);
$bundle_entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(FALSE);
$field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
$route
// Unset the 'the_entity_type_id' requirement.
->setRequirements(['_entity_create_access' => $route->getRequirement('_entity_create_access')])
->setOption('parameters', ['the_bundle_entity_type_id' => [
'type' => 'entity:the_bundle_entity_type_id',
'with_config_overrides' => TRUE,
]]);
$data['add_form_bundle_entity_id_key_type_integer'] = [clone $route, $entity_type7->reveal(), $bundle_entity_type->reveal(), $field_storage_definition->reveal()];
return $data;
}
/**
* @covers ::getCanonicalRoute
* @dataProvider providerTestGetCanonicalRoute
*/
public function testGetCanonicalRoute(Route $expected = NULL, EntityTypeInterface $entity_type, FieldStorageDefinitionInterface $field_storage_definition = NULL) {
if ($field_storage_definition) {
$this->entityFieldManager->getFieldStorageDefinitions($entity_type->id())
->willReturn([$entity_type->getKey('id') => $field_storage_definition]);
}
$route = $this->routeProvider->getCanonicalRoute($entity_type);
$this->assertEquals($expected, $route);
}
public function providerTestGetCanonicalRoute() {
$data = [];
$entity_type1 = $this->getEntityType();
$entity_type1->hasLinkTemplate('canonical')->willReturn(FALSE);
$data['no_canonical_link_template'] = [NULL, $entity_type1->reveal()];
$entity_type2 = $this->getEntityType();;
$entity_type2->hasLinkTemplate('canonical')->willReturn(TRUE);
$entity_type2->hasViewBuilderClass()->willReturn(FALSE);
$data['no_view_builder'] = [NULL, $entity_type2->reveal()];
$entity_type3 = $this->getEntityType($entity_type2);
$entity_type3->hasViewBuilderClass()->willReturn(TRUE);
$entity_type3->id()->willReturn('the_entity_type_id');
$entity_type3->getLinkTemplate('canonical')->willReturn('/the/canonical/link/template');
$entity_type3->isSubclassOf(FieldableEntityInterface::class)->willReturn(FALSE);
$route = (new Route('/the/canonical/link/template'))
->setDefaults([
'_entity_view' => 'the_entity_type_id.full',
'_title_callback' => '\Drupal\Core\Entity\Controller\EntityController::title',
])
->setRequirements([
'_entity_access' => 'the_entity_type_id.view',
])
->setOptions([
'parameters' => [
'the_entity_type_id' => [
'type' => 'entity:the_entity_type_id',
],
],
]);
$data['id_key_type_null'] = [clone $route, $entity_type3->reveal()];
$entity_type4 = $this->getEntityType($entity_type3);
$entity_type4->isSubclassOf(FieldableEntityInterface::class)->willReturn(TRUE);
$entity_type4->getKey('id')->willReturn('id');
$route->setRequirement('the_entity_type_id', '\d+');
$field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
$field_storage_definition->getType()->willReturn('integer');
$data['id_key_type_integer'] = [clone $route, $entity_type4->reveal(), $field_storage_definition->reveal()];
return $data;
}
/**
* @covers ::getEntityTypeIdKeyType
*/
public function testGetEntityTypeIdKeyType() {
$entity_manager = $this->prophesize(EntityManagerInterface::class);
$route_provider = new TestDefaultHtmlRouteProvider($entity_manager->reveal());
$entity_type = $this->prophesize(EntityTypeInterface::class);
$entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(TRUE);
$entity_type_id = 'the_entity_type_id';
$entity_type->id()->willReturn($entity_type_id);
$entity_type->id()->willReturn('the_entity_type_id');
$entity_type->getKey('id')->willReturn('id');
$field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
$field_storage_definition->getType()->willReturn('integer');
$entity_manager->getFieldStorageDefinitions($entity_type_id)->willReturn(['id' => $field_storage_definition]);
$this->entityFieldManager->getFieldStorageDefinitions('the_entity_type_id')->willReturn(['id' => $field_storage_definition]);
$type = $route_provider->getEntityTypeIdKeyType($entity_type->reveal());
$type = $this->routeProvider->getEntityTypeIdKeyType($entity_type->reveal());
$this->assertSame('integer', $type);
}
@ -47,98 +229,28 @@ class DefaultHtmlRouteProviderTest extends UnitTestCase {
* @covers ::getEntityTypeIdKeyType
*/
public function testGetEntityTypeIdKeyTypeNotFieldable() {
$entity_manager = $this->prophesize(EntityManagerInterface::class);
$route_provider = new TestDefaultHtmlRouteProvider($entity_manager->reveal());
$entity_type = $this->prophesize(EntityTypeInterface::class);
$entity_type->isSubclassOf(FieldableEntityInterface::class)->willReturn(FALSE);
$entity_manager->getFieldStorageDefinitions(Argument::any())->shouldNotBeCalled();
$this->entityFieldManager->getFieldStorageDefinitions(Argument::any())->shouldNotBeCalled();
$type = $route_provider->getEntityTypeIdKeyType($entity_type->reveal());
$type = $this->routeProvider->getEntityTypeIdKeyType($entity_type->reveal());
$this->assertNull($type);
}
/**
* @covers ::getCanonicalRoute
* @dataProvider providerTestGetCanonicalRoute
* @param \Prophecy\Prophecy\ObjectProphecy $base_entity_type
* @return \Prophecy\Prophecy\ObjectProphecy
*/
public function testGetCanonicalRoute($entity_type_prophecy, $expected, $field_storage_definition = NULL) {
$entity_manager = $this->prophesize(EntityManagerInterface::class);
$route_provider = new TestDefaultHtmlRouteProvider($entity_manager->reveal());
$entity_type = $entity_type_prophecy->reveal();
if ($field_storage_definition) {
$entity_manager->getFieldStorageDefinitions($entity_type->id())
->willReturn([$entity_type->getKey('id') => $field_storage_definition]);
protected function getEntityType(ObjectProphecy $base_entity_type = NULL) {
$entity_type = $this->prophesize(EntityTypeInterface::class);
if ($base_entity_type) {
foreach ($base_entity_type->getMethodProphecies() as $method => $prophecies) {
foreach ($prophecies as $prophecy) {
$entity_type->addMethodProphecy(clone $prophecy);
}
}
}
$route = $route_provider->getCanonicalRoute($entity_type);
$this->assertEquals($expected, $route);
}
public function providerTestGetCanonicalRoute() {
$data = [];
$entity_type1 = $this->prophesize(EntityTypeInterface::class);
$entity_type1->hasLinkTemplate('canonical')->willReturn(FALSE);
$data['no_canonical_link_template'] = [$entity_type1, NULL];
$entity_type2 = $this->prophesize(EntityTypeInterface::class);
$entity_type2->hasLinkTemplate('canonical')->willReturn(TRUE);
$entity_type2->hasViewBuilderClass()->willReturn(FALSE);
$data['no_view_builder'] = [$entity_type2, NULL];
$entity_type3 = $this->prophesize(EntityTypeInterface::class);
$entity_type3->hasLinkTemplate('canonical')->willReturn(TRUE);
$entity_type3->hasViewBuilderClass()->willReturn(TRUE);
$entity_type3->id()->willReturn('the_entity_type_id');
$entity_type3->getLinkTemplate('canonical')->willReturn('/the/canonical/link/template');
$entity_type3->isSubclassOf(FieldableEntityInterface::class)->willReturn(FALSE);
$route3 = (new Route('/the/canonical/link/template'))
->setDefaults([
'_entity_view' => 'the_entity_type_id.full',
'_title_callback' => '\Drupal\Core\Entity\Controller\EntityController::title',
])
->setRequirements([
'_entity_access' => 'the_entity_type_id.view',
])
->setOptions([
'parameters' => [
'the_entity_type_id' => [
'type' => 'entity:the_entity_type_id',
],
],
]);
$data['id_key_type_null'] = [$entity_type3, $route3];
$entity_type4 = $this->prophesize(EntityTypeInterface::class);
$entity_type4->hasLinkTemplate('canonical')->willReturn(TRUE);
$entity_type4->hasViewBuilderClass()->willReturn(TRUE);
$entity_type4->id()->willReturn('the_entity_type_id');
$entity_type4->getLinkTemplate('canonical')->willReturn('/the/canonical/link/template');
$entity_type4->isSubclassOf(FieldableEntityInterface::class)->willReturn(TRUE);
$entity_type4->getKey('id')->willReturn('id');
$route4 = (new Route('/the/canonical/link/template'))
->setDefaults([
'_entity_view' => 'the_entity_type_id.full',
'_title_callback' => '\Drupal\Core\Entity\Controller\EntityController::title',
])
->setRequirements([
'_entity_access' => 'the_entity_type_id.view',
'the_entity_type_id' => '\d+',
])
->setOptions([
'parameters' => [
'the_entity_type_id' => [
'type' => 'entity:the_entity_type_id',
],
],
]);
$field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
$field_storage_definition->getType()->willReturn('integer');
$data['id_key_type_integer'] = [$entity_type4, $route4, $field_storage_definition];
return $data;
return $entity_type;
}
}
@ -148,6 +260,9 @@ class TestDefaultHtmlRouteProvider extends DefaultHtmlRouteProvider {
public function getEntityTypeIdKeyType(EntityTypeInterface $entity_type) {
return parent::getEntityTypeIdKeyType($entity_type);
}
public function getAddFormRoute(EntityTypeInterface $entity_type) {
return parent::getAddFormRoute($entity_type);
}
public function getCanonicalRoute(EntityTypeInterface $entity_type) {
return parent::getCanonicalRoute($entity_type);
}