Commit fc939d4e authored by alexpott's avatar alexpott

Issue #2268761 by tim.plunkett: Remove support for function-based forms.

parent 50ac4700
......@@ -379,7 +379,7 @@ function _batch_next_set() {
if (isset($current_set['form_submit']) && ($callback = $current_set['form_submit']) && is_callable($callback)) {
// We use our stored copies of $form and $form_state to account for
// possible alterations by previous form submit handlers.
call_user_func_array($callback, array($batch['form_state']['complete_form'], &$batch['form_state']));
call_user_func_array($callback, array(&$batch['form_state']['complete_form'], &$batch['form_state']));
}
return TRUE;
}
......
......@@ -77,8 +77,7 @@ public function getContentResult(Request $request) {
unset($args[0], $args[1]);
$form_state['build_info']['args'] = array_values($args);
$form_id = $this->formBuilder->getFormId($form_object, $form_state);
return $this->formBuilder->buildForm($form_id, $form_state);
return $this->formBuilder->buildForm($form_object, $form_state);
}
/**
......
......@@ -52,7 +52,7 @@ public function getForm(EntityInterface $entity, $operation = 'default', array $
$form_state['build_info']['base_form_id'] = $form_object->getBaseFormID();
$form_state['build_info'] += array('args' => array());
return $this->formBuilder->buildForm($form_object->getFormId(), $form_state);
return $this->formBuilder->buildForm($form_object, $form_state);
}
}
......@@ -9,6 +9,7 @@
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
......@@ -139,18 +140,16 @@ public function getFormId($form_arg, &$form_state) {
$form_arg = $this->classResolver->getInstanceFromDefinition($form_arg);
}
// If the $form_arg implements \Drupal\Core\Form\FormInterface, add that as
// the callback object and determine the form ID.
if (is_object($form_arg) && $form_arg instanceof FormInterface) {
$form_state['build_info']['callback_object'] = $form_arg;
if ($form_arg instanceof BaseFormIdInterface) {
$form_state['build_info']['base_form_id'] = $form_arg->getBaseFormID();
}
return $form_arg->getFormId();
if (!is_object($form_arg) || !($form_arg instanceof FormInterface)) {
throw new \InvalidArgumentException(String::format('The form argument @form_arg is not a valid form.', array('@form_arg' => $form_arg)));
}
// Otherwise, the $form_arg is the form ID.
return $form_arg;
// Add the $form_arg as the callback object and determine the form ID.
$form_state['build_info']['callback_object'] = $form_arg;
if ($form_arg instanceof BaseFormIdInterface) {
$form_state['build_info']['base_form_id'] = $form_arg->getBaseFormID();
}
return $form_arg->getFormId();
}
/**
......@@ -164,8 +163,7 @@ public function getForm($form_arg) {
unset($args[0]);
$form_state['build_info']['args'] = array_values($args);
$form_id = $this->getFormId($form_arg, $form_state);
return $this->buildForm($form_id, $form_state);
return $this->buildForm($form_arg, $form_state);
}
/**
......@@ -468,15 +466,7 @@ public function retrieveForm($form_id, &$form_state) {
// the constructor function itself.
$args = $form_state['build_info']['args'];
// If an explicit form builder callback is defined we just use it, otherwise
// we look for a function named after the $form_id.
$callback = $form_id;
if (!empty($form_state['build_info']['callback'])) {
$callback = $form_state['build_info']['callback'];
}
elseif (!empty($form_state['build_info']['callback_object'])) {
$callback = array($form_state['build_info']['callback_object'], 'buildForm');
}
$callback = array($form_state['build_info']['callback_object'], 'buildForm');
$form = array();
// Assign a default CSS class name based on $form_id.
......@@ -685,40 +675,8 @@ public function prepareForm($form_id, &$form, &$form_state) {
$form += $this->getElementInfo('form');
$form += array('#tree' => FALSE, '#parents' => array());
if (!isset($form['#validate'])) {
// Ensure that modules can rely on #validate being set.
$form['#validate'] = array();
if (isset($form_state['build_info']['callback_object'])) {
$form['#validate'][] = array($form_state['build_info']['callback_object'], 'validateForm');
}
// Check for a handler specific to $form_id.
elseif (function_exists($form_id . '_validate')) {
$form['#validate'][] = $form_id . '_validate';
}
// Otherwise check whether this is a shared form and whether there is a
// handler for the shared $form_id.
elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_validate')) {
$form['#validate'][] = $form_state['build_info']['base_form_id'] . '_validate';
}
}
if (!isset($form['#submit'])) {
// Ensure that modules can rely on #submit being set.
$form['#submit'] = array();
if (isset($form_state['build_info']['callback_object'])) {
$form['#submit'][] = array($form_state['build_info']['callback_object'], 'submitForm');
}
// Check for a handler specific to $form_id.
elseif (function_exists($form_id . '_submit')) {
$form['#submit'][] = $form_id . '_submit';
}
// Otherwise check whether this is a shared form and whether there is a
// handler for the shared $form_id.
elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_submit')) {
$form['#submit'][] = $form_state['build_info']['base_form_id'] . '_submit';
}
}
$form['#validate'][] = array($form_state['build_info']['callback_object'], 'validateForm');
$form['#submit'][] = array($form_state['build_info']['callback_object'], 'submitForm');
// If no #theme has been set, automatically apply theme suggestions.
// theme_form() itself is in #theme_wrappers and not #theme. Therefore, the
......
......@@ -36,7 +36,6 @@ public function getFormId($form_arg, &$form_state);
* The value must be one of the following:
* - The name of a class that implements \Drupal\Core\Form\FormInterface.
* - An instance of a class that implements \Drupal\Core\Form\FormInterface.
* - The name of a function that builds the form.
* @param ...
* Any additional arguments are passed on to the functions called by
* \Drupal::formBuilder()->getForm(), including the unique form constructor
......@@ -59,8 +58,10 @@ public function getForm($form_arg);
* previous page-load. The form is then passed on for processing, validation
* and submission if there is proper input.
*
* @param $form_id
* The unique string identifying the desired form.
* @param \Drupal\Core\Form\FormInterface|string $form_arg
* The value must be one of the following:
* - The name of a class that implements \Drupal\Core\Form\FormInterface.
* - An instance of a class that implements \Drupal\Core\Form\FormInterface.
* @param array $form_state
* An array which stores information about the form. This is passed as a
* reference so that the caller can use it to examine what in the form
......
......@@ -342,6 +342,7 @@ function testEntityFormDisplayExtractFormValues() {
$values_2[1]['value'] = 0;
// Pretend the form has been built.
$form_state['build_info']['callback_object'] = \Drupal::entityManager()->getFormObject($entity_type, 'default');
\Drupal::formBuilder()->prepareForm('field_test_entity_form', $form, $form_state);
drupal_process_form('field_test_entity_form', $form, $form_state);
$form_state['values'][$this->field_name] = $values;
......
......@@ -153,8 +153,6 @@ public function buildForm(array $form, array &$form_state, FieldInstanceConfigIn
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save field settings'));
$form['#submit'][] = array($this, 'submitForm');
$form['#validate'][] = array($this, 'validateForm');
return $form;
}
......
......@@ -216,6 +216,7 @@ private function formSubmitHelper($form, $edit) {
$form_state['input'] = $edit;
$form_state['input']['form_id'] = $form_id;
$form_state['build_info']['callback_object'] = new StubForm($form_id, $form);
\Drupal::formBuilder()->prepareForm($form_id, $form, $form_state);
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Form\FormDefaultHandlersTest.
*/
namespace Drupal\system\Tests\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\simpletest\KernelTestBase;
/**
* Tests automatically added form handlers.
*
* @group Form
*/
class FormDefaultHandlersTest extends KernelTestBase implements FormInterface {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'test_form_handlers';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$form['#validate'][] = array($this, 'customValidateForm');
$form['#submit'][] = array($this, 'customSubmitForm');
$form['submit'] = array('#type' => 'submit', '#value' => 'Save');
return $form;
}
/**
* {@inheritdoc}
*/
public function customValidateForm(array &$form, array &$form_state) {
$form_state['test_handlers']['validate'][] = __FUNCTION__;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
$form_state['test_handlers']['validate'][] = __FUNCTION__;
}
/**
* {@inheritdoc}
*/
public function customSubmitForm(array &$form, array &$form_state) {
$form_state['test_handlers']['submit'][] = __FUNCTION__;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$form_state['test_handlers']['submit'][] = __FUNCTION__;
}
/**
* Tests that default handlers are added even if custom are specified.
*/
function testDefaultAndCustomHandlers() {
$form_state['values'] = array();
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
$handlers = $form_state['test_handlers'];
$this->assertIdentical(count($handlers['validate']), 2);
$this->assertIdentical($handlers['validate'][0], 'customValidateForm');
$this->assertIdentical($handlers['validate'][1], 'validateForm');
$this->assertIdentical(count($handlers['submit']), 2);
$this->assertIdentical($handlers['submit'][0], 'customSubmitForm');
$this->assertIdentical($handlers['submit'][1], 'submitForm');
}
}
......@@ -109,6 +109,7 @@ function testRequiredFields() {
$form[$element]['#required'] = $required;
$form_state['input'][$element] = $empty;
$form_state['input']['form_id'] = $form_id;
$form_state['build_info']['callback_object'] = new StubForm($form_id, $form);
$form_state['method'] = 'post';
// The form token CSRF protection should not interfere with this test,
// so we bypass it by setting the token to FALSE.
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Form\StubForm.
*/
namespace Drupal\system\Tests\Form;
use Drupal\Core\Form\FormBase;
/**
* Provides a stub form for testing purposes.
*/
class StubForm extends FormBase {
/**
* The form array.
*
* @var array
*/
protected $form;
/**
* The form ID.
*
* @var string
*/
protected $formId;
/**
* Constructs a StubForm.
*
* @param string $form_id
* The form ID.
* @param array $form
* The form array.
*/
public function __construct($form_id, $form) {
$this->formId = $form_id;
$this->form = $form;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
$this->formId;
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
return $this->form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
}
}
......@@ -14,7 +14,7 @@
* some AJAX stuff automatically.
* This makes some assumptions about the client.
*/
function views_ajax_form_wrapper($form_id, &$form_state) {
function views_ajax_form_wrapper($form_class, &$form_state) {
// This won't override settings already in.
$form_state += array(
'rerender' => FALSE,
......@@ -25,7 +25,7 @@ function views_ajax_form_wrapper($form_id, &$form_state) {
),
);
$form = \Drupal::formBuilder()->buildForm($form_id, $form_state);
$form = \Drupal::formBuilder()->buildForm($form_class, $form_state);
$output = drupal_render($form);
// These forms have the title built in, so set the title here:
......
......@@ -128,7 +128,8 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
// before rendering the second time.
$drupal_add_js_original = _drupal_add_js();
$drupal_add_js = &drupal_static('_drupal_add_js');
$response = views_ajax_form_wrapper($form_state['form_id'], $form_state);
$form_class = get_class($form_state['build_info']['callback_object']);
$response = views_ajax_form_wrapper($form_class, $form_state);
// If the form has not been submitted, or was not set for rerendering, stop.
if (!$form_state['submitted'] || !empty($form_state['rerender'])) {
......@@ -151,7 +152,7 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
return new RedirectResponse(url($form_path, array('absolute' => TRUE)));
}
$form_state['path'] = $form_path;
$response = views_ajax_form_wrapper($form_state['form_id'], $form_state);
$response = views_ajax_form_wrapper($form_class, $form_state);
}
elseif (!$form_state['ajax']) {
// if nothing on the stack, non-js forms just go back to the main view editor.
......
......@@ -49,11 +49,6 @@ protected function setUp() {
* @covers ::getForm()
*/
public function testGetForm() {
$this->formBuilder->expects($this->once())
->method('buildForm')
->with('the_form_id', $this->isType('array'))
->will($this->returnValue('the form contents'));
$form_controller = $this->getMock('Drupal\Core\Entity\EntityFormInterface');
$form_controller->expects($this->any())
->method('getFormId')
......@@ -63,6 +58,11 @@ public function testGetForm() {
->with('the_entity_type', 'default')
->will($this->returnValue($form_controller));
$this->formBuilder->expects($this->once())
->method('buildForm')
->with($form_controller, $this->isType('array'))
->will($this->returnValue('the form contents'));
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
$entity->expects($this->once())
->method('getEntityTypeId')
......
......@@ -19,6 +19,9 @@ class FormBuilderTest extends FormTestBase {
/**
* Tests the getFormId() method with a string based form ID.
*
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The form argument foo is not a valid form.
*/
public function testGetFormIdWithString() {
$form_arg = 'foo';
......@@ -121,8 +124,6 @@ public function testHandleFormStateResponse($class, $form_state_key) {
}));
$form_state = array();
$this->formBuilder->getFormId($form_arg, $form_state);
try {
$form_state['values'] = array();
$form_state['input']['form_id'] = $form_id;
......@@ -177,8 +178,6 @@ public function testHandleRedirectWithResponse() {
}));
$form_state = array();
$this->formBuilder->getFormId($form_arg, $form_state);
try {
$form_state['values'] = array();
$form_state['input']['form_id'] = $form_id;
......@@ -190,8 +189,12 @@ public function testHandleRedirectWithResponse() {
}
$this->assertSame($response, $form_state['response']);
}
/**
* Tests the getForm() method with a string based form ID.
*
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The form argument test_form_id is not a valid form.
*/
public function testGetFormWithString() {
$form_id = 'test_form_id';
......@@ -233,6 +236,9 @@ public function testGetFormWithClassString() {
/**
* Tests the buildForm() method with a string based form ID.
*
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The form argument test_form_id is not a valid form.
*/
public function testBuildFormWithString() {
$form_id = 'test_form_id';
......@@ -318,7 +324,13 @@ public function testGetCache() {
// FormBuilder::buildForm() will be called twice, but the form object will
// only be called once due to caching.
$form_arg = $this->getMockForm($form_id, $expected_form, 1);
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->once())
->method('buildForm')
->will($this->returnValue($expected_form));
// The CSRF token is checked each time.
$this->csrfToken->expects($this->exactly(2))
......@@ -359,7 +371,7 @@ public function testGetCache() {
// use the form cache.
$form_state['input']['form_id'] = $form_id;
$form_state['input']['form_build_id'] = $form['#build_id'];
$this->formBuilder->buildForm($form_id, $form_state);
$this->formBuilder->buildForm($form_arg, $form_state);
$this->assertEmpty($form_state['errors']);
}
......@@ -394,6 +406,9 @@ public function testUniqueHtmlId() {
// Mock a form object that will be built two times.
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->exactly(2))
->method('buildForm')
->will($this->returnValue($expected_form));
......
......@@ -237,7 +237,7 @@ protected function simulateFormSubmission($form_id, FormInterface $form_arg, arr
$form_state['input']['op'] = 'Submit';
$form_state['programmed'] = $programmed;
$form_state['submitted'] = TRUE;
return $this->formBuilder->buildForm($form_id, $form_state);
return $this->formBuilder->buildForm($form_arg, $form_state);
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment