Issue #2309323 by Berdir, tim.plunkett: Allow #submit and #validate to be specified as methods of the form object.

8.0.x
webchick 2014-08-23 14:18:18 -07:00
parent 37586d9773
commit 6a6e601d4a
46 changed files with 164 additions and 115 deletions

View File

@ -138,7 +138,7 @@ class EntityForm extends FormBase implements EntityFormInterface {
$entity = $this->entity; $entity = $this->entity;
// Add a process callback. // Add a process callback.
$form['#process'][] = array($this, 'processForm'); $form['#process'][] = '::processForm';
if (!isset($form['langcode'])) { if (!isset($form['langcode'])) {
// If the form did not specify otherwise, default to keeping the existing // If the form did not specify otherwise, default to keeping the existing
@ -210,13 +210,8 @@ class EntityForm extends FormBase implements EntityFormInterface {
$actions['submit'] = array( $actions['submit'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Save'), '#value' => $this->t('Save'),
'#validate' => array( '#validate' => array('::validate'),
array($this, 'validate'), '#submit' => array('::submit', '::save'),
),
'#submit' => array(
array($this, 'submit'),
array($this, 'save'),
),
); );
if (!$this->entity->isNew() && $this->entity->hasLinkTemplate('delete-form')) { if (!$this->entity->isNew() && $this->entity->hasLinkTemplate('delete-form')) {
@ -317,11 +312,6 @@ class EntityForm extends FormBase implements EntityFormInterface {
*/ */
public function buildEntity(array $form, FormStateInterface $form_state) { public function buildEntity(array $form, FormStateInterface $form_state) {
$entity = clone $this->entity; $entity = clone $this->entity;
// If you submit a form, the form state comes from caching, which forces
// the form object to be the one before caching. Ensure to have the
// form object of the current request.
$form_state['controller'] = $this;
$this->copyFormValuesToEntity($entity, $form, $form_state); $this->copyFormValuesToEntity($entity, $form, $form_state);
// Invoke all specified builders for copying form values to entity // Invoke all specified builders for copying form values to entity

View File

@ -639,8 +639,8 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
$form += $this->getElementInfo('form'); $form += $this->getElementInfo('form');
$form += array('#tree' => FALSE, '#parents' => array()); $form += array('#tree' => FALSE, '#parents' => array());
$form['#validate'][] = array($form_state['build_info']['callback_object'], 'validateForm'); $form['#validate'][] = '::validateForm';
$form['#submit'][] = array($form_state['build_info']['callback_object'], 'submitForm'); $form['#submit'][] = '::submitForm';
// If no #theme has been set, automatically apply theme suggestions. // If no #theme has been set, automatically apply theme suggestions.
// theme_form() itself is in #theme_wrappers and not #theme. Therefore, the // theme_form() itself is in #theme_wrappers and not #theme. Therefore, the
@ -767,9 +767,9 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
// Allow for elements to expand to multiple elements, e.g., radios, // Allow for elements to expand to multiple elements, e.g., radios,
// checkboxes and files. // checkboxes and files.
if (isset($element['#process']) && !$element['#processed']) { if (isset($element['#process']) && !$element['#processed']) {
foreach ($element['#process'] as $process) { foreach ($element['#process'] as $callback) {
$complete_form = &$form_state->getCompleteForm(); $complete_form = &$form_state->getCompleteForm();
$element = call_user_func_array($process, array(&$element, &$form_state, &$complete_form)); $element = call_user_func_array($form_state->prepareCallback($callback), array(&$element, &$form_state, &$complete_form));
} }
$element['#processed'] = TRUE; $element['#processed'] = TRUE;
} }

View File

@ -796,6 +796,17 @@ class FormState implements FormStateInterface, \ArrayAccess {
return $this; return $this;
} }
/**
* {@inheritdoc}
*/
public function prepareCallback($callback) {
if (is_string($callback) && substr($callback, 0, 2) == '::') {
$callback = array($this->get('build_info')['callback_object'], substr($callback, 2));
}
return $callback;
}
/** /**
* Wraps drupal_set_message(). * Wraps drupal_set_message().
* *

View File

@ -456,4 +456,18 @@ interface FormStateInterface {
*/ */
public function setRebuild($rebuild = TRUE); public function setRebuild($rebuild = TRUE);
/**
* Converts support notations for a form callback to a valid callable.
*
* Specifically, supports methods on the form/callback object as strings when
* they start with ::, for example "::submitForm()".
*
* @param string|array $callback
* The callback.
*
* @return array|string
* A valid callable.
*/
public function prepareCallback($callback);
} }

View File

@ -105,7 +105,7 @@ class FormSubmitter implements FormSubmitterInterface {
$handlers = array(); $handlers = array();
} }
foreach ($handlers as $function) { foreach ($handlers as $callback) {
// Check if a previous _submit handler has set a batch, but make sure we // Check if a previous _submit handler has set a batch, but make sure we
// do not react to a batch that is already being processed (for instance // do not react to a batch that is already being processed (for instance
// if a batch operation performs a // if a batch operation performs a
@ -114,11 +114,11 @@ class FormSubmitter implements FormSubmitterInterface {
// Some previous submit handler has set a batch. To ensure correct // Some previous submit handler has set a batch. To ensure correct
// execution order, store the call in a special 'control' batch set. // execution order, store the call in a special 'control' batch set.
// See _batch_next_set(). // See _batch_next_set().
$batch['sets'][] = array('form_submit' => $function); $batch['sets'][] = array('form_submit' => $callback);
$batch['has_form_submits'] = TRUE; $batch['has_form_submits'] = TRUE;
} }
else { else {
call_user_func_array($function, array(&$form, &$form_state)); call_user_func_array($form_state->prepareCallback($callback), array(&$form, &$form_state));
} }
} }
} }

View File

@ -79,8 +79,8 @@ class FormValidator implements FormValidatorInterface {
$handlers = array(); $handlers = array();
} }
foreach ($handlers as $function) { foreach ($handlers as $callback) {
call_user_func_array($function, array(&$form, &$form_state)); call_user_func_array($form_state->prepareCallback($callback), array(&$form, &$form_state));
} }
} }
@ -263,7 +263,7 @@ class FormValidator implements FormValidatorInterface {
elseif (isset($elements['#element_validate'])) { elseif (isset($elements['#element_validate'])) {
foreach ($elements['#element_validate'] as $callback) { foreach ($elements['#element_validate'] as $callback) {
$complete_form = &$form_state->getCompleteForm(); $complete_form = &$form_state->getCompleteForm();
call_user_func_array($callback, array(&$elements, &$form_state, &$complete_form)); call_user_func_array($form_state->prepareCallback($callback), array(&$elements, &$form_state, &$complete_form));
} }
} }

View File

@ -104,7 +104,7 @@ class SiteSettingsForm extends FormBase {
array('driver'), array('driver'),
array($default_driver), array($default_driver),
), ),
'#submit' => array(array($this, 'submitForm')), '#submit' => array('::submitForm'),
); );
$form['errors'] = array(); $form['errors'] = array();

View File

@ -101,7 +101,7 @@ class BlockForm extends EntityForm {
'#title' => t('Theme'), '#title' => t('Theme'),
'#default_value' => $theme, '#default_value' => $theme,
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'themeSwitch'), 'callback' => '::themeSwitch',
'wrapper' => 'edit-block-region-wrapper', 'wrapper' => 'edit-block-region-wrapper',
), ),
); );

View File

@ -244,13 +244,8 @@ class CommentForm extends ContentEntityForm {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Preview'), '#value' => $this->t('Preview'),
'#access' => $preview_mode != DRUPAL_DISABLED, '#access' => $preview_mode != DRUPAL_DISABLED,
'#validate' => array( '#validate' => array('::validate'),
array($this, 'validate'), '#submit' => array('::submit', '::preview'),
),
'#submit' => array(
array($this, 'submit'),
array($this, 'preview'),
),
); );
return $element; return $element;

View File

@ -95,7 +95,7 @@ class ConfigSingleExportForm extends FormBase {
'#options' => $config_types, '#options' => $config_types,
'#default_value' => $config_type, '#default_value' => $config_type,
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'updateConfigurationType'), 'callback' => '::updateConfigurationType',
'wrapper' => 'edit-config-type-wrapper', 'wrapper' => 'edit-config-type-wrapper',
), ),
); );
@ -109,7 +109,7 @@ class ConfigSingleExportForm extends FormBase {
'#prefix' => '<div id="edit-config-type-wrapper">', '#prefix' => '<div id="edit-config-type-wrapper">',
'#suffix' => '</div>', '#suffix' => '</div>',
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'updateExport'), 'callback' => '::updateExport',
'wrapper' => 'edit-export-wrapper', 'wrapper' => 'edit-export-wrapper',
), ),
); );

View File

@ -156,13 +156,8 @@ class MessageForm extends ContentEntityForm {
$elements['submit']['#value'] = $this->t('Send message'); $elements['submit']['#value'] = $this->t('Send message');
$elements['preview'] = array( $elements['preview'] = array(
'#value' => $this->t('Preview'), '#value' => $this->t('Preview'),
'#validate' => array( '#validate' => array('::validate'),
array($this, 'validate'), '#submit' => array('::submit', '::preview'),
),
'#submit' => array(
array($this, 'submit'),
array($this, 'preview'),
),
); );
return $elements; return $elements;
} }

View File

@ -59,7 +59,7 @@ class DblogFilterForm extends FormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Reset'), '#value' => $this->t('Reset'),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'resetForm')), '#submit' => array('::resetForm'),
); );
} }
return $form; return $form;

View File

@ -189,7 +189,7 @@ class EditorImageDialog extends FormBase {
// No regular submit-handler. This form only works via JavaScript. // No regular submit-handler. This form only works via JavaScript.
'#submit' => array(), '#submit' => array(),
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'submitForm'), 'callback' => '::submitForm',
'event' => 'click', 'event' => 'click',
), ),
); );

View File

@ -69,7 +69,7 @@ class EditorLinkDialog extends FormBase {
// No regular submit-handler. This form only works via JavaScript. // No regular submit-handler. This form only works via JavaScript.
'#submit' => array(), '#submit' => array(),
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'submitForm'), 'callback' => '::submitForm',
'event' => 'click', 'event' => 'click',
), ),
); );

View File

@ -157,7 +157,7 @@ class FieldInstanceEditForm extends FormBase {
$form['actions']['delete'] = array( $form['actions']['delete'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Delete field'), '#value' => $this->t('Delete field'),
'#submit' => array(array($this, 'delete')), '#submit' => array('::delete'),
); );
return $form; return $form;
} }

View File

@ -99,7 +99,7 @@ class Overview extends OverviewTerms {
// The form needs to have submit and validate handlers set explicitly. // The form needs to have submit and validate handlers set explicitly.
// Use the existing taxonomy overview submit handler. // Use the existing taxonomy overview submit handler.
$form['#submit'] = array(array($this, 'submitForm')); $form['#submit'] = array('::submitForm');
$form['terms']['#empty'] = $this->t('No containers or forums available. <a href="@container">Add container</a> or <a href="@forum">Add forum</a>.', array( $form['terms']['#empty'] = $this->t('No containers or forums available. <a href="@container">Add container</a> or <a href="@forum">Add forum</a>.', array(
'@container' => $this->url('forum.add_container'), '@container' => $this->url('forum.add_container'),
'@forum' => $this->url('forum.add_forum') '@forum' => $this->url('forum.add_forum')

View File

@ -49,8 +49,8 @@ class LanguageAddForm extends LanguageFormBase {
'select#edit-predefined-langcode' => array('value' => 'custom'), 'select#edit-predefined-langcode' => array('value' => 'custom'),
), ),
), ),
'#validate' => array(array($this, 'validatePredefined')), '#validate' => array('::validatePredefined'),
'#submit' => array(array($this, 'submitForm')), '#submit' => array('::submitForm'),
); );
$custom_language_states_conditions = array( $custom_language_states_conditions = array(
@ -72,8 +72,8 @@ class LanguageAddForm extends LanguageFormBase {
$form['custom_language']['submit'] = array( $form['custom_language']['submit'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Add custom language'), '#value' => $this->t('Add custom language'),
'#validate' => array(array($this, 'validateCustom')), '#validate' => array('::validateCustom'),
'#submit' => array(array($this, 'submitForm')), '#submit' => array('::submitForm'),
); );
return $form; return $form;

View File

@ -38,8 +38,8 @@ class LanguageEditForm extends LanguageFormBase {
$actions['submit'] = array( $actions['submit'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Save language'), '#value' => $this->t('Save language'),
'#validate' => array(array($this, 'validateCommon')), '#validate' => array('::validateCommon'),
'#submit' => array(array($this, 'submitForm')), '#submit' => array('::submitForm'),
); );
return $actions; return $actions;
} }

View File

@ -74,7 +74,7 @@ class TranslateFilterForm extends TranslateFormBase {
$form['filters']['actions']['reset'] = array( $form['filters']['actions']['reset'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Reset'), '#value' => $this->t('Reset'),
'#submit' => array(array($this, 'resetForm')), '#submit' => array('::resetForm'),
); );
} }

View File

@ -288,7 +288,7 @@ class NodeForm extends ContentEntityForm {
$element['publish']['#value'] = $node->isPublished() ? t('Save and keep published') : t('Save and publish'); $element['publish']['#value'] = $node->isPublished() ? t('Save and keep published') : t('Save and publish');
} }
$element['publish']['#weight'] = 0; $element['publish']['#weight'] = 0;
array_unshift($element['publish']['#submit'], array($this, 'publish')); array_unshift($element['publish']['#submit'], '::publish');
// Add a "Unpublish" button. // Add a "Unpublish" button.
$element['unpublish'] = $element['submit']; $element['unpublish'] = $element['submit'];
@ -300,7 +300,7 @@ class NodeForm extends ContentEntityForm {
$element['unpublish']['#value'] = !$node->isPublished() ? t('Save and keep unpublished') : t('Save and unpublish'); $element['unpublish']['#value'] = !$node->isPublished() ? t('Save and keep unpublished') : t('Save and unpublish');
} }
$element['unpublish']['#weight'] = 10; $element['unpublish']['#weight'] = 10;
array_unshift($element['unpublish']['#submit'], array($this, 'unpublish')); array_unshift($element['unpublish']['#submit'], '::unpublish');
// If already published, the 'publish' button is primary. // If already published, the 'publish' button is primary.
if ($node->isPublished()) { if ($node->isPublished()) {
@ -321,13 +321,8 @@ class NodeForm extends ContentEntityForm {
'#access' => $preview_mode != DRUPAL_DISABLED && ($node->access('create') || $node->access('update')), '#access' => $preview_mode != DRUPAL_DISABLED && ($node->access('create') || $node->access('update')),
'#value' => t('Preview'), '#value' => t('Preview'),
'#weight' => 20, '#weight' => 20,
'#validate' => array( '#validate' => array('::validate'),
array($this, 'validate'), '#submit' => array('::submit', '::preview'),
),
'#submit' => array(
array($this, 'submit'),
array($this, 'preview'),
),
); );
$element['delete']['#access'] = $node->access('delete'); $element['delete']['#access'] = $node->access('delete');

View File

@ -44,7 +44,7 @@ class EditForm extends PathFormBase {
$form['actions']['delete'] = array( $form['actions']['delete'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Delete'), '#value' => $this->t('Delete'),
'#submit' => array(array($this, 'deleteSubmit')), '#submit' => array('::deleteSubmit'),
); );
return $form; return $form;
} }

View File

@ -50,7 +50,7 @@ class PathFilterForm extends FormBase {
$form['basic']['reset'] = array( $form['basic']['reset'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Reset'), '#value' => $this->t('Reset'),
'#submit' => array(array($this, 'resetForm')), '#submit' => array('::resetForm'),
); );
} }
return $form; return $form;

View File

@ -185,7 +185,7 @@ class SearchPageListBuilder extends DraggableListBuilder implements FormInterfac
$form['status']['wipe'] = array( $form['status']['wipe'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Re-index site'), '#value' => $this->t('Re-index site'),
'#submit' => array(array($this, 'searchAdminReindexSubmit')), '#submit' => array('::searchAdminReindexSubmit'),
); );
$items = array(10, 20, 50, 100, 200, 500); $items = array(10, 20, 50, 100, 200, 500);
@ -271,8 +271,8 @@ class SearchPageListBuilder extends DraggableListBuilder implements FormInterfac
$form['search_pages']['add_page']['add_search_submit'] = array( $form['search_pages']['add_page']['add_search_submit'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Add new page'), '#value' => $this->t('Add new page'),
'#validate' => array(array($this, 'validateAddSearchPage')), '#validate' => array('::validateAddSearchPage'),
'#submit' => array(array($this, 'submitAddSearchPage')), '#submit' => array('::submitAddSearchPage'),
'#limit_validation_errors' => array(array('search_type')), '#limit_validation_errors' => array(array('search_type')),
); );

View File

@ -89,10 +89,7 @@ class SetCustomize extends EntityForm {
'submit' => array( 'submit' => array(
'#value' => t('Save changes'), '#value' => t('Save changes'),
'#access' => (bool) Element::getVisibleChildren($form['shortcuts']['links']), '#access' => (bool) Element::getVisibleChildren($form['shortcuts']['links']),
'#submit' => array( '#submit' => array('::submit', '::save'),
array($this, 'submit'),
array($this, 'save'),
),
), ),
); );
} }

View File

@ -72,9 +72,11 @@ class FormAjaxController implements ContainerInjectionInterface {
// up to the #ajax['callback'] function of the element (may or may not be a // up to the #ajax['callback'] function of the element (may or may not be a
// button) that triggered the Ajax request to determine what needs to be // button) that triggered the Ajax request to determine what needs to be
// rendered. // rendered.
$callback = NULL;
if (!empty($form_state['triggering_element'])) { if (!empty($form_state['triggering_element'])) {
$callback = $form_state['triggering_element']['#ajax']['callback']; $callback = $form_state['triggering_element']['#ajax']['callback'];
} }
$callback = $form_state->prepareCallback($callback);
if (empty($callback) || !is_callable($callback)) { if (empty($callback) || !is_callable($callback)) {
throw new HttpException(500, t('Internal Server Error')); throw new HttpException(500, t('Internal Server Error'));
} }

View File

@ -92,7 +92,7 @@ class CronForm extends ConfigFormBase {
$form['run'] = array( $form['run'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => t('Run cron'), '#value' => t('Run cron'),
'#submit' => array(array($this, 'submitCron')), '#submit' => array('::submitCron'),
); );
$status = '<p>' . t('Last run: %cron-last ago.', array('%cron-last' => $this->dateFormatter->formatInterval(REQUEST_TIME - $this->state->get('system.cron_last')))) . '</p>'; $status = '<p>' . t('Last run: %cron-last ago.', array('%cron-last' => $this->dateFormatter->formatInterval(REQUEST_TIME - $this->state->get('system.cron_last')))) . '</p>';

View File

@ -135,7 +135,7 @@ abstract class DateFormatFormBase extends EntityForm {
'#default_value' => '', '#default_value' => '',
'#field_suffix' => ' <small id="edit-date-format-suffix"></small>', '#field_suffix' => ' <small id="edit-date-format-suffix"></small>',
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'dateTimeLookup'), 'callback' => '::dateTimeLookup',
'event' => 'keyup', 'event' => 'keyup',
'progress' => array('type' => 'throbber', 'message' => NULL), 'progress' => array('type' => 'throbber', 'message' => NULL),
), ),

View File

@ -107,7 +107,7 @@ class PerformanceForm extends ConfigFormBase {
$form['clear_cache']['clear'] = array( $form['clear_cache']['clear'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => t('Clear all caches'), '#value' => t('Clear all caches'),
'#submit' => array(array($this, 'submitCacheClear')), '#submit' => array('::submitCacheClear'),
); );
$form['caching'] = array( $form['caching'] = array(

View File

@ -37,8 +37,8 @@ class FormDefaultHandlersTest extends KernelTestBase implements FormInterface {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildForm(array $form, FormStateInterface $form_state) { public function buildForm(array $form, FormStateInterface $form_state) {
$form['#validate'][] = array($this, 'customValidateForm'); $form['#validate'][] = '::customValidateForm';
$form['#submit'][] = array($this, 'customSubmitForm'); $form['#submit'][] = '::customSubmitForm';
$form['submit'] = array('#type' => 'submit', '#value' => 'Save'); $form['submit'] = array('#type' => 'submit', '#value' => 'Save');
return $form; return $form;
} }

View File

@ -42,7 +42,7 @@ class AjaxTestDialogForm extends FormBase {
'#name' => 'button1', '#name' => 'button1',
'#value' => 'Button 1 (modal)', '#value' => 'Button 1 (modal)',
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'modal'), 'callback' => '::modal',
), ),
); );
$form['button2'] = array( $form['button2'] = array(
@ -50,7 +50,7 @@ class AjaxTestDialogForm extends FormBase {
'#name' => 'button2', '#name' => 'button2',
'#value' => 'Button 2 (non-modal)', '#value' => 'Button 2 (non-modal)',
'#ajax' => array( '#ajax' => array(
'callback' => array($this, 'nonModal'), 'callback' => '::nonModal',
), ),
); );

View File

@ -35,7 +35,7 @@ class FormTestLimitValidationErrorsForm extends FormBase {
$form['test'] = array( $form['test'] = array(
'#title' => 'Test', '#title' => 'Test',
'#type' => 'textfield', '#type' => 'textfield',
'#element_validate' => array(array($this, 'elementValidateLimitValidationErrors')), '#element_validate' => array('::elementValidateLimitValidationErrors'),
); );
$form['test_numeric_index'] = array( $form['test_numeric_index'] = array(
'#tree' => TRUE, '#tree' => TRUE,
@ -43,7 +43,7 @@ class FormTestLimitValidationErrorsForm extends FormBase {
$form['test_numeric_index'][0] = array( $form['test_numeric_index'][0] = array(
'#title' => 'Test (numeric index)', '#title' => 'Test (numeric index)',
'#type' => 'textfield', '#type' => 'textfield',
'#element_validate' => array(array($this, 'elementValidateLimitValidationErrors')), '#element_validate' => array('::elementValidateLimitValidationErrors'),
); );
$form['test_substring'] = array( $form['test_substring'] = array(
@ -52,30 +52,30 @@ class FormTestLimitValidationErrorsForm extends FormBase {
$form['test_substring']['foo'] = array( $form['test_substring']['foo'] = array(
'#title' => 'Test (substring) foo', '#title' => 'Test (substring) foo',
'#type' => 'textfield', '#type' => 'textfield',
'#element_validate' => array(array($this, 'elementValidateLimitValidationErrors')), '#element_validate' => array('::elementValidateLimitValidationErrors'),
); );
$form['test_substring']['foobar'] = array( $form['test_substring']['foobar'] = array(
'#title' => 'Test (substring) foobar', '#title' => 'Test (substring) foobar',
'#type' => 'textfield', '#type' => 'textfield',
'#element_validate' => array(array($this, 'elementValidateLimitValidationErrors')), '#element_validate' => array('::elementValidateLimitValidationErrors'),
); );
$form['actions']['partial'] = array( $form['actions']['partial'] = array(
'#type' => 'submit', '#type' => 'submit',
'#limit_validation_errors' => array(array('test')), '#limit_validation_errors' => array(array('test')),
'#submit' => array(array($this, 'partialSubmitForm')), '#submit' => array('::partialSubmitForm'),
'#value' => t('Partial validate'), '#value' => t('Partial validate'),
); );
$form['actions']['partial_numeric_index'] = array( $form['actions']['partial_numeric_index'] = array(
'#type' => 'submit', '#type' => 'submit',
'#limit_validation_errors' => array(array('test_numeric_index', 0)), '#limit_validation_errors' => array(array('test_numeric_index', 0)),
'#submit' => array(array($this, 'partialSubmitForm')), '#submit' => array('::partialSubmitForm'),
'#value' => t('Partial validate (numeric index)'), '#value' => t('Partial validate (numeric index)'),
); );
$form['actions']['substring'] = array( $form['actions']['substring'] = array(
'#type' => 'submit', '#type' => 'submit',
'#limit_validation_errors' => array(array('test_substring', 'foo')), '#limit_validation_errors' => array(array('test_substring', 'foo')),
'#submit' => array(array($this, 'partialSubmitForm')), '#submit' => array('::partialSubmitForm'),
'#value' => t('Partial validate (substring)'), '#value' => t('Partial validate (substring)'),
); );
$form['actions']['full'] = array( $form['actions']['full'] = array(

View File

@ -74,7 +74,7 @@ class FormTestProgrammaticForm extends FormBase {
// Use the same submit handler for this button as for the form itself. // Use the same submit handler for this button as for the form itself.
// (This must be set explicitly or otherwise the form API will ignore the // (This must be set explicitly or otherwise the form API will ignore the
// #limit_validation_errors property.) // #limit_validation_errors property.)
'#submit' => array(array($this, 'submitForm')), '#submit' => array('::submitForm'),
); );
$user_input = $form_state->getUserInput(); $user_input = $form_state->getUserInput();
if (!empty($user_input['field_to_validate']) && $user_input['field_to_validate'] != 'all') { if (!empty($user_input['field_to_validate']) && $user_input['field_to_validate'] != 'all') {

View File

@ -53,7 +53,7 @@ class FormTestRebuildPreserveValuesForm extends FormBase {
$form['add_more'] = array( $form['add_more'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => 'Add more', '#value' => 'Add more',
'#submit' => array(array($this, 'addMoreSubmitForm')), '#submit' => array('::addMoreSubmitForm'),
); );
} }
else { else {

View File

@ -63,7 +63,7 @@ class FormTestStorageForm extends FormBase {
'#type' => 'textfield', '#type' => 'textfield',
'#title' => 'Value', '#title' => 'Value',
'#default_value' => $form_state['storage']['thing']['value'], '#default_value' => $form_state['storage']['thing']['value'],
'#element_validate' => array(array($this, 'elementValidateValueCached')), '#element_validate' => array('::elementValidateValueCached'),
); );
$form['continue_button'] = array( $form['continue_button'] = array(
'#type' => 'button', '#type' => 'button',
@ -73,7 +73,7 @@ class FormTestStorageForm extends FormBase {
$form['continue_submit'] = array( $form['continue_submit'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => 'Continue submit', '#value' => 'Continue submit',
'#submit' => array(array($this, 'continueSubmitForm')), '#submit' => array('::continueSubmitForm'),
); );
$form['submit'] = array( $form['submit'] = array(
'#type' => 'submit', '#type' => 'submit',

View File

@ -27,7 +27,7 @@ class FormTestValidateRequiredForm extends FormBase {
*/ */
public function buildForm(array $form, FormStateInterface $form_state) { public function buildForm(array $form, FormStateInterface $form_state) {
$options = array('foo' => 'foo', 'bar' => 'bar'); $options = array('foo' => 'foo', 'bar' => 'bar');
$validate = array(array($this, 'elementValidateRequired')); $validate = array('::elementValidateRequired');
$form['textfield'] = array( $form['textfield'] = array(
'#type' => 'textfield', '#type' => 'textfield',

View File

@ -339,7 +339,7 @@ class OverviewTerms extends FormBase {
); );
$form['actions']['reset_alphabetical'] = array( $form['actions']['reset_alphabetical'] = array(
'#type' => 'submit', '#type' => 'submit',
'#submit' => array(array($this, 'submitReset')), '#submit' => array('::submitReset'),
'#value' => $this->t('Reset to alphabetical'), '#value' => $this->t('Reset to alphabetical'),
); );
} }

View File

@ -97,7 +97,7 @@ class VocabularyForm extends EntityForm {
// the submit button has custom submit handlers. // the submit button has custom submit handlers.
if ($this->moduleHandler->moduleExists('language')) { if ($this->moduleHandler->moduleExists('language')) {
array_unshift($actions['submit']['#submit'], 'language_configuration_element_submit'); array_unshift($actions['submit']['#submit'], 'language_configuration_element_submit');
array_unshift($actions['submit']['#submit'], array($this, 'languageConfigurationSubmit')); array_unshift($actions['submit']['#submit'], '::languageConfigurationSubmit');
} }
// We cannot leverage the regular submit handler definition because we // We cannot leverage the regular submit handler definition because we
// have button-specific ones here. Hence we need to explicitly set it for // have button-specific ones here. Hence we need to explicitly set it for

View File

@ -105,9 +105,9 @@ class UserLoginForm extends FormBase {
$form['actions'] = array('#type' => 'actions'); $form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Log in')); $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Log in'));
$form['#validate'][] = array($this, 'validateName'); $form['#validate'][] = '::validateName';
$form['#validate'][] = array($this, 'validateAuthentication'); $form['#validate'][] = '::validateAuthentication';
$form['#validate'][] = array($this, 'validateFinal'); $form['#validate'][] = '::validateFinal';
return $form; return $form;
} }

View File

@ -37,7 +37,7 @@ class ProfileForm extends AccountForm {
$user = $this->currentUser(); $user = $this->currentUser();
$element['delete']['#type'] = 'submit'; $element['delete']['#type'] = 'submit';
$element['delete']['#value'] = $this->t('Cancel account'); $element['delete']['#value'] = $this->t('Cancel account');
$element['delete']['#submit'] = array(array($this, 'editCancelSubmit')); $element['delete']['#submit'] = array('::editCancelSubmit');
$element['delete']['#access'] = $account->id() > 1 && (($account->id() == $user->id() && $user->hasPermission('cancel account')) || $user->hasPermission('administer users')); $element['delete']['#access'] = $account->id() > 1 && (($account->id() == $user->id() && $user->hasPermission('cancel account')) || $user->hasPermission('administer users'));
return $element; return $element;

View File

@ -46,7 +46,7 @@ class AdvancedSettingsForm extends ConfigFormBase {
$form['cache']['clear_cache'] = array( $form['cache']['clear_cache'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t("Clear Views' cache"), '#value' => $this->t("Clear Views' cache"),
'#submit' => array(array($this, 'cacheSubmit')), '#submit' => array('::cacheSubmit'),
); );
$form['debug'] = array( $form['debug'] = array(

View File

@ -153,9 +153,7 @@ class ViewAddForm extends ViewFormBase {
$actions['cancel'] = array( $actions['cancel'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Cancel'), '#value' => $this->t('Cancel'),
'#submit' => array( '#submit' => array('::cancel'),
array($this, 'cancel'),
),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
); );
return $actions; return $actions;

View File

@ -58,9 +58,7 @@ class ViewDuplicateForm extends ViewFormBase {
$actions['submit'] = array( $actions['submit'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Duplicate'), '#value' => $this->t('Duplicate'),
'#submit' => array( '#submit' => array('::submit'),
array($this, 'submit'),
),
); );
return $actions; return $actions;
} }

View File

@ -240,9 +240,7 @@ class ViewEditForm extends ViewFormBase {
$actions['cancel'] = array( $actions['cancel'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Cancel'), '#value' => $this->t('Cancel'),
'#submit' => array( '#submit' => array('::cancel'),
array($this, 'cancel'),
),
); );
if ($this->entity->isLocked()) { if ($this->entity->isLocked()) {
$actions['submit']['#access'] = FALSE; $actions['submit']['#access'] = FALSE;
@ -418,7 +416,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Enable !display_title', array('!display_title' => $display_title)), '#value' => $this->t('Enable !display_title', array('!display_title' => $display_title)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDisplayEnable'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDisplayEnable', '::submitDelayDestination'),
'#prefix' => '<li class="enable">', '#prefix' => '<li class="enable">',
"#suffix" => '</li>', "#suffix" => '</li>',
); );
@ -443,7 +441,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Duplicate !display_title', array('!display_title' => $display_title)), '#value' => $this->t('Duplicate !display_title', array('!display_title' => $display_title)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDisplayDuplicate'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDisplayDuplicate', '::submitDelayDestination'),
'#prefix' => '<li class="duplicate">', '#prefix' => '<li class="duplicate">',
"#suffix" => '</li>', "#suffix" => '</li>',
); );
@ -453,7 +451,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Delete !display_title', array('!display_title' => $display_title)), '#value' => $this->t('Delete !display_title', array('!display_title' => $display_title)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDisplayDelete'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDisplayDelete', '::submitDelayDestination'),
'#prefix' => '<li class="delete">', '#prefix' => '<li class="delete">',
"#suffix" => '</li>', "#suffix" => '</li>',
); );
@ -467,7 +465,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Duplicate as !type', array('!type' => $label)), '#value' => $this->t('Duplicate as !type', array('!type' => $label)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDuplicateDisplayAsType'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDuplicateDisplayAsType', '::submitDelayDestination'),
'#prefix' => '<li class="duplicate">', '#prefix' => '<li class="duplicate">',
'#suffix' => '</li>', '#suffix' => '</li>',
); );
@ -478,7 +476,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Undo delete of !display_title', array('!display_title' => $display_title)), '#value' => $this->t('Undo delete of !display_title', array('!display_title' => $display_title)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDisplayUndoDelete'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDisplayUndoDelete', '::submitDelayDestination'),
'#prefix' => '<li class="undo-delete">', '#prefix' => '<li class="undo-delete">',
"#suffix" => '</li>', "#suffix" => '</li>',
); );
@ -488,7 +486,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Disable !display_title', array('!display_title' => $display_title)), '#value' => $this->t('Disable !display_title', array('!display_title' => $display_title)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDisplayDisable'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDisplayDisable', '::submitDelayDestination'),
'#prefix' => '<li class="disable">', '#prefix' => '<li class="disable">',
"#suffix" => '</li>', "#suffix" => '</li>',
); );
@ -760,7 +758,7 @@ class ViewEditForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Add !display', array('!display' => $label)), '#value' => $this->t('Add !display', array('!display' => $label)),
'#limit_validation_errors' => array(), '#limit_validation_errors' => array(),
'#submit' => array(array($this, 'submitDisplayAdd'), array($this, 'submitDelayDestination')), '#submit' => array('::submitDisplayAdd', '::submitDelayDestination'),
'#attributes' => array('class' => array('add-display')), '#attributes' => array('class' => array('add-display')),
// Allow JavaScript to remove the 'Add ' prefix from the button label when // Allow JavaScript to remove the 'Add ' prefix from the button label when
// placing the button in a "Add" dropdown menu. // placing the button in a "Add" dropdown menu.

View File

@ -112,7 +112,7 @@ class ViewPreviewForm extends ViewFormBase {
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->t('Update preview'), '#value' => $this->t('Update preview'),
'#attributes' => array('class' => array('arguments-preview')), '#attributes' => array('class' => array('arguments-preview')),
'#submit' => array(array($this, 'submitPreview')), '#submit' => array('::submitPreview'),
'#id' => 'preview-submit', '#id' => 'preview-submit',
'#ajax' => array( '#ajax' => array(
'path' => 'admin/structure/views/view/' . $view->id() . '/preview/' . $this->displayID, 'path' => 'admin/structure/views/view/' . $view->id() . '/preview/' . $this->displayID,

View File

@ -7,7 +7,9 @@
namespace Drupal\Tests\Core\Form; namespace Drupal\Tests\Core\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
@ -218,6 +220,38 @@ class FormStateTest extends UnitTestCase {
$this->assertSame($expected, $form_state->getValues()); $this->assertSame($expected, $form_state->getValues());
} }
/**
* @covers ::prepareCallback()
*/
public function testPrepareCallbackValidMethod() {
$form_state = new FormState();
$form_state['build_info']['callback_object'] = new PrepareCallbackTestForm();
$processed_callback = $form_state->prepareCallback('::buildForm');
$this->assertEquals(array($form_state['build_info']['callback_object'], 'buildForm'), $processed_callback);
}
/**
* @covers ::prepareCallback()
*/
public function testPrepareCallbackInValidMethod() {
$form_state = new FormState();
$form_state['build_info']['callback_object'] = new PrepareCallbackTestForm();
$processed_callback = $form_state->prepareCallback('not_a_method');
// The callback was not changed as no such method exists.
$this->assertEquals('not_a_method', $processed_callback);
}
/**
* @covers ::prepareCallback()
*/
public function testPrepareCallbackArray() {
$form_state = new FormState();
$form_state['build_info']['callback_object'] = new PrepareCallbackTestForm();
$callback = array($form_state['build_info']['callback_object'], 'buildForm');
$processed_callback = $form_state->prepareCallback($callback);
$this->assertEquals($callback, $processed_callback);
}
public function providerTestSetValue() { public function providerTestSetValue() {
$data = array(); $data = array();
$data[] = array( $data[] = array(
@ -315,3 +349,16 @@ class FormStateTest extends UnitTestCase {
} }
} }
/**
* A test form used for the prepareCallback() tests.
*/
class PrepareCallbackTestForm implements FormInterface {
public function getFormId() {
return 'test_form';
}
public function buildForm(array $form, FormStateInterface $form_state) {}
public function validateForm(array &$form, FormStateInterface $form_state) { }
public function submitForm(array &$form, FormStateInterface $form_state) { }
}

View File

@ -202,13 +202,16 @@ class FormSubmitterTest extends UnitTestCase {
*/ */
public function testExecuteSubmitHandlers() { public function testExecuteSubmitHandlers() {
$form_submitter = $this->getFormSubmitter(); $form_submitter = $this->getFormSubmitter();
$mock = $this->getMock('stdClass', array('submit_handler', 'hash_submit')); $mock = $this->getMock('stdClass', array('submit_handler', 'hash_submit', 'simple_string_submit'));
$mock->expects($this->once()) $mock->expects($this->once())
->method('submit_handler') ->method('submit_handler')
->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface')); ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
$mock->expects($this->once()) $mock->expects($this->once())
->method('hash_submit') ->method('hash_submit')
->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface')); ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
$mock->expects($this->once())
->method('simple_string_submit')
->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
$form = array(); $form = array();
$form_state = new FormState(); $form_state = new FormState();
@ -220,6 +223,12 @@ class FormSubmitterTest extends UnitTestCase {
// $form_state submit handlers will supersede $form handlers. // $form_state submit handlers will supersede $form handlers.
$form_state['submit_handlers'][] = array($mock, 'submit_handler'); $form_state['submit_handlers'][] = array($mock, 'submit_handler');
$form_submitter->executeSubmitHandlers($form, $form_state); $form_submitter->executeSubmitHandlers($form, $form_state);
// Methods directly on the form object can be specified as a string.
$form_state = new FormState();
$form_state['build_info']['callback_object'] = $mock;
$form_state['submit_handlers'][] = '::simple_string_submit';
$form_submitter->executeSubmitHandlers($form, $form_state);
} }
/** /**