diff --git a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php index 0061530..f965360 100644 --- a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php @@ -38,8 +38,18 @@ public function __construct(ContentNegotiation $negotiation) { public function onRequestSetController(GetResponseEvent $event) { $request = $event->getRequest(); + // @todo This should all get converted into one or more RouteEnhancers. if (!$request->attributes->has('_controller') && $this->negotiation->getContentType($request) === 'html') { - $request->attributes->set('_controller', '\Drupal\Core\HtmlPageController::content'); + if ($request->attributes->has('_form')) { + $request->attributes->set('_controller', '\Drupal\Core\HtmlFormController::content'); + } + elseif ($request->attributes->has('_content')) { + $request->attributes->set('_controller', '\Drupal\Core\HtmlPageController::content'); + } + else { + throw new \InvalidArgumentException('No valid subcontroller key was found'); + } + } } diff --git a/core/lib/Drupal/Core/HtmlFormController.php b/core/lib/Drupal/Core/HtmlFormController.php new file mode 100644 index 0000000..b641341 --- /dev/null +++ b/core/lib/Drupal/Core/HtmlFormController.php @@ -0,0 +1,81 @@ +container = $container; + } + + /** + * Controller method for generic HTML form pages. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * @param callable $_form + * The name of the form class for this request. + * + * @return \Symfony\Component\HttpFoundation\Response + * A response object. + */ + public function content(Request $request, $_form) { + // If this is a class, instantiate it. + if (class_exists($_form)) { + if (in_array('Drupal\Core\ControllerInterface', class_implements($_form))) { + $form_arg = $_form::create($this->container); + } + else { + $form_arg = new $_form(); + } + } + // Otherwise, it is a service. + else { + $form_arg = $this->container->get($_form); + } + + // Using reflection, find all of the parameters needed by the form in the + // request attributes, skipping $form and $form_state. + $attributes = $request->attributes->all(); + $reflection = new \ReflectionMethod($form_arg, 'buildForm'); + $params = $reflection->getParameters(); + $args = array(); + foreach (array_splice($params, 2) as $param) { + if (array_key_exists($param->name, $attributes)) { + $args[] = $attributes[$param->name]; + } + } + $form_state['build_info']['args'] = $args; + + $form_id = _drupal_form_id($form_arg, $form_state); + $form = drupal_build_form($form_id, $form_state); + return new Response(drupal_render_page($form)); + } + +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php index cf2fe24..39a9b86 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php @@ -47,13 +47,48 @@ protected function setUp() { * Tests using an object as the form callback. */ function testObjectFormCallback() { + $config_factory = $this->container->get('config.factory'); + $this->drupalGet('form-test/object-builder'); $this->assertText('The FormTestObject::buildForm() method was used for this form.'); $elements = $this->xpath('//form[@id="form-test-form-test-object"]'); $this->assertTrue(!empty($elements), 'The correct form ID was used.'); - $this->drupalPost('form-test/object-builder', NULL, t('Save')); + $this->drupalPost(NULL, array('bananas' => 'green'), t('Save')); $this->assertText('The FormTestObject::validateForm() method was used for this form.'); $this->assertText('The FormTestObject::submitForm() method was used for this form.'); + $value = $config_factory->get('form_test.object')->get('bananas'); + $this->assertIdentical('green', $value); + + $this->drupalGet('form-test/object-arguments-builder/yellow'); + $this->assertText('The FormTestArgumentsObject::buildForm() method was used for this form.'); + $elements = $this->xpath('//form[@id="form-test-form-test-arguments-object"]'); + $this->assertTrue(!empty($elements), 'The correct form ID was used.'); + $this->drupalPost(NULL, NULL, t('Save')); + $this->assertText('The FormTestArgumentsObject::validateForm() method was used for this form.'); + $this->assertText('The FormTestArgumentsObject::submitForm() method was used for this form.'); + $value = $config_factory->get('form_test.object')->get('bananas'); + $this->assertIdentical('yellow', $value); + + $this->drupalGet('form-test/object-service-builder'); + $this->assertText('The FormTestServiceObject::buildForm() method was used for this form.'); + $elements = $this->xpath('//form[@id="form-test-form-test-service-object"]'); + $this->assertTrue(!empty($elements), 'The correct form ID was used.'); + $this->drupalPost(NULL, array('bananas' => 'brown'), t('Save')); + $this->assertText('The FormTestServiceObject::validateForm() method was used for this form.'); + $this->assertText('The FormTestServiceObject::submitForm() method was used for this form.'); + $value = $config_factory->get('form_test.object')->get('bananas'); + $this->assertIdentical('brown', $value); + + $this->drupalGet('form-test/object-controller-builder'); + $this->assertText('The FormTestControllerObject::create() method was used for this form.'); + $this->assertText('The FormTestControllerObject::buildForm() method was used for this form.'); + $elements = $this->xpath('//form[@id="form-test-form-test-controller-object"]'); + $this->assertTrue(!empty($elements), 'The correct form ID was used.'); + $this->drupalPost(NULL, array('bananas' => 'black'), t('Save')); + $this->assertText('The FormTestControllerObject::validateForm() method was used for this form.'); + $this->assertText('The FormTestControllerObject::submitForm() method was used for this form.'); + $value = $config_factory->get('form_test.object')->get('bananas'); + $this->assertIdentical('black', $value); } } diff --git a/core/modules/system/tests/modules/condition_test/condition_test.routing.yml b/core/modules/system/tests/modules/condition_test/condition_test.routing.yml index 96fbdca..d242511 100644 --- a/core/modules/system/tests/modules/condition_test/condition_test.routing.yml +++ b/core/modules/system/tests/modules/condition_test/condition_test.routing.yml @@ -1,6 +1,6 @@ condition_test_1: pattern: '/condition_test' defaults: - _controller: '\Drupal\condition_test\FormController::getForm' + _form: '\Drupal\condition_test\FormController' requirements: _access: 'TRUE' diff --git a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php index 03b918e..93c3603 100644 --- a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php +++ b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php @@ -30,12 +30,11 @@ public function getFormID() { } /** - * Provides a simple method the router can fire in order to invoke this form. + * Constructs a \Drupal\condition_test\FormController object. */ - public function getForm() { + public function __construct() { $manager = new ConditionManager(drupal_container()->getParameter('container.namespaces')); $this->condition = $manager->createInstance('node_type'); - return drupal_get_form($this); } /** diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module index fe5d999..3a0ecaf 100644 --- a/core/modules/system/tests/modules/form_test/form_test.module +++ b/core/modules/system/tests/modules/form_test/form_test.module @@ -28,12 +28,6 @@ function form_test_menu() { 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); - $items['form-test/object-builder'] = array( - 'title' => 'Form object builder test', - 'page callback' => 'form_test_object_builder', - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); $items['form-test/system-config-form'] = array( 'title' => 'Form object builder test', 'page callback' => 'form_test_system_config_form', @@ -377,13 +371,6 @@ function form_test_permission() { } /** - * Page callback: Displays a form built from an object. - */ -function form_test_object_builder() { - return drupal_get_form(new FormTestObject()); -} - -/** * Page callback: Displays a form built from SystemConfigForm. */ function form_test_system_config_form() { diff --git a/core/modules/system/tests/modules/form_test/form_test.routing.yml b/core/modules/system/tests/modules/form_test/form_test.routing.yml new file mode 100644 index 0000000..826e737 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml @@ -0,0 +1,27 @@ +form_test.route1: + pattern: '/form-test/object-builder' + defaults: + _form: '\Drupal\form_test\FormTestObject' + requirements: + _access: 'TRUE' + +form_test.route2: + pattern: '/form-test/object-arguments-builder/{arg}' + defaults: + _form: '\Drupal\form_test\FormTestArgumentsObject' + requirements: + _access: 'TRUE' + +form_test.route3: + pattern: '/form-test/object-service-builder' + defaults: + _form: 'form_test.form.serviceForm' + requirements: + _access: 'TRUE' + +form_test.route4: + pattern: '/form-test/object-controller-builder' + defaults: + _form: '\Drupal\form_test\FormTestControllerObject' + requirements: + _access: 'TRUE' diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestArgumentsObject.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestArgumentsObject.php new file mode 100644 index 0000000..ee13968 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestArgumentsObject.php @@ -0,0 +1,61 @@ + 'The FormTestArgumentsObject::buildForm() method was used for this form.'); + + $form['bananas'] = array( + '#type' => 'textfield', + '#default_value' => check_plain($arg), + '#title' => t('Bananas'), + ); + + $form['actions']['#type'] = 'actions'; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + return $form; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + */ + public function validateForm(array &$form, array &$form_state) { + drupal_set_message(t('The FormTestArgumentsObject::validateForm() method was used for this form.')); + } + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + */ + public function submitForm(array &$form, array &$form_state) { + drupal_set_message(t('The FormTestArgumentsObject::submitForm() method was used for this form.')); + config('form_test.object') + ->set('bananas', $form_state['values']['bananas']) + ->save(); + } + +} diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestBundle.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestBundle.php new file mode 100644 index 0000000..0ccf9d8 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestBundle.php @@ -0,0 +1,26 @@ +register('form_test.form.serviceForm', 'Drupal\form_test\FormTestServiceObject'); + } + +} diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestControllerObject.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestControllerObject.php new file mode 100644 index 0000000..38a8fc7 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestControllerObject.php @@ -0,0 +1,70 @@ + 'The FormTestControllerObject::buildForm() method was used for this form.'); + + $form['bananas'] = array( + '#type' => 'textfield', + '#title' => t('Bananas'), + ); + + $form['actions']['#type'] = 'actions'; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + return $form; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + */ + public function validateForm(array &$form, array &$form_state) { + drupal_set_message(t('The FormTestControllerObject::validateForm() method was used for this form.')); + } + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + */ + public function submitForm(array &$form, array &$form_state) { + drupal_set_message(t('The FormTestControllerObject::submitForm() method was used for this form.')); + config('form_test.object') + ->set('bananas', $form_state['values']['bananas']) + ->save(); + } + +} diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestServiceObject.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestServiceObject.php new file mode 100644 index 0000000..c7663ef --- /dev/null +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestServiceObject.php @@ -0,0 +1,61 @@ + 'The FormTestServiceObject::buildForm() method was used for this form.'); + + $form['bananas'] = array( + '#type' => 'textfield', + '#default_value' => 'brown', + '#title' => t('Bananas'), + ); + + $form['actions']['#type'] = 'actions'; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + return $form; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + */ + public function validateForm(array &$form, array &$form_state) { + drupal_set_message(t('The FormTestServiceObject::validateForm() method was used for this form.')); + } + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + */ + public function submitForm(array &$form, array &$form_state) { + drupal_set_message(t('The FormTestServiceObject::submitForm() method was used for this form.')); + config('form_test.object') + ->set('bananas', $form_state['values']['bananas']) + ->save(); + } + +} diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php index d7f6d53..cc699b8 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php @@ -58,19 +58,6 @@ public static function create(ContainerInterface $container) { } /** - * Creates a new instance of this form. - * - * @param \Drupal\views\ViewStorageInterface $view - * The view being acted upon. - * - * @return array - * The built form array. - */ - public function getForm(ViewStorageInterface $view) { - return drupal_get_form($this, $view); - } - - /** * Implements \Drupal\Core\Form\FormInterface::getFormID(). */ public function getFormID() { diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php index 3f38679..f9b7272 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php @@ -16,19 +16,6 @@ class DeleteForm implements FormInterface { /** - * Creates a new instance of this form. - * - * @param \Drupal\views\ViewStorageInterface $view - * The view being acted upon. - * - * @return array - * The built form array. - */ - public function getForm(ViewStorageInterface $view) { - return drupal_get_form($this, $view); - } - - /** * Implements \Drupal\Core\Form\FormInterface::getFormID(). */ public function getFormID() { diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php index 82ea585..662e00d 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php @@ -44,14 +44,4 @@ public static function create(ContainerInterface $container) { ); } - /** - * Creates a new instance of this form. - * - * @return array - * The built form array. - */ - public function getForm() { - return drupal_get_form($this); - } - } diff --git a/core/modules/views/views_ui/views_ui.routing.yml b/core/modules/views/views_ui/views_ui.routing.yml index ed81159..9c64891 100644 --- a/core/modules/views/views_ui/views_ui.routing.yml +++ b/core/modules/views/views_ui/views_ui.routing.yml @@ -15,14 +15,14 @@ views_ui.add: views_ui.settings.basic: pattern: '/admin/structure/views/settings' defaults: - _controller: '\Drupal\views_ui\Form\BasicSettingsForm::getForm' + _form: '\Drupal\views_ui\Form\BasicSettingsForm' requirements: _permission: 'administer views' views_ui.settings.advanced: pattern: '/admin/structure/views/settings/advanced' defaults: - _controller: '\Drupal\views_ui\Form\AdvancedSettingsForm::getForm' + _form: '\Drupal\views_ui\Form\AdvancedSettingsForm' requirements: _permission: 'administer views' @@ -58,7 +58,7 @@ views_ui.clone: views_ui.delete: pattern: '/admin/structure/views/view/{view}/delete' defaults: - _controller: 'Drupal\views_ui\Form\DeleteForm::getForm' + _form: 'Drupal\views_ui\Form\DeleteForm' requirements: _permission: 'administer views' @@ -104,7 +104,7 @@ views_ui.preview: views_ui.breakLock: pattern: '/admin/structure/views/view/{view}/break-lock' defaults: - _controller: '\Drupal\views_ui\Form\BreakLockForm::getForm' + _form: '\Drupal\views_ui\Form\BreakLockForm' display_id: NULL requirements: _permission: 'administer views'