Issue #2666792 by bojanz, dawehner, edysmp, heddn: Provide a route provider for add-page of entities
parent
3d4a798ad8
commit
076ebd3435
|
@ -7,22 +7,28 @@
|
|||
|
||||
namespace Drupal\Core\Entity\Controller;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Routing\UrlGeneratorInterface;
|
||||
use Drupal\Core\Routing\UrlGeneratorTrait;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides generic entity title callbacks for use in routing.
|
||||
* Provides the add-page and title callbacks for entities.
|
||||
*
|
||||
* It provides:
|
||||
* - An add title callback for entities without bundles.
|
||||
* - An add title callback for entities with bundles.
|
||||
* - The add-page callback.
|
||||
* - An add title callback for entity types.
|
||||
* - An add title callback for entity types with bundles.
|
||||
* - A view title callback.
|
||||
* - An edit title callback.
|
||||
* - A delete title callback.
|
||||
|
@ -30,6 +36,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
class EntityController implements ContainerInjectionInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
use UrlGeneratorTrait;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
|
@ -52,6 +59,13 @@ class EntityController implements ContainerInjectionInterface {
|
|||
*/
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityController.
|
||||
*
|
||||
|
@ -61,14 +75,20 @@ class EntityController implements ContainerInjectionInterface {
|
|||
* The entity type bundle info.
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation.
|
||||
* @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
|
||||
* The url generator.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityRepositoryInterface $entity_repository, TranslationInterface $string_translation) {
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityRepositoryInterface $entity_repository, RendererInterface $renderer, TranslationInterface $string_translation, UrlGeneratorInterface $url_generator) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityTypeBundleInfo = $entity_type_bundle_info;
|
||||
$this->entityRepository = $entity_repository;
|
||||
$this->renderer = $renderer;
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->urlGenerator = $url_generator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,12 +99,83 @@ class EntityController implements ContainerInjectionInterface {
|
|||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_type.bundle.info'),
|
||||
$container->get('entity.repository'),
|
||||
$container->get('string_translation')
|
||||
$container->get('renderer'),
|
||||
$container->get('string_translation'),
|
||||
$container->get('url_generator')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a generic add title callback for entities without bundles.
|
||||
* Displays add links for the available bundles.
|
||||
*
|
||||
* Redirects to the add form if there's only one bundle available.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse|array
|
||||
* If there's only one available bundle, a redirect response.
|
||||
* Otherwise, a render array with the add links for each bundle.
|
||||
*/
|
||||
public function addPage($entity_type_id) {
|
||||
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
|
||||
$bundle_key = $entity_type->getKey('bundle');
|
||||
$bundle_entity_type_id = $entity_type->getBundleEntityType();
|
||||
$build = [
|
||||
'#theme' => 'entity_add_list',
|
||||
'#bundles' => [],
|
||||
];
|
||||
if ($bundle_entity_type_id) {
|
||||
$bundle_argument = $bundle_entity_type_id;
|
||||
$bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
|
||||
$bundle_entity_type_label = $bundle_entity_type->getLowercaseLabel();
|
||||
$build['#cache']['tags'] = $bundle_entity_type->getListCacheTags();
|
||||
|
||||
// Build the message shown when there are no bundles.
|
||||
$link_text = $this->t('Add a new @entity_type.', ['@entity_type' => $bundle_entity_type_label]);
|
||||
$link_route_name = 'entity.' . $bundle_entity_type->id() . '.add_form';
|
||||
$build['#add_bundle_message'] = $this->t('There is no @entity_type yet. @add_link', [
|
||||
'@entity_type' => $bundle_entity_type_label,
|
||||
'@add_link' => Link::createFromRoute($link_text, $link_route_name)->toString(),
|
||||
]);
|
||||
// Filter out the bundles the user doesn't have access to.
|
||||
$access_control_handler = $this->entityTypeManager->getAccessControlHandler($bundle_entity_type_id);
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
$access = $access_control_handler->createAccess($bundle_name, NULL, [], TRUE);
|
||||
if (!$access->isAllowed()) {
|
||||
unset($bundles[$bundle_name]);
|
||||
}
|
||||
$this->renderer->addCacheableDependency($build, $access);
|
||||
}
|
||||
// Add descriptions from the bundle entities.
|
||||
$bundles = $this->loadBundleDescriptions($bundles, $bundle_entity_type);
|
||||
}
|
||||
else {
|
||||
$bundle_argument = $bundle_key;
|
||||
}
|
||||
|
||||
$form_route_name = 'entity.' . $entity_type_id . '.add_form';
|
||||
// Redirect if there's only one bundle available.
|
||||
if (count($bundles) == 1) {
|
||||
$bundle_names = array_keys($bundles);
|
||||
$bundle_name = reset($bundle_names);
|
||||
return $this->redirect($form_route_name, [$bundle_argument => $bundle_name]);
|
||||
}
|
||||
// Prepare the #bundles array for the template.
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
$build['#bundles'][$bundle_name] = [
|
||||
'label' => $bundle_info['label'],
|
||||
'description' => isset($bundle_info['description']) ? $bundle_info['description'] : '',
|
||||
'add_link' => Link::createFromRoute($bundle_info['label'], $form_route_name, [$bundle_argument => $bundle_name]),
|
||||
];
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a generic add title callback for an entity type.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID.
|
||||
|
@ -209,4 +300,32 @@ class EntityController implements ContainerInjectionInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the bundle information with descriptions, if known.
|
||||
*
|
||||
* @param array $bundles
|
||||
* An array of bundle information.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $bundle_entity_type
|
||||
* The ID of the bundle entity type.
|
||||
*
|
||||
* @return array
|
||||
* The expanded array of bundle information.
|
||||
*/
|
||||
protected function loadBundleDescriptions(array $bundles, EntityTypeInterface $bundle_entity_type) {
|
||||
if (!$bundle_entity_type->isSubclassOf('\Drupal\Core\Entity\EntityDescriptionInterface')) {
|
||||
return $bundles;
|
||||
}
|
||||
$bundle_names = array_keys($bundles);
|
||||
$storage = $this->entityTypeManager->getStorage($bundle_entity_type->id());
|
||||
/** @var \Drupal\Core\Entity\EntityDescriptionInterface[] $bundle_entities */
|
||||
$bundle_entities = $storage->loadMultiple($bundle_names);
|
||||
foreach ($bundles as $bundle_name => &$bundle_info) {
|
||||
if (isset($bundle_entities[$bundle_name])) {
|
||||
$bundle_info['description'] = $bundle_entities[$bundle_name]->getDescription();
|
||||
}
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\EntityDescriptionInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity;
|
||||
|
||||
/**
|
||||
* Defines the interface for entities that have a description.
|
||||
*/
|
||||
interface EntityDescriptionInterface {
|
||||
|
||||
/**
|
||||
* Gets the entity description.
|
||||
*
|
||||
* @return string
|
||||
* The entity description.
|
||||
*/
|
||||
public function getDescription();
|
||||
|
||||
/**
|
||||
* Sets the entity description.
|
||||
*
|
||||
* @param string $description
|
||||
* The entity description.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDescription($description);
|
||||
|
||||
}
|
|
@ -10,9 +10,9 @@ namespace Drupal\Core\Entity\Routing;
|
|||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
||||
/**
|
||||
* Provides HTML routes for entities with administrative edit/delete pages.
|
||||
* Provides HTML routes for entities with administrative add/edit/delete pages.
|
||||
*
|
||||
* Use this class if the edit and delete form routes should use the
|
||||
* Use this class if the add/edit/delete form routes should use the
|
||||
* administrative theme.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider.
|
||||
|
@ -21,6 +21,16 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
|||
*/
|
||||
class AdminHtmlRouteProvider extends DefaultHtmlRouteProvider {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAddPageRoute(EntityTypeInterface $entity_type) {
|
||||
if ($route = parent::getAddPageRoute($entity_type)) {
|
||||
$route->setOption('_admin_route', TRUE);
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,8 @@ use Symfony\Component\Routing\RouteCollection;
|
|||
* This class provides the following routes for entities, with title and access
|
||||
* callbacks:
|
||||
* - canonical
|
||||
* - add-page
|
||||
* - add-form
|
||||
* - edit-form
|
||||
* - delete-form
|
||||
*
|
||||
|
@ -78,8 +80,12 @@ class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHa
|
|||
|
||||
$entity_type_id = $entity_type->id();
|
||||
|
||||
if ($add_route = $this->getAddFormRoute($entity_type)) {
|
||||
$collection->add("entity.{$entity_type_id}.add_form", $add_route);
|
||||
if ($add_page_route = $this->getAddPageRoute($entity_type)) {
|
||||
$collection->add("entity.{$entity_type_id}.add_page", $add_page_route);
|
||||
}
|
||||
|
||||
if ($add_form_route = $this->getAddFormRoute($entity_type)) {
|
||||
$collection->add("entity.{$entity_type_id}.add_form", $add_form_route);
|
||||
}
|
||||
|
||||
if ($canonical_route = $this->getCanonicalRoute($entity_type)) {
|
||||
|
@ -97,6 +103,29 @@ class DefaultHtmlRouteProvider implements EntityRouteProviderInterface, EntityHa
|
|||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the add page route.
|
||||
*
|
||||
* Built only for entity types that have bundles.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return \Symfony\Component\Routing\Route|null
|
||||
* The generated route, if available.
|
||||
*/
|
||||
protected function getAddPageRoute(EntityTypeInterface $entity_type) {
|
||||
if ($entity_type->hasLinkTemplate('add-page') && $entity_type->getKey('bundle')) {
|
||||
$route = new Route($entity_type->getLinkTemplate('add-page'));
|
||||
$route->setDefault('_controller', EntityController::class . '::addPage');
|
||||
$route->setDefault('_title_callback', EntityController::class . '::addTitle');
|
||||
$route->setDefault('entity_type_id', $entity_type->id());
|
||||
$route->setRequirement('_entity_create_access', $entity_type->id());
|
||||
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the add-form route.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Tests\Entity\EntityAddUITest.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Tests\Entity;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestBundle;
|
||||
use Drupal\entity_test\Entity\EntityTestMul;
|
||||
use Drupal\entity_test\Entity\EntityTestWithBundle;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Tests the /add and /add/{type} controllers.
|
||||
*
|
||||
* @group entity
|
||||
*/
|
||||
class EntityAddUITest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['entity_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$web_user = $this->drupalCreateUser([
|
||||
"administer entity_test_with_bundle content",
|
||||
"administer entity_test content",
|
||||
]);
|
||||
$this->drupalLogin($web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the add page for an entity type using bundle entities.
|
||||
*/
|
||||
public function testAddPageWithBundleEntities() {
|
||||
$this->drupalGet('/entity_test_with_bundle/add');
|
||||
// No bundles exist, the add bundle message should be present.
|
||||
$this->assertText('There is no test entity bundle yet.');
|
||||
$this->assertLink('Add a new test entity bundle.');
|
||||
|
||||
// One bundle exists, confirm redirection to the add-form.
|
||||
EntityTestBundle::create([
|
||||
'id' => 'test',
|
||||
'label' => 'Test label',
|
||||
'description' => 'My test description',
|
||||
])->save();
|
||||
$this->drupalGet('/entity_test_with_bundle/add');
|
||||
$this->assertUrl('/entity_test_with_bundle/add/test');
|
||||
|
||||
// Two bundles exist, confirm both are shown.
|
||||
EntityTestBundle::create([
|
||||
'id' => 'test2',
|
||||
'label' => 'Test2 label',
|
||||
'description' => 'My test2 description',
|
||||
])->save();
|
||||
$this->drupalGet('/entity_test_with_bundle/add');
|
||||
|
||||
$this->assertLink('Test label');
|
||||
$this->assertLink('Test2 label');
|
||||
$this->assertText('My test description');
|
||||
$this->assertText('My test2 description');
|
||||
|
||||
$this->clickLink('Test2 label');
|
||||
$this->drupalGet('/entity_test_with_bundle/add/test2');
|
||||
|
||||
$this->drupalPostForm(NULL, ['name[0][value]' => 'test name'], t('Save'));
|
||||
$entity = EntityTestWithBundle::load(1);
|
||||
$this->assertEqual('test name', $entity->label());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the add page for an entity type not using bundle entities.
|
||||
*/
|
||||
public function testAddPageWithoutBundleEntities() {
|
||||
entity_test_create_bundle('test', 'Test label', 'entity_test_mul');
|
||||
// Delete the default bundle, so that we can rely on our own.
|
||||
entity_test_delete_bundle('entity_test_mul', 'entity_test_mul');
|
||||
|
||||
// One bundle exists, confirm redirection to the add-form.
|
||||
$this->drupalGet('/entity_test_mul/add');
|
||||
$this->assertUrl('/entity_test_mul/add/test');
|
||||
|
||||
// Two bundles exist, confirm both are shown.
|
||||
entity_test_create_bundle('test2', 'Test2 label', 'entity_test_mul');
|
||||
$this->drupalGet('/entity_test_mul/add');
|
||||
|
||||
$this->assertLink('Test label');
|
||||
$this->assertLink('Test2 label');
|
||||
|
||||
$this->clickLink('Test2 label');
|
||||
$this->drupalGet('/entity_test_mul/add/test2');
|
||||
|
||||
$this->drupalPostForm(NULL, ['name[0][value]' => 'test name'], t('Save'));
|
||||
$entity = EntityTestMul::load(1);
|
||||
$this->assertEqual('test name', $entity->label());
|
||||
}
|
||||
|
||||
}
|
|
@ -217,6 +217,13 @@ function system_theme() {
|
|||
'variables' => array('menu_items' => NULL),
|
||||
'file' => 'system.admin.inc',
|
||||
),
|
||||
'entity_add_list' => array(
|
||||
'variables' => array(
|
||||
'bundles' => array(),
|
||||
'add_bundle_message' => NULL,
|
||||
),
|
||||
'template' => 'entity-add-list',
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -316,6 +323,25 @@ function system_theme_suggestions_field(array $variables) {
|
|||
return $suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares variables for the list of available bundles.
|
||||
*
|
||||
* Default template: entity-add-list.html.twig.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - bundles: An array of bundles with the label, description, add_link keys.
|
||||
* - add_bundle_message: The message shown when there are no bundles. Only
|
||||
+ * available if the entity type uses bundle entities.
|
||||
*/
|
||||
function template_preprocess_entity_add_list(&$variables) {
|
||||
foreach ($variables['bundles'] as $bundle_name => $bundle_info) {
|
||||
$variables['bundles'][$bundle_name]['description'] = [
|
||||
'#markup' => $bundle_info['description'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup authorize Authorized operations
|
||||
* @{
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to present a list of available bundles.
|
||||
*
|
||||
* Available variables:
|
||||
* - bundles: A list of bundles, each with the following properties:
|
||||
* - label: Bundle label.
|
||||
* - description: Bundle description.
|
||||
* - add_link: Link to create an entity of this bundle.
|
||||
* - add_bundle_message: The message shown when there are no bundles. Only
|
||||
* available if the entity type uses bundle entities.
|
||||
*
|
||||
* @see template_preprocess_entity_add_list()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{% if bundles is not empty %}
|
||||
<dl>
|
||||
{% for bundle in bundles %}
|
||||
<dt>{{ bundle.add_link }}</dt>
|
||||
<dd>{{ bundle.description }}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% elseif add_bundle_message is not empty %}
|
||||
<p>
|
||||
{{ add_bundle_message }}
|
||||
</p>
|
||||
{% endif %}
|
|
@ -13,3 +13,17 @@ field.storage_settings.shape:
|
|||
foreign_key_name:
|
||||
type: string
|
||||
label: 'Foreign key name'
|
||||
|
||||
entity_test.entity_test_bundle.*:
|
||||
type: config_entity
|
||||
label: 'Entity test bundle'
|
||||
mapping:
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
id:
|
||||
type: string
|
||||
label: 'Machine-readable name'
|
||||
description:
|
||||
type: text
|
||||
label: 'Description'
|
||||
|
|
|
@ -196,7 +196,7 @@ function entity_test_entity_bundle_info() {
|
|||
$bundles = array();
|
||||
$entity_types = \Drupal::entityManager()->getDefinitions();
|
||||
foreach ($entity_types as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->getProvider() == 'entity_test') {
|
||||
if ($entity_type->getProvider() == 'entity_test' && $entity_type_id != 'entity_test_with_bundle') {
|
||||
$bundles[$entity_type_id] = \Drupal::state()->get($entity_type_id . '.bundles') ?: array($entity_type_id => array('label' => 'Entity Test Bundle'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,3 +7,6 @@ view test entity translations:
|
|||
title: 'View translations of test entities'
|
||||
view test entity field:
|
||||
title: 'View test entity field'
|
||||
administer entity_test_with_bundle content:
|
||||
title: 'administer entity_test_with_bundle content'
|
||||
description: 'administer entity_test_with_bundle content'
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\entity_test\Entity\EntityTestBundle.
|
||||
*/
|
||||
|
||||
namespace Drupal\entity_test\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
|
||||
use Drupal\Core\Entity\EntityDescriptionInterface;
|
||||
|
||||
/**
|
||||
* Defines the Test entity bundle configuration entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "entity_test_bundle",
|
||||
* label = @Translation("Test entity bundle"),
|
||||
* handlers = {
|
||||
* "access" = "\Drupal\Core\Entity\EntityAccessControlHandler",
|
||||
* "form" = {
|
||||
* "default" = "\Drupal\Core\Entity\BundleEntityFormBase",
|
||||
* },
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
|
||||
* },
|
||||
* },
|
||||
* admin_permission = "administer entity_test_with_bundle content",
|
||||
* config_prefix = "entity_test_bundle",
|
||||
* bundle_of = "entity_test_with_bundle",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "description",
|
||||
* },
|
||||
* links = {
|
||||
* "add-form" = "/entity_test_bundle/add",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class EntityTestBundle extends ConfigEntityBundleBase implements EntityDescriptionInterface {
|
||||
|
||||
/**
|
||||
* The machine name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The human-readable name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDescription($description) {
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,8 @@ namespace Drupal\entity_test\Entity;
|
|||
* "langcode" = "langcode",
|
||||
* },
|
||||
* links = {
|
||||
* "add-form" = "/entity_test_mul/add",
|
||||
* "add-page" = "/entity_test_mul/add",
|
||||
* "add-form" = "/entity_test_mul/add/{type}",
|
||||
* "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}",
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\entity_test\Entity\EntityTestWithBundle.
|
||||
*/
|
||||
|
||||
namespace Drupal\entity_test\Entity;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
|
||||
/**
|
||||
* Defines the Test entity with bundle entity class.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "entity_test_with_bundle",
|
||||
* label = @Translation("Test entity with bundle"),
|
||||
* handlers = {
|
||||
* "list_builder" = "Drupal\entity_test\EntityTestListBuilder",
|
||||
* "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
|
||||
* "access" = "\Drupal\Core\Entity\EntityAccessControlHandler",
|
||||
* "form" = {
|
||||
* "default" = "\Drupal\Core\Entity\ContentEntityForm",
|
||||
* "delete" = "\Drupal\Core\Entity\EntityDeleteForm"
|
||||
* },
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
|
||||
* },
|
||||
* },
|
||||
* base_table = "entity_test_with_bundle",
|
||||
* admin_permission = "administer entity_test_with_bundle content",
|
||||
* persistent_cache = FALSE,
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "uuid" = "uuid",
|
||||
* "bundle" = "type",
|
||||
* "label" = "name",
|
||||
* "langcode" = "langcode",
|
||||
* },
|
||||
* bundle_entity_type = "entity_test_bundle",
|
||||
* links = {
|
||||
* "canonical" = "/entity_test_with_bundle/{entity_test_with_bundle}",
|
||||
* "add-page" = "/entity_test_with_bundle/add",
|
||||
* "add-form" = "/entity_test_with_bundle/add/{entity_test_bundle}",
|
||||
* "edit-form" = "/entity_test_with_bundle/manage/{entity_test_with_bundle}/edit",
|
||||
* "delete-form" = "/entity_test_with_bundle/delete/entity_test_with_bundle/{entity_test_with_bundle}",
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class EntityTestWithBundle extends ContentEntityBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
$fields['name'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Name'))
|
||||
->setDescription(t('The name of the test entity.'))
|
||||
->setTranslatable(TRUE)
|
||||
->setSetting('max_length', 32)
|
||||
->setDisplayOptions('view', [
|
||||
'label' => 'hidden',
|
||||
'type' => 'string',
|
||||
'weight' => -5,
|
||||
])
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'string_textfield',
|
||||
'weight' => -5,
|
||||
]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
|
@ -25,11 +25,6 @@ class EntityTestRoutes {
|
|||
|
||||
$routes = array();
|
||||
foreach ($types as $entity_type_id) {
|
||||
$routes["entity.$entity_type_id.add_form"] = new Route(
|
||||
"$entity_type_id/add",
|
||||
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'),
|
||||
|
|
|
@ -58,6 +58,44 @@ class DefaultHtmlRouteProviderTest extends UnitTestCase {
|
|||
$this->routeProvider = new TestDefaultHtmlRouteProvider($this->entityTypeManager->reveal(), $this->entityFieldManager->reveal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAddPageRoute
|
||||
* @dataProvider providerTestGetAddPageRoute
|
||||
*/
|
||||
public function testGetAddPageRoute(Route $expected = NULL, EntityTypeInterface $entity_type) {
|
||||
$route = $this->routeProvider->getAddPageRoute($entity_type);
|
||||
$this->assertEquals($expected, $route);
|
||||
}
|
||||
|
||||
public function providerTestGetAddPageRoute() {
|
||||
$data = [];
|
||||
|
||||
$entity_type1 = $this->getEntityType();
|
||||
$entity_type1->hasLinkTemplate('add-page')->willReturn(FALSE);
|
||||
$data['no_add_page_link_template'] = [NULL, $entity_type1->reveal()];
|
||||
|
||||
$entity_type2 = $this->getEntityType();
|
||||
$entity_type2->hasLinkTemplate('add-page')->willReturn(TRUE);
|
||||
$entity_type2->getKey('bundle')->willReturn(NULL);
|
||||
$data['no_bundle'] = [NULL, $entity_type2->reveal()];
|
||||
|
||||
$entity_type3 = $this->getEntityType();
|
||||
$entity_type3->hasLinkTemplate('add-page')->willReturn(TRUE);
|
||||
$entity_type3->getLinkTemplate('add-page')->willReturn('/the/add/page/link/template');
|
||||
$entity_type3->id()->willReturn('the_entity_type_id');
|
||||
$entity_type3->getKey('bundle')->willReturn('type');
|
||||
$route = new Route('/the/add/page/link/template');
|
||||
$route->setDefaults([
|
||||
'_controller' => 'Drupal\Core\Entity\Controller\EntityController::addPage',
|
||||
'_title_callback' => 'Drupal\Core\Entity\Controller\EntityController::addTitle',
|
||||
'entity_type_id' => 'the_entity_type_id',
|
||||
]);
|
||||
$route->setRequirement('_entity_create_access', 'the_entity_type_id');
|
||||
$data['add_page'] = [clone $route, $entity_type3->reveal()];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAddFormRoute
|
||||
* @dataProvider providerTestGetAddFormRoute
|
||||
|
@ -260,6 +298,9 @@ class TestDefaultHtmlRouteProvider extends DefaultHtmlRouteProvider {
|
|||
public function getEntityTypeIdKeyType(EntityTypeInterface $entity_type) {
|
||||
return parent::getEntityTypeIdKeyType($entity_type);
|
||||
}
|
||||
public function getAddPageRoute(EntityTypeInterface $entity_type) {
|
||||
return parent::getAddPageRoute($entity_type);
|
||||
}
|
||||
public function getAddFormRoute(EntityTypeInterface $entity_type) {
|
||||
return parent::getAddFormRoute($entity_type);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Theme override to to present a list of available bundles.
|
||||
*
|
||||
* Available variables:
|
||||
* - bundles: A list of bundles, each with the following properties:
|
||||
* - label: Bundle label.
|
||||
* - description: Bundle description.
|
||||
* - add_link: Link to create an entity of this bundle.
|
||||
* - add_bundle_message: The message shown when there are no bundles. Only
|
||||
* available if the entity type uses bundle entities.
|
||||
*
|
||||
* @see template_preprocess_entity_add_list()
|
||||
*/
|
||||
#}
|
||||
{% if bundles is not empty %}
|
||||
<ul class="admin-list">
|
||||
{% for bundle in bundles %}
|
||||
<li class="clearfix"><a href="{{ bundle.add_link.url }}"><span class="label">{{ bundle.label }}</span><div class="description">{{ bundle.description }}</div></a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% elseif add_bundle_message is not empty %}
|
||||
<p>
|
||||
{{ add_bundle_message }}
|
||||
</p>
|
||||
{% endif %}
|
|
@ -0,0 +1,30 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to present a list of available bundles.
|
||||
*
|
||||
* Available variables:
|
||||
* - bundles: A list of bundles, each with the following properties:
|
||||
* - label: Bundle label.
|
||||
* - description: Bundle description.
|
||||
* - add_link: Link to create an entity of this bundle.
|
||||
* - add_bundle_message: The message shown when there are no bundles. Only
|
||||
* available if the entity type uses bundle entities.
|
||||
*
|
||||
* @see template_preprocess_entity_add_list()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{% if bundles is not empty %}
|
||||
<dl>
|
||||
{% for bundle in bundles %}
|
||||
<dt>{{ bundle.add_link }}</dt>
|
||||
<dd>{{ bundle.description }}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% elseif add_bundle_message is not empty %}
|
||||
<p>
|
||||
{{ add_bundle_message }}
|
||||
</p>
|
||||
{% endif %}
|
Loading…
Reference in New Issue