diff --git a/.travis.yml b/.travis.yml index 7c84d51e471c238382d76e9e17367042d096af28..0a4764e3327c7bed6585eda94acdc4e509b09aef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,10 +40,20 @@ before_script: # Download Drupal 8 core. - travis_retry git clone --branch 8.0.x --depth 1 http://git.drupal.org/project/drupal.git - cd drupal + # Add a patch for BrowserTestBase + - curl -o 2636228-6.patch https://www.drupal.org/files/issues/2636228-6.patch + - patch -p1 < 2636228-6.patch # Reference entity in build site. - ln -s $TESTDIR modules/entity + # Start a web server on port 8888, run in the background; wait for + # initialization. + - nohup php -S localhost:8888 > /dev/null 2>&1 & + + # Export web server URL for browser tests. + - export SIMPLETEST_BASE_URL=http://localhost:8888 + script: # Run the PHPUnit tests which also include the kernel tests. - - ./vendor/phpunit/phpunit/phpunit -c ./core/phpunit.xml.dist ./modules/entity + - ./vendor/phpunit/phpunit/phpunit -c ./core/phpunit.xml.dist --verbose ./modules/entity diff --git a/entity.module b/entity.module new file mode 100644 index 0000000000000000000000000000000000000000..f1845403d133d6e80fa2581a5d4153f70063eb4b --- /dev/null +++ b/entity.module @@ -0,0 +1,47 @@ +<?php + +/** + * @file + * Provides expanded entity APIs. + */ + +use Drupal\Core\Url; + +/** + * Implements hook_theme(). + */ +function entity_theme() { + return [ + 'entity_add_list' => [ + 'variables' => [ + 'bundles' => [], + 'bundle_type' => NULL, + ], + 'template' => 'entity-add-list', + ], + ]; +} + +/** + * Prepares variables for the list of available bundles. + * + * Default template: entity-add-list.html.twig. + * + * @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. + */ +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(), + ]; + + foreach ($variables['bundles'] as $bundle_name => $bundle_info) { + $variables['bundles'][$bundle_name]['description'] = [ + '#markup' => $bundle_info['description'], + ]; + } +} diff --git a/src/Controller/EntityCreateController.php b/src/Controller/EntityCreateController.php new file mode 100644 index 0000000000000000000000000000000000000000..bece86b969131b8eb7b1329fd686868bacf2f5cc --- /dev/null +++ b/src/Controller/EntityCreateController.php @@ -0,0 +1,220 @@ +<?php + +/** + * @file + * Contains \Drupal\entity\Controller\EntityCreateController. + */ + +namespace Drupal\entity\Controller; + +use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Core\Render\RendererInterface; +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Link; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + +/** + * A generic controller for creating entities. + */ +class EntityCreateController extends ControllerBase { + + /** + * The entity type bundle info. + * + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface + */ + protected $entityTypeBundleInfo; + + /** + * The renderer service. + * + * @var \Drupal\Core\Render\RendererInterface + */ + protected $renderer; + + /** + * Constructs a new EntityCreateController object. + * + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info + * The entity type bundle info. + * @param \Drupal\Core\Render\RendererInterface $renderer + * The renderer. + */ + public function __construct(EntityTypeBundleInfoInterface $entity_type_bundle_info, RendererInterface $renderer) { + $this->entityTypeBundleInfo = $entity_type_bundle_info; + $this->renderer = $renderer; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.bundle.info'), + $container->get('renderer') + ); + } + + /** + * 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. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * + * @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, Request $request) { + $entity_type = $this->entityTypeManager()->getDefinition($entity_type_id); + $bundle_type = $entity_type->getBundleEntityType(); + $bundle_key = $entity_type->getKey('bundle'); + $form_route_name = 'entity.' . $entity_type_id . '.add_form'; + $build = [ + '#theme' => 'entity_add_list', + '#cache' => [ + 'tags' => $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]); + } + $this->renderer->addCacheableDependency($build, $access); + } + // 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]); + } + // 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]), + ]; + } + + return $build; + } + + /** + * The title callback for the add page. + * + * @param string $entity_type_id + * The entity type ID. + * + * @return string + * The page title. + */ + public function addPageTitle($entity_type_id) { + $entity_type = $this->entityTypeManager()->getDefinition($entity_type_id); + return $this->t('Add @entity-type', ['@entity-type' => $entity_type->getLowercaseLabel()]); + } + + /** + * Provides the add form for an entity. + * + * @param string $entity_type_id + * The entity type ID. + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. + * + * @return array + * The add form. + */ + public function addForm($entity_type_id, RouteMatchInterface $route_match) { + $entity_type = $this->entityTypeManager()->getDefinition($entity_type_id); + $values = []; + // Entities of this type have bundles, one was provided in the url. + if ($bundle_key = $entity_type->getKey('bundle')) { + $bundle_name = $route_match->getRawParameter($bundle_key); + $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id); + if (empty($bundle_name) || !isset($bundles[$bundle_name])) { + // The bundle parameter is invalid. + throw new NotFoundHttpException(); + } + $values[$bundle_key] = $bundle_name; + } + $entity = $this->entityTypeManager()->getStorage($entity_type_id)->create($values); + + return $this->entityFormBuilder()->getForm($entity, 'add'); + } + + /** + * The title callback for the add form. + * + * @param string $entity_type_id + * The entity type ID. + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. + * + * @return string + * The page title. + */ + public function addFormTitle($entity_type_id, RouteMatchInterface $route_match) { + $entity_type = $this->entityTypeManager()->getDefinition($entity_type_id); + $bundle_key = $entity_type->getKey('bundle'); + $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id); + if ($bundle_key && count($bundles) > 1) { + $bundle_name = $route_match->getRawParameter($bundle_key); + $title = $this->t('Add @bundle', ['@bundle' => $bundles[$bundle_name]['label']]); + } + else { + $title = $this->t('Add @entity-type', ['@entity-type' => $entity_type->getLowercaseLabel()]); + } + + return $title; + } + + /** + * Expands the bundle information with descriptions, if known. + * + * @param array $bundles + * An array of bundle information. + * @param string $bundle_type + * The id of the bundle entity type. + * + * @return array + * The expanded array of bundle information. + */ + protected function loadBundleDescriptions(array $bundles, $bundle_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\entity\Entity\EntityDescriptionInterface')) { + return $bundles; + } + $bundle_names = array_keys($bundles); + $bundle_entities = $this->entityTypeManager->getStorage($bundle_type)->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; + } + +} diff --git a/src/Entity/EntityDescriptionInterface.php b/src/Entity/EntityDescriptionInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..eb770e1d8d9c8f6ae1f9622ea6dd2c25c7d0ca1e --- /dev/null +++ b/src/Entity/EntityDescriptionInterface.php @@ -0,0 +1,33 @@ +<?php + +/** + * @file + * Contains \Drupal\entity\Entity\EntityDescriptionInterface. + */ + +namespace Drupal\entity\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); + +} diff --git a/src/Routing/AdminCreateHtmlRouteProvider.php b/src/Routing/AdminCreateHtmlRouteProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..0161715f55278fdbfcf0a03a3ac84e869f761bc2 --- /dev/null +++ b/src/Routing/AdminCreateHtmlRouteProvider.php @@ -0,0 +1,37 @@ +<?php + +/** + * @file + * Contains \Drupal\entity\Routing\AdminCreateHtmlRouteProvider. + */ + +namespace Drupal\entity\Routing; + +use Drupal\Core\Entity\EntityTypeInterface; + +/** + * Provides HTML routes for creating entities using the administrative theme. + */ +class AdminCreateHtmlRouteProvider extends CreateHtmlRouteProvider { + + /** + * {@inheritdoc} + */ + protected function addPageRoute(EntityTypeInterface $entity_type) { + if ($route = parent::addPageRoute($entity_type)) { + $route->setOption('_admin_route', TRUE); + return $route; + } + } + + /** + * {@inheritdoc} + */ + protected function addFormRoute(EntityTypeInterface $entity_type) { + if ($route = parent::addFormRoute($entity_type)) { + $route->setOption('_admin_route', TRUE); + return $route; + } + } + +} diff --git a/src/Routing/CreateHtmlRouteProvider.php b/src/Routing/CreateHtmlRouteProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..221b598e906d7403d4a814d0308f06df87132169 --- /dev/null +++ b/src/Routing/CreateHtmlRouteProvider.php @@ -0,0 +1,85 @@ +<?php + +/** + * @file + * Contains \Drupal\entity\Routing\CreateHtmlRouteProvider. + */ + +namespace Drupal\entity\Routing; + +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\Routing\EntityRouteProviderInterface; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; + +/** + * Provides HTML routes for creating entities. + * + * This class provides the following routes for entities, with title callbacks: + * - add-page + * - add-form + * + * @see \Drupal\entity\Routing\AdminCreateHtmlRouteProvider. + */ +class CreateHtmlRouteProvider implements EntityRouteProviderInterface { + + /** + * {@inheritdoc} + */ + public function getRoutes(EntityTypeInterface $entity_type) { + $routes = new RouteCollection(); + if ($route = $this->addPageRoute($entity_type)) { + $routes->add('entity.' . $entity_type->id() . '.add_page', $route); + } + if ($route = $this->addFormRoute($entity_type)) { + $routes->add('entity.' . $entity_type->id() . '.add_form', $route); + } + + return $routes; + } + + /** + * Returns 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 addPageRoute(EntityTypeInterface $entity_type) { + if ($entity_type->hasLinkTemplate('add-page') && $entity_type->getKey('bundle')) { + $route = new Route($entity_type->getLinkTemplate('add-page')); + $route->setDefault('_controller', '\Drupal\entity\Controller\EntityCreateController::addPage'); + $route->setDefault('_title_callback', '\Drupal\entity\Controller\EntityCreateController::addPageTitle'); + $route->setDefault('entity_type_id', $entity_type->id()); + $route->setRequirement('_entity_create_access', $entity_type->id()); + + return $route; + } + } + + /** + * Returns 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 addFormRoute(EntityTypeInterface $entity_type) { + if ($entity_type->hasLinkTemplate('add-form')) { + $route = new Route($entity_type->getLinkTemplate('add-form')); + $route->setDefault('_controller', '\Drupal\entity\Controller\EntityCreateController::addForm'); + $route->setDefault('_title_callback', '\Drupal\entity\Controller\EntityCreateController::addFormTitle'); + $route->setDefault('entity_type_id', $entity_type->id()); + $route->setRequirement('_entity_create_access', $entity_type->id()); + + return $route; + } + } + +} diff --git a/templates/entity-add-list.html.twig b/templates/entity-add-list.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..55970efd08b32e55aa292407afe5ee8c392fc9e9 --- /dev/null +++ b/templates/entity-add-list.html.twig @@ -0,0 +1,31 @@ +{# +/** + * @file + * 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. + * + * @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> +{% else %} + <p> + {% trans %} + Go to the <a href="{{ create_bundle_url }}">{{ bundle_type_label }} creation page</a> to add a new {{ bundle_type_label }}. + {% endtrans %} + </p> +{% endif %} diff --git a/tests/Functional/CreateUITest.php b/tests/Functional/CreateUITest.php new file mode 100644 index 0000000000000000000000000000000000000000..dbf467ccf136c0430684a3137378a22793414f0d --- /dev/null +++ b/tests/Functional/CreateUITest.php @@ -0,0 +1,97 @@ +<?php + +/** + * @file + * Contains \Drupal\Tests\entity\Functional\CreateUITest. + */ + +namespace Drupal\Tests\entity\Functional; + +use Drupal\entity_module_test\Entity\EnhancedEntity; +use Drupal\entity_module_test\Entity\EnhancedEntityBundle; +use Drupal\simpletest\BrowserTestBase; + +/** + * Tests the entity creation UI provided by EntityCreateController. + * + * @group entity + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ +class CreateUITest extends BrowserTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = ['entity_module_test', 'user', 'entity']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + EnhancedEntityBundle::create([ + 'id' => 'first', + 'label' => 'First', + 'description' => 'The first bundle', + ])->save(); + $account = $this->drupalCreateUser(['administer entity_test_enhanced']); + $this->drupalLogin($account); + } + + /** + * Tests the add page. + */ + public function testAddPage() { + // This test revealed that if the first bundle gets created in testAddPage + // before drupalGet(), the built cache won't get reset when the second + // bundle is created. This is a BrowserTestBase specific bug. + // @todo Remove comment when the bug is fixed. + + // When only one bundle exists, the add page should redirect to the form. + $this->drupalGet('/entity_test_enhanced/add'); + $this->assertSession()->addressEquals('/entity_test_enhanced/add/first'); + + EnhancedEntityBundle::create([ + 'id' => 'second', + 'label' => 'Second', + 'description' => 'The <b>second</b> bundle', + ])->save(); + $this->drupalGet('/entity_test_enhanced/add'); + $assert = $this->assertSession(); + $assert->addressEquals('/entity_test_enhanced/add'); + $assert->statusCodeEquals(200); + $assert->elementTextContains('css', '.page-title', 'Add entity test with enhancements'); + // Confirm the presence of unescaped descriptions. + $assert->responseContains('The first bundle'); + $assert->responseContains('The <b>second</b> bundle'); + // Validate the links. + $link = $this->getSession()->getPage()->findLink('First'); + $this->assertEquals('/entity_test_enhanced/add/first', $link->getAttribute('href')); + $link = $this->getSession()->getPage()->findLink('Second'); + $this->assertEquals('/entity_test_enhanced/add/second', $link->getAttribute('href')); + } + + /** + * Tests the add form. + */ + public function testAddForm() { + $this->drupalGet('/entity_test_enhanced/add/first'); + $assert = $this->assertSession(); + $assert->elementTextContains('css', '.page-title', 'Add entity test with enhancements'); + $assert->elementExists('css', 'form.entity-test-enhanced-first-add-form'); + + // In case of multiple bundles, the current one is a part of the page title. + EnhancedEntityBundle::create([ + 'id' => 'second', + 'label' => 'Second', + 'description' => 'The <b>second</b> bundle', + ])->save(); + $this->drupalGet('/entity_test_enhanced/add/first'); + $this->assertSession()->elementTextContains('css', '.page-title', 'Add First'); + } + +} diff --git a/tests/Kernel/EntityRevisionLogTraitTest.php b/tests/Kernel/EntityRevisionLogTraitTest.php index d2c7a87adabbabd5d7098629c6eb605bc12575b1..a0b3b3834c0772b1adc111c36e2954e16e685aee 100644 --- a/tests/Kernel/EntityRevisionLogTraitTest.php +++ b/tests/Kernel/EntityRevisionLogTraitTest.php @@ -8,6 +8,7 @@ namespace Drupal\Tests\entity\Kernel; use Drupal\entity_module_test\Entity\EnhancedEntity; +use Drupal\entity_module_test\Entity\EnhancedEntityBundle; use Drupal\KernelTests\KernelTestBase; use Drupal\user\Entity\User; @@ -29,6 +30,12 @@ class EntityRevisionLogTraitTest extends KernelTestBase { $this->installEntitySchema('user'); $this->installSchema('system', 'sequences'); + + $bundle = EnhancedEntityBundle::create([ + 'id' => 'default', + 'label' => 'Default', + ]); + $bundle->save(); } public function testEntityRevisionLog() { @@ -43,6 +50,7 @@ class EntityRevisionLogTraitTest extends KernelTestBase { /** @var \Drupal\entity\Revision\EntityRevisionLogInterface $entity */ $entity = EnhancedEntity::create([ + 'type' => 'default', 'revision_user' => $user->id(), 'revision_created' => 1447941735, 'revision_log_message' => 'Test message', diff --git a/tests/Kernel/RevisionBasicUITest.php b/tests/Kernel/RevisionBasicUITest.php index e19fdefae5f3f86b8047cc58cb6c0b20ecff8028..b716c66b51182e95fec0e62e9407f423f7dc2ae3 100644 --- a/tests/Kernel/RevisionBasicUITest.php +++ b/tests/Kernel/RevisionBasicUITest.php @@ -8,6 +8,7 @@ namespace Drupal\Tests\entity\Kernel; use Drupal\entity_module_test\Entity\EnhancedEntity; +use Drupal\entity_module_test\Entity\EnhancedEntityBundle; use Drupal\KernelTests\KernelTestBase; use Drupal\user\Entity\Role; use Drupal\user\Entity\User; @@ -33,12 +34,19 @@ class RevisionBasicUITest extends KernelTestBase { $this->installEntitySchema('entity_test_enhanced'); $this->installSchema('system', 'router'); + $bundle = EnhancedEntityBundle::create([ + 'id' => 'default', + 'label' => 'Default', + ]); + $bundle->save(); + \Drupal::service('router.builder')->rebuild(); } public function testRevisionView() { $entity = EnhancedEntity::create([ 'name' => 'rev 1', + 'type' => 'default', ]); $entity->save(); diff --git a/tests/modules/entity_module_test/config/schema/entity_module_test.schema.yml b/tests/modules/entity_module_test/config/schema/entity_module_test.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..c20ef335f0c3530f2704266f24cb8c123b2e1b8b --- /dev/null +++ b/tests/modules/entity_module_test/config/schema/entity_module_test.schema.yml @@ -0,0 +1,13 @@ +entity_module_test.entity_test_enhanced_bundle.*: + type: config_entity + label: 'Entity test with enhancments - Bundle' + mapping: + id: + type: string + label: 'Type' + label: + type: label + label: 'Label' + description: + type: text + label: 'Description' diff --git a/tests/modules/entity_module_test/entity_module_test.permissions.yml b/tests/modules/entity_module_test/entity_module_test.permissions.yml new file mode 100644 index 0000000000000000000000000000000000000000..b41f84b6331b2323beb46675a974cf1ee8f9790b --- /dev/null +++ b/tests/modules/entity_module_test/entity_module_test.permissions.yml @@ -0,0 +1,3 @@ +'administer entity_test_enhanced': + title: 'Administer entity_test_enhanced' + 'restrict access': TRUE diff --git a/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php b/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php index 9cefdace06b340505575e0b7b63c857b49a607be..765c43ea017daa4f06e2f988fe74ccda00952ab3 100644 --- a/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php +++ b/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php @@ -21,8 +21,14 @@ use Drupal\entity\Revision\EntityRevisionLogTrait; * label = @Translation("Entity test with enhancements"), * handlers = { * "storage" = "\Drupal\Core\Entity\Sql\SqlContentEntityStorage", + * "form" = { + * "add" = "\Drupal\Core\Entity\ContentEntityForm", + * "edit" = "\Drupal\Core\Entity\ContentEntityForm", + * "delete" = "\Drupal\Core\Entity\EntityDeleteForm", + * }, * "route_provider" = { * "revision" = "\Drupal\entity\Routing\RevisionRouteProvider", + * "create" = "\Drupal\entity\Routing\CreateHtmlRouteProvider", * }, * }, * base_table = "entity_test_enhanced", @@ -34,12 +40,16 @@ use Drupal\entity\Revision\EntityRevisionLogTrait; * admin_permission = "administer entity_test_enhanced", * entity_keys = { * "id" = "id", + * "bundle" = "type", * "revision" = "vid", * "langcode" = "langcode", * }, * links = { + * "add-page" = "/entity_test_enhanced/add", + * "add-form" = "/entity_test_enhanced/add/{type}", * "revision" = "/entity_test_enhanced/{entity_test_enhanced}/revisions/{entity_test_enhanced_revision}/view", - * } + * }, + * bundle_entity_type = "entity_test_enhanced_bundle" * ) */ class EnhancedEntity extends ContentEntityBase { diff --git a/tests/modules/entity_module_test/src/Entity/EnhancedEntityBundle.php b/tests/modules/entity_module_test/src/Entity/EnhancedEntityBundle.php new file mode 100644 index 0000000000000000000000000000000000000000..afe49a7d4b231d4072d6751f7ba8f067c4c6e179 --- /dev/null +++ b/tests/modules/entity_module_test/src/Entity/EnhancedEntityBundle.php @@ -0,0 +1,79 @@ +<?php + +/** + * @file + * Contains \Drupal\entity_module_test\Entity\EnhancedEntityBundle. + */ + +namespace Drupal\entity_module_test\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityBundleBase; +use Drupal\entity\Entity\EntityDescriptionInterface; + +/** + * Provides bundles for the test entity. + * + * @ConfigEntityType( + * id = "entity_test_enhanced_bundle", + * label = @Translation("Entity test with enhancments - Bundle"), + * handlers = { + * "route_provider" = { + * "create" = "\Drupal\entity\Routing\CreateHtmlRouteProvider", + * }, + * }, + * admin_permission = "administer entity_test_enhanced", + * config_prefix = "entity_test_enhanced_bundle", + * bundle_of = "entity_test_enhanced", + * entity_keys = { + * "id" = "id", + * "label" = "label" + * }, + * config_export = { + * "id", + * "label", + * "description" + * }, + * links = { + * "add-form" = "/entity_test_enhanced_bundle/add", + * }, + * ) + */ +class EnhancedEntityBundle extends ConfigEntityBundleBase implements EntityDescriptionInterface { + + /** + * The bundle ID. + * + * @var string + */ + protected $id; + + /** + * The bundle label. + * + * @var string + */ + protected $label; + + /** + * The bundle description. + * + * @var string + */ + protected $description; + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->description; + } + + /** + * {@inheritdoc} + */ + public function setDescription($description) { + $this->description = $description; + return $this; + } + +}