diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php index 8d919485272..fd207641ef3 100644 --- a/core/lib/Drupal/Core/Entity/EntityForm.php +++ b/core/lib/Drupal/Core/Entity/EntityForm.php @@ -358,7 +358,19 @@ class EntityForm extends FormBase implements EntityFormInterface { $entity = $route_match->getParameter($entity_type_id); } else { - $entity = $this->entityManager->getStorage($entity_type_id)->create([]); + $values = []; + // If the entity has bundles, fetch it from the route match. + $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); + if ($bundle_key = $entity_type->getKey('bundle')) { + if (($bundle_entity_type_id = $entity_type->getBundleEntityType()) && $route_match->getRawParameter($bundle_entity_type_id)) { + $values[$bundle_key] = $route_match->getParameter($bundle_entity_type_id)->id(); + } + elseif ($route_match->getRawParameter($bundle_key)) { + $values[$bundle_key] = $route_match->getParameter($bundle_key); + } + } + + $entity = $this->entityTypeManager->getStorage($entity_type_id)->create($values); } return $entity; diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 0eec45d75e4..668c81defd8 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -67,6 +67,8 @@ function entity_test_entity_types($filter = NULL) { } if ($filter === ENTITY_TEST_TYPES_ROUTING) { $types[] = 'entity_test_base_field_display'; + $types[] = 'entity_test_string_id'; + $types[] = 'entity_test_no_id'; } $types[] = 'entity_test_mulrev'; $types[] = 'entity_test_mulrev_changed'; diff --git a/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php b/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php index b44c7ebeb22..51cc8bdff88 100644 --- a/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php +++ b/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php @@ -44,24 +44,6 @@ class EntityTestController extends ControllerBase { ); } - /** - * Displays the 'Add new entity_test' form. - * - * @param string $entity_type_id - * Name of the entity type for which a create form should be displayed. - * - * @return array - * The processed form for a new entity_test. - * - * @see \Drupal\entity_test\Routing\EntityTestRoutes::routes() - */ - public function testAdd($entity_type_id) { - $entity = entity_create($entity_type_id, array()); - $form = $this->entityFormBuilder()->getForm($entity); - $form['#title'] = $this->t('Create an @type', array('@type' => $entity_type_id)); - return $form; - } - /** * Returns an empty page. * diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php index dc46e902558..c5320e60d63 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php @@ -47,6 +47,7 @@ use Drupal\user\UserInterface; * }, * links = { * "canonical" = "/entity_test/{entity_test}", + * "add-form" = "/entity_test/add", * "edit-form" = "/entity_test/manage/{entity_test}/edit", * "delete-form" = "/entity_test/delete/entity_test/{entity_test}", * }, diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php index 8a3d90f3786..4cc7cc31022 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php @@ -38,6 +38,7 @@ use Drupal\entity_test\FieldStorageDefinition; * }, * links = { * "canonical" = "/entity_test_base_field_display/{entity_test_base_field_display}/edit", + * "add-form" = "/entity_test_base_field_display/add", * "edit-form" = "/entity_test_base_field_display/manage/{entity_test_base_field_display}", * "delete-form" = "/entity_test/delete/entity_test_base_field_display/{entity_test_base_field_display}/edit", * }, diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php index a29c1e2df7b..bc0661ec74a 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php @@ -19,7 +19,11 @@ namespace Drupal\entity_test\Entity; * entity_keys = { * "bundle" = "type", * }, + * admin_permission = "administer entity_test content", * field_ui_base_route = "entity.entity_test_no_id.admin_form", + * links = { + * "add-form" = "/entity_test_no_id/add", + * }, * ) */ class EntityTestNoId extends EntityTest { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php index 1f53e044f40..41f793c38ec 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php @@ -34,6 +34,7 @@ use Drupal\Core\Entity\EntityTypeInterface; * }, * links = { * "canonical" = "/entity_test_string_id/manage/{entity_test_string_id}", + * "add-form" = "/entity_test_string_id/add", * "edit-form" = "/entity_test_string_id/manage/{entity_test_string_id}", * }, * field_ui_base_route = "entity.entity_test_string_id.admin_form", diff --git a/core/modules/system/tests/modules/entity_test/src/Routing/EntityTestRoutes.php b/core/modules/system/tests/modules/entity_test/src/Routing/EntityTestRoutes.php index 8992550f316..a8690b5dbc6 100644 --- a/core/modules/system/tests/modules/entity_test/src/Routing/EntityTestRoutes.php +++ b/core/modules/system/tests/modules/entity_test/src/Routing/EntityTestRoutes.php @@ -22,14 +22,12 @@ class EntityTestRoutes { */ public function routes() { $types = entity_test_entity_types(ENTITY_TEST_TYPES_ROUTING); - $types[] = 'entity_test_string_id'; - $types[] = 'entity_test_no_id'; $routes = array(); foreach ($types as $entity_type_id) { $routes["entity.$entity_type_id.add_form"] = new Route( "$entity_type_id/add", - array('_controller' => '\Drupal\entity_test\Controller\EntityTestController::testAdd', 'entity_type_id' => $entity_type_id), + array('_entity_form' => "$entity_type_id.default"), array('_permission' => 'administer entity_test content') ); diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php index 810bdd1d6de..b08f9f06f2b 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php @@ -8,8 +8,14 @@ namespace Drupal\Tests\Core\Entity; use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Entity\EntityType; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormState; +use Drupal\Core\Routing\RouteMatch; use Drupal\Tests\UnitTestCase; +use Symfony\Component\Routing\Route; /** * @coversDefaultClass \Drupal\Core\Entity\EntityForm @@ -24,6 +30,13 @@ class EntityFormTest extends UnitTestCase { */ protected $entityForm; + /** + * A fake entity type used in the test. + * + * @var \Drupal\Core\Entity\EntityTypeInterface + */ + protected $entityType; + /** * {@inheritdoc} */ @@ -31,6 +44,7 @@ class EntityFormTest extends UnitTestCase { parent::setUp(); $this->entityForm = new EntityForm(); + $this->entityType = new EntityType(['id' => 'entity_test']); } /** @@ -41,17 +55,13 @@ class EntityFormTest extends UnitTestCase { * @dataProvider providerTestFormIds */ public function testFormId($expected, $definition) { - $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface'); - $entity_type->expects($this->any()) - ->method('hasKey') - ->with('bundle') - ->will($this->returnValue($definition['bundle'])); + $this->entityType->set('entity_keys', ['bundle' => $definition['bundle']]); $entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array(), $definition['entity_type']), '', TRUE, TRUE, TRUE, array('getEntityType', 'bundle')); $entity->expects($this->any()) ->method('getEntityType') - ->will($this->returnValue($entity_type)); + ->will($this->returnValue($this->entityType)); $entity->expects($this->any()) ->method('bundle') ->will($this->returnValue($definition['bundle'])); @@ -123,4 +133,115 @@ class EntityFormTest extends UnitTestCase { $this->assertNull($result->get('key_controlled_by_plugin_collection')); } + /** + * Tests EntityForm::getEntityFromRouteMatch() for edit and delete forms. + * + * @covers ::getEntityFromRouteMatch + */ + public function testGetEntityFromRouteMatchEditDelete() { + $entity = $this->prophesize(EntityInterface::class)->reveal(); + $id = $this->entityType->id(); + $route_match = new RouteMatch( + 'test_route', + new Route('/entity-test/manage/{' . $id . '}/edit'), + [$id => $entity], + [$id => 1] + ); + $actual = $this->entityForm->getEntityFromRouteMatch($route_match, $id); + $this->assertEquals($entity, $actual); + } + + /** + * Tests EntityForm::getEntityFromRouteMatch() for add forms without a bundle. + * + * @covers ::getEntityFromRouteMatch + */ + public function testGetEntityFromRouteMatchAdd() { + $entity = $this->prophesize(EntityInterface::class)->reveal(); + $this->setUpStorage()->create([])->willReturn($entity); + $route_match = new RouteMatch('test_route', new Route('/entity-test/add')); + $actual = $this->entityForm->getEntityFromRouteMatch($route_match, $this->entityType->id()); + $this->assertEquals($entity, $actual); + } + + /** + * Tests EntityForm::getEntityFromRouteMatch() with a static bundle. + * + * @covers ::getEntityFromRouteMatch + */ + public function testGetEntityFromRouteMatchAddStatic() { + $entity = $this->prophesize(EntityInterface::class)->reveal(); + $bundle_key = 'bundle'; + $bundle = 'test_bundle'; + $this->entityType->set('entity_keys', ['bundle' => $bundle_key]); + $storage = $this->setUpStorage(); + + // Test without a bundle parameter in the route. + $storage->create([])->willReturn($entity); + $route_match = new RouteMatch('test_route', new Route('/entity-test/add')); + $actual = $this->entityForm->getEntityFromRouteMatch($route_match, $this->entityType->id()); + $this->assertEquals($entity, $actual); + + // Test with a static bundle parameter. + $storage->create([$bundle_key => 'test_bundle'])->willReturn($entity); + $route_match = new RouteMatch( + 'test_route', + new Route('/entity-test/add/{' . $bundle_key . '}'), + [$bundle_key => $bundle], + [$bundle_key => $bundle] + ); + $actual = $this->entityForm->getEntityFromRouteMatch($route_match, $this->entityType->id()); + $this->assertEquals($entity, $actual); + } + + /** + * Tests EntityForm::getEntityFromRouteMatch() with a config entity bundle. + * + * @covers ::getEntityFromRouteMatch + */ + public function testGetEntityFromRouteMatchAddEntity() { + $entity = $this->prophesize(EntityInterface::class)->reveal(); + $bundle_entity_type_id = 'entity_test_bundle'; + $bundle = 'test_entity_bundle'; + $this->entityType->set('bundle_entity_type', $bundle_entity_type_id); + $storage = $this->setUpStorage(); + + // Test without a bundle parameter in the route. + $storage->create([])->willReturn($entity); + $route_match = new RouteMatch('test_route', new Route('/entity-test/add')); + $actual = $this->entityForm->getEntityFromRouteMatch($route_match, $this->entityType->id()); + $this->assertEquals($entity, $actual); + + // Test with an entity bundle parameter. + $storage->create(['bundle' => $bundle])->willReturn($entity); + $bundle_entity = $this->prophesize(EntityInterface::class); + $bundle_entity->id()->willReturn('test_entity_bundle'); + $route_match = new RouteMatch( + 'test_route', + new Route('/entity-test/add/{entity_test_bundle}'), + [$bundle_entity_type_id => $bundle_entity->reveal()], + [$bundle_entity_type_id => $bundle] + ); + $actual = $this->entityForm->getEntityFromRouteMatch($route_match, $this->entityType->id()); + $this->assertEquals($entity, $actual); + } + + /** + * Sets up the storage accessed via the entity type manager in the form. + * + * @return \Prophecy\Prophecy\ObjectProphecy + * The storage prophecy. + */ + protected function setUpStorage() { + $storage = $this->prophesize(EntityStorageInterface::class); + + $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class); + $entity_type_manager->getDefinition($this->entityType->id())->willReturn($this->entityType); + $entity_type_manager->getStorage($this->entityType->id())->willReturn($storage->reveal()); + + $this->entityForm->setEntityTypeManager($entity_type_manager->reveal()); + + return $storage; + } + }