diff --git a/core/lib/Drupal/Core/Controller/FormController.php b/core/lib/Drupal/Core/Controller/FormController.php index dc191c0f875e..6a9b9d597b69 100644 --- a/core/lib/Drupal/Core/Controller/FormController.php +++ b/core/lib/Drupal/Core/Controller/FormController.php @@ -10,6 +10,7 @@ namespace Drupal\Core\Controller; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Form\FormBuilderInterface; use Drupal\Core\Form\FormState; +use Drupal\Core\Routing\RouteMatchInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -52,13 +53,15 @@ abstract class FormController { * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. * * @return array * The render array that results from invoking the controller. */ - public function getContentResult(Request $request) { - $form_arg = $this->getFormArgument($request); - $form_object = $this->getFormObject($request, $form_arg); + public function getContentResult(Request $request, RouteMatchInterface $route_match) { + $form_arg = $this->getFormArgument($route_match); + $form_object = $this->getFormObject($route_match, $form_arg); // Add the form and form_state to trick the getArguments method of the // controller resolver. @@ -88,25 +91,25 @@ abstract class FormController { * _form: Drupal\example\Form\ExampleForm * @endcode * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request object from which to extract a form definition string. + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match object from which to extract a form definition string. * * @return string * The form definition string. */ - abstract protected function getFormArgument(Request $request); + abstract protected function getFormArgument(RouteMatchInterface $route_match); /** * Returns the object used to build the form. * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request using this form. + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. * @param string $form_arg * Either a class name or a service ID. * * @return \Drupal\Core\Form\FormInterface * The form object to use. */ - abstract protected function getFormObject(Request $request, $form_arg); + abstract protected function getFormObject(RouteMatchInterface $route_match, $form_arg); } diff --git a/core/lib/Drupal/Core/Controller/HtmlFormController.php b/core/lib/Drupal/Core/Controller/HtmlFormController.php index 81a9b021cb14..e84975d4e51f 100644 --- a/core/lib/Drupal/Core/Controller/HtmlFormController.php +++ b/core/lib/Drupal/Core/Controller/HtmlFormController.php @@ -8,7 +8,7 @@ namespace Drupal\Core\Controller; use Drupal\Core\Form\FormBuilderInterface; -use Symfony\Component\HttpFoundation\Request; +use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\DependencyInjection\ClassResolverInterface; /** @@ -39,24 +39,16 @@ class HtmlFormController extends FormController { } /** - * @{inheritDoc} + * {@inheritdoc} */ - protected function getFormArgument(Request $request) { - return $request->attributes->get('_form'); + protected function getFormArgument(RouteMatchInterface $route_match) { + return $route_match->getRouteObject()->getDefault('_form'); } /** - * Returns the object used to build the form. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request using this form. - * @param string $form_arg - * Either a class name or a service ID. - * - * @return \Drupal\Core\Form\FormInterface - * The form object to use. + * {@inheritdoc} */ - protected function getFormObject(Request $request, $form_arg) { + protected function getFormObject(RouteMatchInterface $route_match, $form_arg) { return $this->classResolver->getInstanceFromDefinition($form_arg); } diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php index ba3660134eb0..a0b18faac33f 100644 --- a/core/lib/Drupal/Core/Entity/EntityForm.php +++ b/core/lib/Drupal/Core/Entity/EntityForm.php @@ -11,6 +11,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; +use Drupal\Core\Routing\RouteMatchInterface; /** * Base class for entity forms. @@ -36,6 +37,13 @@ class EntityForm extends FormBase implements EntityFormInterface { */ protected $moduleHandler; + /** + * The entity manager. + * + * @var \Drupal\Core\Entity\EntityManagerInterface + */ + protected $entityManager; + /** * The entity being used by this form. * @@ -321,6 +329,20 @@ class EntityForm extends FormBase implements EntityFormInterface { return $this; } + /** + * {@inheritdoc} + */ + public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) { + if ($route_match->getRawParameter($entity_type_id) !== NULL) { + $entity = $route_match->getParameter($entity_type_id); + } + else { + $entity = $this->entityManager->getStorage($entity_type_id)->create([]); + } + + return $entity; + } + /** * Prepares the entity object before the form is built first. */ @@ -362,4 +384,12 @@ class EntityForm extends FormBase implements EntityFormInterface { return $this; } + /** + * {@inheritdoc} + */ + public function setEntityManager(EntityManagerInterface $entity_manager) { + $this->entityManager = $entity_manager; + return $this; + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityFormInterface.php b/core/lib/Drupal/Core/Entity/EntityFormInterface.php index b8ecab11b038..a8fe39e0ebaa 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityFormInterface.php @@ -10,6 +10,7 @@ namespace Drupal\Core\Entity; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\BaseFormIdInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\StringTranslation\TranslationInterface; /** @@ -40,9 +41,6 @@ interface EntityFormInterface extends BaseFormIdInterface { * * The form entity which has been used for populating form element defaults. * - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - * * @return \Drupal\Core\Entity\EntityInterface * The current form entity. */ @@ -64,6 +62,19 @@ interface EntityFormInterface extends BaseFormIdInterface { */ public function setEntity(EntityInterface $entity); + /** + * Determines which entity will be used by this form from a RouteMatch object. + * + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. + * @param string $entity_type_id + * The entity type identifier. + * + * @return \Drupal\Core\Entity\EntityInterface + * The entity object as determined from the passed-in route match. + */ + public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id); + /** * Builds an updated entity object based upon the submitted form values. * @@ -129,4 +140,14 @@ interface EntityFormInterface extends BaseFormIdInterface { */ public function setModuleHandler(ModuleHandlerInterface $module_handler); + /** + * Sets the entity manager for this form. + * + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. + * + * @return $this + */ + public function setEntityManager(EntityManagerInterface $entity_manager); + } diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 06fb6a357ede..58f75b74f0e0 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -294,6 +294,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $form_object ->setStringTranslation($this->translationManager) ->setModuleHandler($this->moduleHandler) + ->setEntityManager($this) ->setOperation($operation); $this->handlers['form'][$operation][$entity_type] = $form_object; } diff --git a/core/lib/Drupal/Core/Entity/HtmlEntityFormController.php b/core/lib/Drupal/Core/Entity/HtmlEntityFormController.php index bd659a96164f..093cb3421425 100644 --- a/core/lib/Drupal/Core/Entity/HtmlEntityFormController.php +++ b/core/lib/Drupal/Core/Entity/HtmlEntityFormController.php @@ -10,7 +10,7 @@ namespace Drupal\Core\Entity; use Drupal\Core\Controller\ControllerResolverInterface; use Drupal\Core\Controller\FormController; use Drupal\Core\Form\FormBuilderInterface; -use Symfony\Component\HttpFoundation\Request; +use Drupal\Core\Routing\RouteMatchInterface; /** * Wrapping controller for entity forms that serve as the main page body. @@ -22,7 +22,7 @@ class HtmlEntityFormController extends FormController { * * @var \Drupal\Core\Entity\EntityManagerInterface */ - protected $manager; + protected $entityManager; /** * Constructs a new \Drupal\Core\Routing\Enhancer\FormEnhancer object. @@ -36,14 +36,14 @@ class HtmlEntityFormController extends FormController { */ public function __construct(ControllerResolverInterface $resolver, FormBuilderInterface $form_builder, EntityManagerInterface $manager) { parent::__construct($resolver, $form_builder); - $this->manager = $manager; + $this->entityManager = $manager; } /** - * @{inheritDoc} + * {@inheritdoc} */ - protected function getFormArgument(Request $request) { - return $request->attributes->get('_entity_form'); + protected function getFormArgument(RouteMatchInterface $route_match) { + return $route_match->getRouteObject()->getDefault('_entity_form'); } /** @@ -66,19 +66,19 @@ class HtmlEntityFormController extends FormController { * _entity_form: 'node' * @endcode */ - protected function getFormObject(Request $request, $form_arg) { + protected function getFormObject(RouteMatchInterface $route_match, $form_arg) { // If no operation is provided, use 'default'. $form_arg .= '.default'; - list ($entity_type, $operation) = explode('.', $form_arg); + list ($entity_type_id, $operation) = explode('.', $form_arg); - if ($request->attributes->has($entity_type)) { - $entity = $request->attributes->get($entity_type); - } - else { - $entity = $this->manager->getStorage($entity_type)->create([]); - } + $form_object = $this->entityManager->getFormObject($entity_type_id, $operation); - return $this->manager->getFormObject($entity_type, $operation)->setEntity($entity); + // Allow the entity form to determine the entity object from a given route + // match. + $entity = $form_object->getEntityFromRouteMatch($route_match, $entity_type_id); + $form_object->setEntity($entity); + + return $form_object; } } diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index caea0e566a03..b7e73f9b1213 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -10,14 +10,13 @@ namespace Drupal\Tests\Core\Entity { use Drupal\Component\Plugin\Discovery\DiscoveryInterface; use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Config\Entity\ConfigEntityStorage; -use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; -use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityHandlerBase; use Drupal\Core\Entity\EntityHandlerInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManager; +use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageInterface; @@ -1503,6 +1502,13 @@ class TestEntityHandlerInjected implements EntityHandlerInterface { */ class TestEntityForm extends EntityHandlerBase { + /** + * The entity manager. + * + * @var \Drupal\Tests\Core\Entity\TestEntityManager + */ + protected $entityManager; + /** * {@inheritdoc} */ @@ -1531,6 +1537,14 @@ class TestEntityForm extends EntityHandlerBase { return $this; } + /** + * {@inheritdoc} + */ + public function setEntityManager(EntityManagerInterface $entity_manager) { + $this->entityManager = $entity_manager; + return $this; + } + } /**