diff --git a/core/lib/Drupal/Core/Entity/Controller/EntityController.php b/core/lib/Drupal/Core/Entity/Controller/EntityController.php index f1df4dc..7276159 100644 --- a/core/lib/Drupal/Core/Entity/Controller/EntityController.php +++ b/core/lib/Drupal/Core/Entity/Controller/EntityController.php @@ -7,15 +7,16 @@ 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\Routing\UrlGeneratorInterface; use Drupal\Core\Routing\UrlGeneratorTrait; -use Drupal\Core\Entity\EntityInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\TranslationInterface; @@ -118,40 +119,48 @@ public static function create(ContainerInterface $container) { */ public function addPage($entity_type_id) { $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); - $bundle_type = $entity_type->getBundleEntityType(); - $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_type); + $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id); $bundle_key = $entity_type->getKey('bundle'); - $form_route_name = 'entity.' . $entity_type_id . '.add_form'; + $bundle_entity_type_id = $entity_type->getBundleEntityType(); $build = [ '#theme' => 'entity_add_list', - '#cache' => [ - 'tags' => $bundle_entity_type->getListCacheTags(), - ], - '#bundle_type' => $bundle_type, ]; - $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id); - // Filter out the bundles the user doesn't have access to. - $access_control_handler = $this->entityTypeManager->getAccessControlHandler($bundle_type); - foreach ($bundles as $bundle_name => $bundle_info) { - $access = $access_control_handler->createAccess($bundle_name, NULL, [], TRUE); - if (!$access->isAllowed()) { - unset($bundles[$bundle_name]); + if ($bundle_entity_type_id) { + $bundle_argument = $bundle_entity_type_id; + $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id); + $build['#cache']['tags'] = $bundle_entity_type->getListCacheTags(); + $build['#bundle_entity_type'] = $bundle_entity_type_id;; + + // 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); } - $this->renderer->addCacheableDependency($build, $access); + // Add descriptions from the bundle entities. + $bundles = $this->loadBundleDescriptions($bundles, $bundle_entity_type); + } + else { + $bundle_argument = $bundle_key; + $build['#cache']['tags'] = $entity_type->getListCacheTags(); } + + $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_key => $bundle_name]); + return $this->redirect($form_route_name, [$bundle_argument => $bundle_name]); } // Prepare the #bundles array for the template. - $bundles = $this->loadBundleDescriptions($bundles, $bundle_type); foreach ($bundles as $bundle_name => $bundle_info) { $build['#bundles'][$bundle_name] = [ 'label' => $bundle_info['label'], 'description' => $bundle_info['description'], - 'add_link' => Link::createFromRoute($bundle_info['label'], $form_route_name, [$bundle_key => $bundle_name]), + 'add_link' => Link::createFromRoute($bundle_info['label'], $form_route_name, [$bundle_argument => $bundle_name]), ]; } @@ -289,28 +298,24 @@ protected function doGetEntity(RouteMatchInterface $route_match, EntityInterface * * @param array $bundles * An array of bundle information. - * @param string $bundle_type + * @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, $bundle_type) { + protected function loadBundleDescriptions(array $bundles, EntityTypeInterface $bundle_entity_type) { // Ensure the presence of the description key. foreach ($bundles as $bundle_name => &$bundle_info) { $bundle_info['description'] = ''; } - // Only bundles provided by entity types have descriptions. - if (empty($bundle_type)) { - return $bundles; - } - $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_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 = $this->entityTypeManager->getStorage($bundle_type)->loadMultiple($bundle_names); + $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(); diff --git a/core/modules/system/src/Tests/Entity/EntityAddUITest.php b/core/modules/system/src/Tests/Entity/EntityAddUITest.php index 7718f3b..ce393b6 100644 --- a/core/modules/system/src/Tests/Entity/EntityAddUITest.php +++ b/core/modules/system/src/Tests/Entity/EntityAddUITest.php @@ -29,49 +29,50 @@ class EntityAddUITest extends WebTestBase { */ protected function setUp() { parent::setUp(); + $web_user = $this->drupalCreateUser([ "administer entity_test_with_bundle content", ]); $this->drupalLogin($web_user); } + /** + * Tests the add page for an entity type using bundle entities. + */ public function testAddPage() { $this->drupalGet('/entity_test_with_bundle/add'); - // As long we don't have any bundles yet, there is some automatic redirect. - $this->assertUrl('/entity_test_with_bundle/add/entity_test_with_bundle'); + // 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'); - $this->assertLink('Test label'); - $this->assertText('My test description'); + $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->assertUrl('/entity_test_with_bundle/add'); - $this->assertLink('Entity Test Bundle'); $this->assertLink('Test label'); $this->assertLink('Test2 label'); $this->assertText('My test description'); $this->assertText('My test2 description'); - $this->clickLink('Test label'); - $this->drupalGet('/entity_test_with_bundle/add/test'); + $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->name->value); + $this->assertEqual('test name', $entity->label()); } } diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 7f0a0f6..e26650c 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -20,6 +20,7 @@ use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\StackedRouteMatchInterface; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Link; use Drupal\Core\Menu\MenuTreeParameters; use Drupal\Core\Extension\ModuleHandler; use Drupal\Core\Url; @@ -220,7 +221,7 @@ function system_theme() { 'entity_add_list' => array( 'variables' => array( 'bundles' => array(), - 'bundle_type' => NULL, + 'bundle_entity_type' => NULL, ), 'template' => 'entity-add-list', ), @@ -330,15 +331,21 @@ function system_theme_suggestions_field(array $variables) { * * @param array $variables * An associative array containing: - * - bundle_type: The entity type of the bundles. * - bundles: An array of bundles with the label, description, add_link keys. + * - bundle_entity_type: The bundle entity type. NULL if bundles aren't + * provided by an entity type. */ function template_preprocess_entity_add_list(&$variables) { - $bundle_type = \Drupal::entityTypeManager()->getDefinition($variables['bundle_type']); - $variables += [ - 'create_bundle_url' => Url::fromRoute('entity.' . $bundle_type->id() . '.add_form')->toString(), - 'bundle_type_label' => $bundle_type->getLowercaseLabel(), - ]; + if (!empty($variables['bundle_entity_type']) && empty($variables['bundles'])) { + $bundle_entity_type = \Drupal::entityTypeManager()->getDefinition($variables['bundle_entity_type']); + $label = $bundle_entity_type->getLowercaseLabel(); + $link_text = t('Add a new @entity_type.', ['@entity_type' => $label]); + $link_route_name = 'entity.' . $bundle_entity_type->id() . '.add_form'; + $variables['add_bundle_message'] = t('There is no @entity_type yet. @add_link', [ + '@entity_type' => $label, + '@add_link' => Link::createFromRoute($link_text, $link_route_name)->toString(), + ]); + } foreach ($variables['bundles'] as $bundle_name => $bundle_info) { $variables['bundles'][$bundle_name]['description'] = [ diff --git a/core/modules/system/templates/entity-add-list.html.twig b/core/modules/system/templates/entity-add-list.html.twig index 55970ef..9205d51 100644 --- a/core/modules/system/templates/entity-add-list.html.twig +++ b/core/modules/system/templates/entity-add-list.html.twig @@ -4,11 +4,11 @@ * Default theme implementation to present a list of available bundles. * * Available variables: - * - create_bundle_url: The url to the bundle creation page. - * - bundle_type_label: The lowercase label of the bundle entity type. * - bundles: A list of bundles, each with the following properties: * - add_link: link to create an entity of this bundle. * - description: Bundle description. + * - 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() * @@ -22,10 +22,8 @@
- {% trans %} - Go to the {{ bundle_type_label }} creation page to add a new {{ bundle_type_label }}. - {% endtrans %} + {{ add_bundle_message }}
{% endif %} diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php index 72a0033..f9abd9b 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php @@ -11,7 +11,7 @@ use Drupal\Core\Entity\EntityDescriptionInterface; /** - * Defines the Node type configuration entity. + * Defines the Test entity bundle configuration entity. * * @ConfigEntityType( * id = "entity_test_bundle", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php index 0ee8bb7..572eefa 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php @@ -12,7 +12,7 @@ use Drupal\Core\Field\BaseFieldDefinition; /** - * Defines the test entity class. + * Defines the Test entity with bundle entity class. * * @ContentEntityType( * id = "entity_test_with_bundle", @@ -43,7 +43,7 @@ * links = { * "canonical" = "/entity_test_with_bundle/{entity_test_with_bundle}", * "add-page" = "/entity_test_with_bundle/add", - * "add-form" = "/entity_test_with_bundle/add/{type}", + * "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}", * }, diff --git a/core/themes/stable/templates/content-edit/entity-add-list.html.twig b/core/themes/stable/templates/content-edit/entity-add-list.html.twig new file mode 100644 index 0000000..9205d51 --- /dev/null +++ b/core/themes/stable/templates/content-edit/entity-add-list.html.twig @@ -0,0 +1,29 @@ +{# +/** + * @file + * Default theme implementation to present a list of available bundles. + * + * Available variables: + * - bundles: A list of bundles, each with the following properties: + * - add_link: link to create an entity of this bundle. + * - description: Bundle description. + * - 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 %} ++ {{ add_bundle_message }} +
+{% endif %}