Issue #2651716 by tstoeckler, bojanz: Entity::getEntityFromRouteMatch() should support bundles
							parent
							
								
									9de35948b6
								
							
						
					
					
						commit
						edb618f556
					
				| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
   *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}",
 | 
			
		||||
 *   },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
 *   },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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')
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue