Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
project
drupal
Commits
ee6ddbe8
Commit
ee6ddbe8
authored
Sep 10, 2014
by
alexpott
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue
#2332389
by tim.plunkett: Finish adding methods to FormStateInterface.
parent
fe85f9be
Changes
34
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1323 additions
and
425 deletions
+1323
-425
core/includes/install.core.inc
core/includes/install.core.inc
+4
-7
core/lib/Drupal/Core/Block/BlockBase.php
core/lib/Drupal/Core/Block/BlockBase.php
+4
-6
core/lib/Drupal/Core/Entity/EntityFormBuilder.php
core/lib/Drupal/Core/Entity/EntityFormBuilder.php
+1
-5
core/lib/Drupal/Core/Form/BaseFormIdInterface.php
core/lib/Drupal/Core/Form/BaseFormIdInterface.php
+1
-1
core/lib/Drupal/Core/Form/FormBuilder.php
core/lib/Drupal/Core/Form/FormBuilder.php
+78
-68
core/lib/Drupal/Core/Form/FormBuilderInterface.php
core/lib/Drupal/Core/Form/FormBuilderInterface.php
+11
-11
core/lib/Drupal/Core/Form/FormCache.php
core/lib/Drupal/Core/Form/FormCache.php
+7
-5
core/lib/Drupal/Core/Form/FormState.php
core/lib/Drupal/Core/Form/FormState.php
+454
-107
core/lib/Drupal/Core/Form/FormStateInterface.php
core/lib/Drupal/Core/Form/FormStateInterface.php
+498
-20
core/lib/Drupal/Core/Form/FormSubmitter.php
core/lib/Drupal/Core/Form/FormSubmitter.php
+7
-12
core/lib/Drupal/Core/Form/FormValidator.php
core/lib/Drupal/Core/Form/FormValidator.php
+22
-25
core/lib/Drupal/Core/Form/FormValidatorInterface.php
core/lib/Drupal/Core/Form/FormValidatorInterface.php
+1
-1
core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php
...ests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php
+4
-1
core/modules/block/src/BlockForm.php
core/modules/block/src/BlockForm.php
+2
-6
core/modules/config/src/Form/ConfigSingleExportForm.php
core/modules/config/src/Form/ConfigSingleExportForm.php
+2
-2
core/modules/image/src/Form/ImageEffectFormBase.php
core/modules/image/src/Form/ImageEffectFormBase.php
+2
-6
core/modules/menu_ui/src/MenuForm.php
core/modules/menu_ui/src/MenuForm.php
+4
-1
core/modules/quickedit/src/QuickEditController.php
core/modules/quickedit/src/QuickEditController.php
+4
-7
core/modules/simpletest/src/Form/SimpletestResultsForm.php
core/modules/simpletest/src/Form/SimpletestResultsForm.php
+1
-1
core/modules/system/src/Tests/Element/PathElementFormTest.php
.../modules/system/src/Tests/Element/PathElementFormTest.php
+9
-12
core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php
...modules/system/src/Tests/Form/FormDefaultHandlersTest.php
+1
-1
core/modules/system/src/Tests/Form/ProgrammaticTest.php
core/modules/system/src/Tests/Form/ProgrammaticTest.php
+3
-3
core/modules/system/src/Tests/System/SystemConfigFormTestBase.php
...ules/system/src/Tests/System/SystemConfigFormTestBase.php
+1
-1
core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php
...modules/batch_test/src/Controller/BatchTestController.php
+3
-3
core/modules/views/includes/ajax.inc
core/modules/views/includes/ajax.inc
+8
-6
core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
...s/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
+9
-8
core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php
...dules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php
+2
-2
core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
+10
-14
core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
+17
-18
core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
+1
-1
core/tests/Drupal/Tests/Core/Form/FormStateTest.php
core/tests/Drupal/Tests/Core/Form/FormStateTest.php
+118
-25
core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
+13
-15
core/tests/Drupal/Tests/Core/Form/FormTestBase.php
core/tests/Drupal/Tests/Core/Form/FormTestBase.php
+7
-10
core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
+14
-14
No files found.
core/includes/install.core.inc
View file @
ee6ddbe8
...
...
@@ -806,12 +806,9 @@ function install_tasks_to_display($install_state) {
function
install_get_form
(
$form_id
,
array
&
$install_state
)
{
// Ensure the form will not redirect, since install_run_tasks() uses a custom
// redirection logic.
$form_state
=
new
FormState
(
array
(
'build_info'
=>
array
(
'args'
=>
array
(
&
$install_state
),
),
'no_redirect'
=>
TRUE
,
));
$form_state
=
(
new
FormState
())
->
addBuildInfo
(
'args'
,
[
&
$install_state
])
->
disableRedirect
();
$form_builder
=
\
Drupal
::
formBuilder
();
if
(
$install_state
[
'interactive'
])
{
$form
=
$form_builder
->
buildForm
(
$form_id
,
$form_state
);
...
...
@@ -827,7 +824,7 @@ function install_get_form($form_id, array &$install_state) {
// values taken from the installation state.
$install_form_id
=
$form_builder
->
getFormId
(
$form_id
,
$form_state
);
if
(
!
empty
(
$install_state
[
'forms'
][
$install_form_id
]))
{
$form_state
->
set
(
'v
alues
'
,
$install_state
[
'forms'
][
$install_form_id
]);
$form_state
->
set
V
alues
(
$install_state
[
'forms'
][
$install_form_id
]);
}
$form_builder
->
submitForm
(
$form_id
,
$form_state
);
...
...
core/lib/Drupal/Core/Block/BlockBase.php
View file @
ee6ddbe8
...
...
@@ -356,9 +356,8 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
foreach
(
$this
->
getVisibilityConditions
()
as
$condition_id
=>
$condition
)
{
// Allow the condition to validate the form.
$condition_values
=
new
FormState
(
array
(
'values'
=>
$form_state
->
getValue
(
array
(
'visibility'
,
$condition_id
)),
));
$condition_values
=
(
new
FormState
())
->
setValues
(
$form_state
->
getValue
([
'visibility'
,
$condition_id
]));
$condition
->
validateConfigurationForm
(
$form
,
$condition_values
);
// Update the original form values.
$form_state
->
setValue
(
array
(
'visibility'
,
$condition_id
),
$condition_values
[
'values'
]);
...
...
@@ -389,9 +388,8 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
$this
->
configuration
[
'cache'
]
=
$form_state
->
getValue
(
'cache'
);
foreach
(
$this
->
getVisibilityConditions
()
as
$condition_id
=>
$condition
)
{
// Allow the condition to submit the form.
$condition_values
=
new
FormState
(
array
(
'values'
=>
$form_state
->
getValue
(
array
(
'visibility'
,
$condition_id
)),
));
$condition_values
=
(
new
FormState
())
->
setValues
(
$form_state
->
getValue
([
'visibility'
,
$condition_id
]));
$condition
->
submitConfigurationForm
(
$form
,
$condition_values
);
// Update the original form values.
$form_state
->
setValue
(
array
(
'visibility'
,
$condition_id
),
$condition_values
[
'values'
]);
...
...
core/lib/Drupal/Core/Entity/EntityFormBuilder.php
View file @
ee6ddbe8
...
...
@@ -49,11 +49,7 @@ public function getForm(EntityInterface $entity, $operation = 'default', array $
$form_object
=
$this
->
entityManager
->
getFormObject
(
$entity
->
getEntityTypeId
(),
$operation
);
$form_object
->
setEntity
(
$entity
);
$form_state
=
new
FormState
(
$form_state_additions
);
$form_state
[
'build_info'
][
'callback_object'
]
=
$form_object
;
$form_state
[
'build_info'
][
'base_form_id'
]
=
$form_object
->
getBaseFormID
();
$form_state
[
'build_info'
]
+=
array
(
'args'
=>
array
());
$form_state
=
(
new
FormState
())
->
setFormState
(
$form_state_additions
);
return
$this
->
formBuilder
->
buildForm
(
$form_object
,
$form_state
);
}
...
...
core/lib/Drupal/Core/Form/BaseFormIdInterface.php
View file @
ee6ddbe8
...
...
@@ -10,7 +10,7 @@
/**
* Provides an interface for a Form that has a base form ID.
*
* This will become the $form_state
['build_i
nfo
']
['base_form_id'] used to
* This will become the $form_state
->getBaseI
nfo
()
['base_form_id'] used to
* generate the name of hook_form_BASE_FORM_ID_alter().
*/
interface
BaseFormIdInterface
extends
FormInterface
{
...
...
core/lib/Drupal/Core/Form/FormBuilder.php
View file @
ee6ddbe8
...
...
@@ -157,7 +157,7 @@ public function getFormId($form_arg, FormStateInterface &$form_state) {
}
// Add the $form_arg as the callback object and determine the form ID.
$form_state
->
addBuildInfo
(
'callback_o
bject
'
,
$form_arg
);
$form_state
->
setFormO
bject
(
$form_arg
);
if
(
$form_arg
instanceof
BaseFormIdInterface
)
{
$form_state
->
addBuildInfo
(
'base_form_id'
,
$form_arg
->
getBaseFormID
());
}
...
...
@@ -188,7 +188,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) {
$input
=
$form_state
->
getUserInput
();
if
(
!
isset
(
$input
))
{
$request
=
$this
->
requestStack
->
getCurrentRequest
();
$input
=
$form_state
[
'method'
]
==
'get'
?
$request
->
query
->
all
()
:
$request
->
request
->
all
();
$input
=
$form_state
->
isMethodType
(
'get'
)
?
$request
->
query
->
all
()
:
$request
->
request
->
all
();
$form_state
->
setUserInput
(
$input
);
}
...
...
@@ -227,7 +227,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) {
// self::setCache() removes uncacheable $form_state keys (see properties
// in \Drupal\Core\Form\FormState) in order for multi-step forms to work
// properly. This means that form processing logic for single-step forms
// using $form_state
['c
ache
']
may depend on data stored in those keys
// using $form_state
->isC
ache
d()
may depend on data stored in those keys
// during self::retrieveForm()/self::prepareForm(), but form processing
// should not depend on whether the form is cached or not, so $form_state
// is adjusted to match what it would be after a
...
...
@@ -239,7 +239,9 @@ public function buildForm($form_id, FormStateInterface &$form_state) {
// - temporary: Any assigned data is expected to survives within the same
// page request.
if
(
$check_cache
)
{
$cache_form_state
=
$form_state
->
getCacheableArray
(
array
(
'always_process'
,
'temporary'
));
$cache_form_state
=
$form_state
->
getCacheableArray
();
$cache_form_state
[
'always_process'
]
=
$form_state
->
getAlwaysProcess
();
$cache_form_state
[
'temporary'
]
=
$form_state
->
getTemporary
();
$form_state
=
$form_state_before_retrieval
;
$form_state
->
setFormState
(
$cache_form_state
);
}
...
...
@@ -280,6 +282,8 @@ public function buildForm($form_id, FormStateInterface &$form_state) {
*/
public
function
rebuildForm
(
$form_id
,
FormStateInterface
&
$form_state
,
$old_form
=
NULL
)
{
$form
=
$this
->
retrieveForm
(
$form_id
,
$form_state
);
// All rebuilt forms will be cached.
$form_state
->
setCached
();
// If only parts of the form will be returned to the browser (e.g., Ajax or
// RIA clients), re-use the old #build_id to not require client-side code to
...
...
@@ -288,7 +292,8 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form
// build's data in the form cache; also allowing the user to go back to an
// earlier build, make changes, and re-submit.
// @see self::prepareForm()
if
(
isset
(
$old_form
[
'#build_id'
])
&&
!
empty
(
$form_state
[
'rebuild_info'
][
'copy'
][
'#build_id'
]))
{
$rebuild_info
=
$form_state
->
getRebuildInfo
();
if
(
isset
(
$old_form
[
'#build_id'
])
&&
!
empty
(
$rebuild_info
[
'copy'
][
'#build_id'
]))
{
$form
[
'#build_id'
]
=
$old_form
[
'#build_id'
];
}
else
{
...
...
@@ -298,7 +303,7 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form
// #action defaults to request_uri(), but in case of Ajax and other partial
// rebuilds, the form is submitted to an alternate URL, and the original
// #action needs to be retained.
if
(
isset
(
$old_form
[
'#action'
])
&&
!
empty
(
$
form_state
[
'
rebuild_info
'
]
[
'copy'
][
'#action'
]))
{
if
(
isset
(
$old_form
[
'#action'
])
&&
!
empty
(
$rebuild_info
[
'copy'
][
'#action'
]))
{
$form
[
'#action'
]
=
$old_form
[
'#action'
];
}
...
...
@@ -308,13 +313,13 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form
// cached is the $form structure before it passes through
// self::doBuildForm(), so we need to do it here.
// @todo For Drupal 8, find a way to avoid this code duplication.
if
(
empty
(
$form_state
[
'no_c
ache
'
]
))
{
if
(
$form_state
->
isC
ache
d
(
))
{
$this
->
setCache
(
$form
[
'#build_id'
],
$form
,
$form_state
);
}
// Clear out all group associations as these might be different when
// re-rendering the form.
$form_state
->
set
(
'g
roups
'
,
array
()
);
$form_state
->
set
G
roups
([]
);
// Return a fully built form that is ready for rendering.
return
$this
->
doBuildForm
(
$form_id
,
$form
,
$form_state
);
...
...
@@ -338,7 +343,8 @@ public function setCache($form_build_id, $form, FormStateInterface $form_state)
* {@inheritdoc}
*/
public
function
submitForm
(
$form_arg
,
FormStateInterface
&
$form_state
)
{
if
(
!
isset
(
$form_state
[
'build_info'
][
'args'
]))
{
$build_info
=
$form_state
->
getBuildInfo
();
if
(
empty
(
$build_info
[
'args'
]))
{
$args
=
func_get_args
();
// Remove $form and $form_state from the arguments.
unset
(
$args
[
0
],
$args
[
1
]);
...
...
@@ -351,15 +357,15 @@ public function submitForm($form_arg, FormStateInterface &$form_state) {
// there).
$form_state
->
setUserInput
(
$form_state
->
getValues
());
$form_state
->
set
(
'p
rogrammed
'
,
TRUE
);
$form_state
->
set
P
rogrammed
(
);
$form_id
=
$this
->
getFormId
(
$form_arg
,
$form_state
);
$form
=
$this
->
retrieveForm
(
$form_id
,
$form_state
);
// Programmed forms are always submitted.
$form_state
->
set
(
's
ubmitted
'
,
TRUE
);
$form_state
->
set
S
ubmitted
(
);
// Reset form validation.
$form_state
->
set
(
'must_validate'
,
TRUE
);
$form_state
->
set
ValidationEnforced
(
);
$form_state
->
clearErrors
();
$this
->
prepareForm
(
$form_id
,
$form
,
$form_state
);
...
...
@@ -376,9 +382,10 @@ public function retrieveForm($form_id, FormStateInterface &$form_state) {
// We save two copies of the incoming arguments: one for modules to use
// when mapping form ids to constructor functions, and another to pass to
// the constructor function itself.
$args
=
$form_state
[
'build_info'
][
'args'
];
$build_info
=
$form_state
->
getBuildInfo
();
$args
=
$build_info
[
'args'
];
$callback
=
array
(
$form_state
[
'build_info'
][
'callback_o
bject
'
]
,
'buildForm'
)
;
$callback
=
[
$form_state
->
getFormO
bject
()
,
'buildForm'
]
;
$form
=
array
();
// Assign a default CSS class name based on $form_id.
...
...
@@ -386,8 +393,8 @@ public function retrieveForm($form_id, FormStateInterface &$form_state) {
// form constructor function to override or remove the default class.
$form
[
'#attributes'
][
'class'
][]
=
Html
::
getClass
(
$form_id
);
// Same for the base form ID, if any.
if
(
isset
(
$
form_state
[
'
build_info
'
]
[
'base_form_id'
]))
{
$form
[
'#attributes'
][
'class'
][]
=
Html
::
getClass
(
$
form_state
[
'
build_info
'
]
[
'base_form_id'
]);
if
(
isset
(
$build_info
[
'base_form_id'
]))
{
$form
[
'#attributes'
][
'class'
][]
=
Html
::
getClass
(
$build_info
[
'base_form_id'
]);
}
// We need to pass $form_state by reference in order for forms to modify it,
...
...
@@ -410,10 +417,10 @@ public function retrieveForm($form_id, FormStateInterface &$form_state) {
* {@inheritdoc}
*/
public
function
processForm
(
$form_id
,
&
$form
,
FormStateInterface
&
$form_state
)
{
$form_state
->
set
(
'v
alues
'
,
array
()
);
$form_state
->
set
V
alues
([]
);
// With GET, these forms are always submitted if requested.
if
(
$form_state
[
'method'
]
==
'get'
&&
!
empty
(
$form_state
[
'a
lways
_p
rocess
'
]
))
{
if
(
$form_state
->
isMethodType
(
'get'
)
&&
$form_state
->
getA
lways
P
rocess
(
))
{
$input
=
$form_state
->
getUserInput
();
if
(
!
isset
(
$input
[
'form_build_id'
]))
{
$input
[
'form_build_id'
]
=
$form
[
'#build_id'
];
...
...
@@ -435,7 +442,7 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) {
$form
=
$this
->
doBuildForm
(
$form_id
,
$form
,
$form_state
);
// Only process the input if we have a correct form submission.
if
(
$form_state
[
'p
rocess
_
input
'
]
)
{
if
(
$form_state
->
isP
rocessi
ngI
nput
()
)
{
// Form constructors may explicitly set #token to FALSE when cross site
// request forgery is irrelevant to the form, such as search forms.
if
(
isset
(
$form
[
'#token'
])
&&
$form
[
'#token'
]
===
FALSE
)
{
...
...
@@ -447,8 +454,9 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) {
// submit button is not taken account. Therefore, check whether there is
// exactly one submit button in the form, and if so, automatically use it
// as triggering_element.
if
(
$form_state
[
'programmed'
]
&&
!
isset
(
$form_state
[
'triggering_element'
])
&&
count
(
$form_state
[
'buttons'
])
==
1
)
{
$form_state
->
set
(
'triggering_element'
,
reset
(
$form_state
[
'buttons'
]));
$buttons
=
$form_state
->
getButtons
();
if
(
$form_state
->
isProgrammed
()
&&
!
$form_state
->
getTriggeringElement
()
&&
count
(
$buttons
)
==
1
)
{
$form_state
->
setTriggeringElement
(
reset
(
$buttons
));
}
$this
->
formValidator
->
validateForm
(
$form_id
,
$form
,
$form_state
);
...
...
@@ -462,35 +470,35 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) {
Html
::
resetSeenIds
();
}
if
(
!
$form_state
[
'r
ebuild
'
]
&&
!
FormState
::
hasAnyErrors
())
{
if
(
!
$form_state
->
isR
ebuild
ing
()
&&
!
FormState
::
hasAnyErrors
())
{
if
(
$submit_response
=
$this
->
formSubmitter
->
doSubmitForm
(
$form
,
$form_state
))
{
return
$submit_response
;
}
}
// Don't rebuild or cache form submissions invoked via self::submitForm().
if
(
!
empty
(
$form_state
[
'p
rogrammed
'
]
))
{
if
(
$form_state
->
isP
rogrammed
(
))
{
return
;
}
// If $form_state
['r
ebuild
']
has been set and input has been processed
// If $form_state
->isR
ebuild
ing()
has been set and input has been processed
// without validation errors, we are in a multi-step workflow that is not
// yet complete. A new $form needs to be constructed based on the changes
// made to $form_state during this request. Normally, a submit handler
// sets $form_state
['r
ebuild
']
if a fully executed form requires
another
// step. However, for forms that have not been fully executed
(e.g., Ajax
// submissions triggered by non-buttons), there is no submit
handler to
// set $form_state
['r
ebuild
']
. It would not make sense to
redisplay the
// identical form without an error for the user to correct,
so we also
// rebuild error-free non-executed forms, regardless of
// $form_state
['r
ebuild
']
.
// sets $form_state
->isR
ebuild
ing()
if a fully executed form requires
//
another
step. However, for forms that have not been fully executed
//
(e.g., Ajax
submissions triggered by non-buttons), there is no submit
//
handler to
set $form_state
->isR
ebuild
ing()
. It would not make sense to
//
redisplay the
identical form without an error for the user to correct,
//
so we also
rebuild error-free non-executed forms, regardless of
// $form_state
->isR
ebuild
ing()
.
// @todo Simplify this logic; considering Ajax and non-HTML front-ends,
// along with element-level #submit properties, it makes no sense to
// have divergent form execution based on whether the triggering element
// has #executes_submit_callback set to TRUE.
if
((
$form_state
[
'r
ebuild
'
]
||
!
$form_state
[
'e
xecuted
'
]
)
&&
!
FormState
::
hasAnyErrors
())
{
if
((
$form_state
->
isR
ebuild
ing
()
||
!
$form_state
->
isE
xecuted
()
)
&&
!
FormState
::
hasAnyErrors
())
{
// Form building functions (e.g., self::handleInputElement()) may use
// $form_state
['r
ebuild
']
to determine if they are running in the
// $form_state
->isR
ebuild
ing()
to determine if they are running in the
// context of a rebuild, so ensure it is set.
$form_state
->
setRebuild
();
$form
=
$this
->
rebuildForm
(
$form_id
,
$form_state
,
$form
);
...
...
@@ -498,13 +506,13 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) {
}
// After processing the form, the form builder or a #process callback may
// have
set
$form_state
['c
ache
']
to indicate that the form and form
state
// shall be cached. But the form may only be cached if
the 'no_cache'
//
property is not set to TRUE
. Only cache $form as it was
prior to
// self::doBuildForm(), because self::doBuildForm() must run for
each
// request to accommodate new user input. Rebuilt forms are not cached
here,
// because self::rebuildForm() already takes care of that.
if
(
!
$form_state
[
'r
ebuild
'
]
&&
$form_state
[
'cache'
]
&&
empty
(
$form_state
[
'no_c
ache
'
]
))
{
// have
called
$form_state
->setC
ache
d()
to indicate that the form and form
//
state
shall be cached. But the form may only be cached if
//
$form_state->disableCache() is not called
. Only cache $form as it was
//
prior to
self::doBuildForm(), because self::doBuildForm() must run for
//
each
request to accommodate new user input. Rebuilt forms are not cached
//
here,
because self::rebuildForm() already takes care of that.
if
(
!
$form_state
->
isR
ebuild
ing
()
&&
$form_state
->
isC
ache
d
(
))
{
$this
->
setCache
(
$form
[
'#build_id'
],
$unprocessed_form
,
$form_state
);
}
}
...
...
@@ -516,10 +524,9 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
$user
=
$this
->
currentUser
();
$form
[
'#type'
]
=
'form'
;
$form_state
->
set
(
'programmed'
,
isset
(
$form_state
[
'programmed'
])
?
$form_state
[
'programmed'
]
:
FALSE
);
// Fix the form method, if it is 'get' in $form_state, but not in $form.
if
(
$form_state
->
get
(
'method'
)
==
'get'
&&
!
isset
(
$form
[
'#method'
]))
{
if
(
$form_state
->
isMethodType
(
'get'
)
&&
!
isset
(
$form
[
'#method'
]))
{
$form
[
'#method'
]
=
'get'
;
}
...
...
@@ -551,7 +558,7 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
// since tokens are session-bound and forms displayed to anonymous users are
// very likely cached, we cannot assign a token for them.
// During installation, there is no $user yet.
if
(
$user
&&
$user
->
isAuthenticated
()
&&
!
$form_state
[
'p
rogrammed
'
]
)
{
if
(
$user
&&
$user
->
isAuthenticated
()
&&
!
$form_state
->
isP
rogrammed
()
)
{
// Form constructors may explicitly set #token to FALSE when cross site
// request forgery is irrelevant to the form, such as search forms.
if
(
isset
(
$form
[
'#token'
])
&&
$form
[
'#token'
]
===
FALSE
)
{
...
...
@@ -592,22 +599,23 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
$form
[
'#validate'
][]
=
'::validateForm'
;
$form
[
'#submit'
][]
=
'::submitForm'
;
$build_info
=
$form_state
->
getBuildInfo
();
// If no #theme has been set, automatically apply theme suggestions.
// theme_form() itself is in #theme_wrappers and not #theme. Therefore, the
// #theme function only has to care for rendering the inner form elements,
// not the form itself.
if
(
!
isset
(
$form
[
'#theme'
]))
{
$form
[
'#theme'
]
=
array
(
$form_id
);
if
(
isset
(
$
form_state
[
'
build_info
'
]
[
'base_form_id'
]))
{
$form
[
'#theme'
][]
=
$
form_state
[
'
build_info
'
]
[
'base_form_id'
];
if
(
isset
(
$build_info
[
'base_form_id'
]))
{
$form
[
'#theme'
][]
=
$build_info
[
'base_form_id'
];
}
}
// Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and
// hook_form_FORM_ID_alter() implementations.
$hooks
=
array
(
'form'
);
if
(
isset
(
$
form_state
[
'
build_info
'
]
[
'base_form_id'
]))
{
$hooks
[]
=
'form_'
.
$
form_state
[
'
build_info
'
]
[
'base_form_id'
];
if
(
isset
(
$build_info
[
'base_form_id'
]))
{
$hooks
[]
=
'form_'
.
$build_info
[
'base_form_id'
];
}
$hooks
[]
=
'form_'
.
$form_id
;
$this
->
moduleHandler
->
alter
(
$hooks
,
$form
,
$form_state
,
$form_id
);
...
...
@@ -690,11 +698,11 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
// for programmed forms coming from self::submitForm(), or if the form_id
// coming from the POST data is set and matches the current form_id.
$input
=
$form_state
->
getUserInput
();
if
(
$form_state
[
'p
rogrammed
'
]
||
(
!
empty
(
$input
)
&&
(
isset
(
$input
[
'form_id'
])
&&
(
$input
[
'form_id'
]
==
$form_id
))))
{
$form_state
->
set
(
'p
rocess
_i
nput
'
,
TRUE
);
if
(
$form_state
->
isP
rogrammed
()
||
(
!
empty
(
$input
)
&&
(
isset
(
$input
[
'form_id'
])
&&
(
$input
[
'form_id'
]
==
$form_id
))))
{
$form_state
->
set
P
rocess
I
nput
(
);
}
else
{
$form_state
->
set
(
'p
rocess
_i
nput
'
,
FALSE
);
$form_state
->
set
P
rocess
I
nput
(
FALSE
);
}
// All form elements should have an #array_parents property.
...
...
@@ -791,14 +799,14 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
// If there is a file element, we need to flip a flag so later the
// form encoding can be set.
if
(
isset
(
$element
[
'#type'
])
&&
$element
[
'#type'
]
==
'file'
)
{
$form_state
->
set
(
'has_f
ile
_e
lement
'
,
TRUE
);
$form_state
->
set
HasF
ile
E
lement
(
);
}
// Final tasks for the form element after self::doBuildForm() has run for
// all other elements.
if
(
isset
(
$element
[
'#type'
])
&&
$element
[
'#type'
]
==
'form'
)
{
// If there is a file element, we set the form encoding.
if
(
isset
(
$form_state
[
'
has
_f
ile
_e
lement
'
]
))
{
if
(
$form_state
->
has
F
ile
E
lement
(
))
{
$element
[
'#attributes'
][
'enctype'
]
=
'multipart/form-data'
;
}
...
...
@@ -808,24 +816,26 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
// though the user clicked the first button. Therefore, to be as
// consistent as we can be across browsers, if no 'triggering_element' has
// been identified yet, default it to the first button.
if
(
!
$form_state
[
'programmed'
]
&&
!
isset
(
$form_state
[
'triggering_element'
])
&&
!
empty
(
$form_state
[
'buttons'
]))
{
$form_state
->
set
(
'triggering_element'
,
$form_state
[
'buttons'
][
0
]);
$buttons
=
$form_state
->
getButtons
();
if
(
!
$form_state
->
isProgrammed
()
&&
!
$form_state
->
getTriggeringElement
()
&&
!
empty
(
$buttons
))
{
$form_state
->
setTriggeringElement
(
$buttons
[
0
]);
}
$triggering_element
=
$form_state
->
get
(
't
riggering
_e
lement
'
);
$triggering_element
=
$form_state
->
get
T
riggering
E
lement
(
);
// If the triggering element specifies "button-level" validation and
// submit handlers to run instead of the default form-level ones, then add
// those to the form state.
foreach
(
array
(
'validate'
,
'submit'
)
as
$type
)
{
if
(
isset
(
$triggering_element
[
'#'
.
$type
]))
{
$form_state
->
set
(
$type
.
'_handlers'
,
$triggering_element
[
'#'
.
$type
]);
}
if
(
isset
(
$triggering_element
[
'#validate'
]))
{
$form_state
->
setValidateHandlers
(
$triggering_element
[
'#validate'
]);
}
if
(
isset
(
$triggering_element
[
'#submit'
]))
{
$form_state
->
setSubmitHandlers
(
$triggering_element
[
'#submit'
]);
}
// If the triggering element executes submit handlers, then set the form
// state key that's needed for those handlers to run.
if
(
!
empty
(
$triggering_element
[
'#executes_submit_callback'
]))
{
$form_state
->
set
(
's
ubmitted
'
,
TRUE
);
$form_state
->
set
S
ubmitted
(
);
}
// Special processing if the triggering element is a button.
...
...
@@ -899,7 +909,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$
// #access=FALSE on an element usually allow access for some users, so forms
// submitted with self::submitForm() may bypass access restriction and be
// treated as high-privilege users instead.
$process_input
=
empty
(
$element
[
'#disabled'
])
&&
((
$form_state
[
'p
rogrammed
'
]
&&
$form_state
[
'programmed_bypass_a
ccess
_c
heck
'
]
)
||
(
$form_state
[
'p
rocess
_
input
'
]
&&
(
!
isset
(
$element
[
'#access'
])
||
$element
[
'#access'
])));
$process_input
=
empty
(
$element
[
'#disabled'
])
&&
((
$form_state
->
isP
rogrammed
()
&&
$form_state
->
isBypassingProgrammedA
ccess
C
heck
s
()
)
||
(
$form_state
->
isP
rocessin
gIn
put
()
&&
(
!
isset
(
$element
[
'#access'
])
||
$element
[
'#access'
])));
// Set the element's #value property.
if
(
!
isset
(
$element
[
'#value'
])
&&
!
array_key_exists
(
'#value'
,
$element
))
{
...
...
@@ -925,7 +935,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$
// use default values for the latter, if required. Programmatically
// submitted forms can submit explicit NULL values when calling
// self::submitForm() so we do not modify FormState::$input for them.
if
(
!
$input_exists
&&
!
$form_state
[
'r
ebuild
'
]
&&
!
$form_state
[
'p
rogrammed
'
]
)
{
if
(
!
$input_exists
&&
!
$form_state
->
isR
ebuild
ing
()
&&
!
$form_state
->
isP
rogrammed
()
)
{
// Add the necessary parent keys to FormState::$input and sets the
// element's input value to NULL.
NestedArray
::
setValue
(
$form_state
->
getUserInput
(),
$element
[
'#parents'
],
NULL
);
...
...
@@ -967,7 +977,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$
if
(
$process_input
)
{
// Detect if the element triggered the submission via Ajax.
if
(
$this
->
elementTriggeredScriptedSubmission
(
$element
,
$form_state
))
{
$form_state
->
set
(
't
riggering
_e
lement
'
,
$element
);
$form_state
->
set
T
riggering
E
lement
(
$element
);
}
// If the form was submitted by the browser rather than via Ajax, then it
...
...
@@ -979,11 +989,11 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$
// form_state_values_clean() and for the self::doBuildForm() code that
// handles a form submission containing no button information in
// \Drupal::request()->request.
$buttons
=
$form_state
->
get
(
'b
uttons
'
);
$buttons
=
$form_state
->
get
B
uttons
(
);
$buttons
[]
=
$element
;
$form_state
->
set
(
'b
uttons
'
,
$buttons
);
$form_state
->
set
B
uttons
(
$buttons
);
if
(
$this
->
buttonWasClicked
(
$element
,
$form_state
))
{
$form_state
->
set
(
't
riggering
_e
lement
'
,
$element
);
$form_state
->
set
T
riggering
E
lement
(
$element
);
}
}
}
...
...
@@ -1031,10 +1041,10 @@ protected function elementTriggeredScriptedSubmission($element, FormStateInterfa
* textfield (self::doBuildForm() has extra code for that).
*
* Because this function contains only part of the logic needed to determine
* $form_state
['t
riggering
_e
lement
']
, it should not be called from anywhere
* $form_state
->getT
riggering
E
lement
()
, it should not be called from anywhere
* other than within the Form API. Form validation and submit handlers needing
* to know which button was clicked should get that information from
* $form_state
['t
riggering
_e
lement
']
.
* $form_state
->getT
riggering
E
lement
()
.
*/
protected
function
buttonWasClicked
(
$element
,
FormStateInterface
&
$form_state
)
{
// First detect normal 'vanilla' button clicks. Traditionally, all standard
...
...
core/lib/Drupal/Core/Form/FormBuilderInterface.php
View file @
ee6ddbe8
...
...
@@ -42,7 +42,7 @@ public function getFormId($form_arg, FormStateInterface &$form_state);
* function. For example, the node_edit form requires that a node object is
* passed in here when it is called. These are available to implementations
* of hook_form_alter() and hook_form_FORM_ID_alter() as the array
* $form_state
['b
uild
_i
nfo
']
['args'].
* $form_state
->getB
uild
I
nfo
()
['args'].
*
* @return array
* The form array.
...
...
@@ -79,10 +79,10 @@ public function buildForm($form_id, FormStateInterface &$form_state);
* This is the key function for making multi-step forms advance from step to
* step. It is called by self::processForm() when all user input processing,
* including calling validation and submission handlers, for the request is
* finished. If a validate or submit handler set $form_state
['r
ebuild
'] to
* TRUE, and if other conditions don't preempt a rebuild from happening,
then
* this function is called to generate a new $form, the next step in the
form
* workflow, to be returned for rendering.
* finished. If a validate or submit handler set $form_state
->isR
ebuild
ing()
*
to
TRUE, and if other conditions don't preempt a rebuild from happening,
*
then
this function is called to generate a new $form, the next step in the
*
form
workflow, to be returned for rendering.
*
* Ajax form submissions are almost always multi-step workflows, so that is
* one common use-case during which form rebuilding occurs. See
...
...
@@ -98,7 +98,7 @@ public function buildForm($form_id, FormStateInterface &$form_state);
* (optional) A previously built $form. Used to retain the #build_id and
* #action properties in Ajax callbacks and similar partial form rebuilds.
* The only properties copied from $old_form are the ones which both exist
* in $old_form and for which $form_state
['r
ebuild
_i
nfo
']
['copy'][PROPERTY]
* in $old_form and for which $form_state
->getR
ebuild
I
nfo
()
['copy'][PROPERTY]
* is TRUE. If $old_form is not passed, the entire $form is rebuilt freshly.
* 'rebuild_info' needs to be a separate top-level property next to
* 'build_info', since the contained data must not be cached.
...
...
@@ -148,8 +148,8 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form
* @endcode
* would be called via self::submitForm() as follows:
* @code
* $form_state->set
('v
alues
',
$my_form_values);
* $form_state
['b
uild
_i
nfo
'][
'args'
] = array(
&$object);
* $form_state->set
V
alues
(
$my_form_values);
* $form_state
->addB
uild
I
nfo
(
'args'
, [
&$object
]
);
* drupal_form_submit('mymodule_form', $form_state);
* @endcode
* For example:
...
...
@@ -161,7 +161,7 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form
* $values['pass']['pass1'] = 'password';
* $values['pass']['pass2'] = 'password';
* $values['op'] = t('Create new account');
* $form_state->set
('v
alues
',
$values);
* $form_state->set
V
alues
(
$values);
* drupal_form_submit('user_register_form', $form_state);
* @endcode
*/
...
...
@@ -293,8 +293,8 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state);
* the next submission needs to be processed, a multi-step workflow is
* needed. This is most commonly implemented with a submit handler setting
* persistent data within $form_state based on *validated* values in
* $form_state->getValues() and
sett
ing $form_state
['r
ebuild
']. The form
* building functions must then be implemented to use the $form_state
data
* $form_state->getValues() and
check
ing $form_state
->isR
ebuild
ing(). The
*
form
building functions must then be implemented to use the $form_state
* to rebuild the form with the structure appropriate for the new state.
* - Where user input must affect the rendering of the form without affecting
* its structure, the necessary conditional rendering logic should reside
...
...
core/lib/Drupal/Core/Form/FormCache.php
View file @
ee6ddbe8
...
...
@@ -95,8 +95,9 @@ protected function loadCachedFormState($form_build_id, FormStateInterface $form_
// If the original form is contained in include files, load the files.
// @see \Drupal\Core\Form\FormStateInterface::loadInclude()
$form_state
[
'build_info'
]
+=
array
(
'files'
=>
array
());
foreach
(
$form_state
[
'build_info'
][
'files'
]
as
$file
)
{
$build_info
=
$form_state
->
getBuildInfo
();
$build_info
+=
[
'files'
=>
[]];
foreach
(
$build_info
[
'files'
]
as
$file
)
{
if
(
is_array
(
$file
))
{
$file
+=
array
(
'type'
=>
'inc'
,
'name'
=>
$file
[
'module'
]);
$this
->
moduleHandler
->
loadInclude
(
$file
[
'module'
],
$file
[
'type'
],
$file
[
'name'
]);
...
...
@@ -109,9 +110,10 @@ protected function loadCachedFormState($form_build_id, FormStateInterface $form_
// for this request.
// @todo Ensure we are not storing an excessively large string list
// in: https://www.drupal.org/node/2295823
$form_state
[
'build_info'
]
+=
array
(
'safe_strings'
=>
array
());
SafeMarkup
::
setMultiple
(
$form_state
[
'build_info'
][
'safe_strings'
]);
unset
(
$form_state
[
'build_info'
][
'safe_strings'
]);
$build_info
+=
[
'safe_strings'
=>
[]];
SafeMarkup
::
setMultiple
(
$build_info
[
'safe_strings'
]);
unset
(
$build_info
[
'safe_strings'
]);
$form_state
->
setBuildInfo
(
$build_info
);
}
}
...
...
core/lib/Drupal/Core/Form/FormState.php
View file @
ee6ddbe8
...
...
@@ -25,13 +25,6 @@ class FormState implements FormStateInterface, \ArrayAccess {
*/
protected
static
$anyErrors
=
FALSE
;
/**
* The internal storage of the form state.
*
* @var array
*/
protected
$internalStorage
=
array
();
/**
* The complete form structure.
*
...
...
@@ -92,12 +85,12 @@ class FormState implements FormStateInterface, \ArrayAccess {
* re-submit the form). However, if 'rebuild' has been set to TRUE, then a new
* copy of the form is immediately built and sent to the browser, instead of a
* redirect. This is used for multi-step forms, such as wizards and
* confirmation forms. Normally,
$form_state['
rebuild
']
is set by a submit
*
handler,
since its is usually logic within a submit handler that determines
*
whether
a form is done or requires another step. However, a validation
*
handler may already set $form_state['
rebuild
']
to cause the form processing
*
to bypass submit
handlers and rebuild the form instead, even if there are
*
no validation
errors.
* confirmation forms. Normally,
self::$
rebuild is set by a submit
handler,
* since its is usually logic within a submit handler that determines
whether
* a form is done or requires another step. However, a validation
handler may
*
already set self::$
rebuild to cause the form processing
to bypass submit