Problem/Motivation

The FormBuilder class is complex and long, but large portions of it are not actually for building and processing, but for submissions.
This makes it harder to unit test, harder to understand the code flow, and harder to maintain.

Proposed resolution

Move form submission into a new class.
In order to minimize the changes for existing module code, have FormBuilder pass through those method calls to the new class.

Remaining tasks

N/A

User interface changes

N/A

API changes

No API break, but https://drupal.org/node/2121003 should be updated to clarify which service/interface executeSubmitHandlers() and redirectForm() are on now

Comments

tim.plunkett’s picture

Status: Active » Needs review
StatusFileSize
new136.92 KB
new41.96 KB

Building on the other patch, this is just to get something up.

The last submitted patch, 1: form-2257835-1-full.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 1: form-2257835-1.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new153.18 KB
sun’s picture

Awesome! That's exactly the parity I thought of :-)

  1. +++ b/core/core.services.yml
    @@ -122,10 +122,13 @@ services:
    +  form_submission:
    +    class: Drupal\Core\Form\FormSubmission
    

    For consistency, I think the service ID should be form_submitter and the class name should be FormSubmitter.

    Alternatively, we might want to go back to the other issue and quickly rename the validator into validation prior to commit?

  2. +++ b/core/lib/Drupal/Core/Form/FormSubmission.php
    @@ -0,0 +1,232 @@
    +  public function handleFormSubmission(&$form, &$form_state) {
    ...
    +  public function redirectForm($form_state) {
    ...
    +  public function executeSubmitHandlers(&$form, &$form_state) {
    

    Minor: The order of methods looks a bit off/reversed in the class and interface...

    1. submitForm
    2. executeSubmitHandlers
    3. redirectForm

  3. +++ b/core/lib/Drupal/Core/Form/FormSubmissionInterface.php
    @@ -0,0 +1,30 @@
    +  public function handleFormSubmission(&$form, &$form_state);
    

    The validator interface calls the corresponding method validateForm() — any particular reason for not renaming this submitForm()?

tim.plunkett’s picture

1) eeek I guess maybe we should.

2) Yeah this is very rough, I'll be rearranging the methods in both interface and class before I'm done, this is still WIP

3) So I did not yet move in FormBuilder::submitForm(). the validateForm() method takes a form and triggers validation. This handleFormSubmission() method cannot really be called to submit a form, it is used during form processing...

sun’s picture

I'm not convinced that FormBuilder::submitForm() belongs to this class. It lives/operates at the opposite end; i.e., it's an initial entry point to build a form + futz with $form_state in a way to auto-submit it, but doesn't interfere with the actual form submission logic.

In turn, IMO this patch already covers pretty much everything the class should cover. Just some polishing and I'd consider it done :-)

tim.plunkett’s picture

StatusFileSize
new61.35 KB

A lot moved around and the interdiff was useless.
#2209977: Move form validation logic out of FormBuilder into a new class went in!

sun’s picture

Apologies, I don't know how, but somehow I completely missed the following moved methods in the earlier patch:

+++ b/core/lib/Drupal/Core/Form/FormSubmissionProcessor.php
@@ -0,0 +1,319 @@
+  public function determineTriggeringElement($element, $form_state) {
...
+  protected function elementTriggeredScriptedSubmission($element, $form_state) {
...
+  protected function buttonWasClicked($element, $form_state) {

+++ b/core/lib/Drupal/Core/Form/FormSubmissionProcessorInterface.php
@@ -0,0 +1,119 @@
+  public function determineTriggeringElement($element, $form_state);

These methods are not part of the form submission/processing logic at all.

They belong to the user input processing, which is (currently) performed during form building. Their abstract meaning is:

Determine if some values in $_GET or $_POST are mapping to some form elements, so we can *pretend* that those (button) elements saw user input and were "clicked", even if they were actually not.

A positive result of that user input processing is stored in $form_state - as if the user input had contained the actually required values to trigger that state natively (even though it did not).

This information must be set and is consumed before the form validation + submission workflow begins. The effective triggering element can have additional form validation handlers assigned to it.

That is why it is not part of the submission workflow.

Status: Needs review » Needs work

The last submitted patch, 8: form-2257835-8.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new49.85 KB

This information must be set and is consumed before the form validation + submission workflow begins

Good point about the validation here. Pulled that part out.

sun’s picture

Thanks. Last remaining step from my perspective is: Naming.

Can we rename FormSubmissionProcessor into just simply FormSubmitter, please?

(ibid on the service ID: form_submission_processorform_submitter)

FormSubmissionProcessor is completely out of line compared to everything else, which defeats the whole point of splitting up the main Form API concepts. FormProcessor cannot be used as name, because major parts of the actual form processing logic still live in FormBuilder::processForm() (which is fine). The FormValidator isn't a FormValidationProcessor either. Despite the offer in #5, you objected to rename FormValidator. This is about the submission workflow of a form only; hence, FormSubmitter.

Second, you wanted to re-order the methods in the class + interface to follow #5.2.

sun’s picture

Status: Needs review » Needs work
tim.plunkett’s picture

Status: Needs work » Needs review

I think we need a second opinion on the class naming, resetting to needs review for that.

I reordered the methods, but I have execute and redirect swapped. I can fix that after we settle on a name.

pwolanin’s picture

FormSubmitter in analogy to FormValidator makes sense to me. Also, it's much shorter without really being less informative.

sun’s picture

Thanks for your prompt feedback, @pwolanin.

@tim.plunkett: Also, if you'd explain the underlying reasoning for naming it FormSubmissionProcessor, then others might be able to relate to that (whichever) idea. Right now, I'm not able to see any reasoning that would make sense of that naming, so I assume you're interpreting it as "bikeshed" whereas I'm clearly not — the parity of FormBuilder + FormValidator + FormSubmitter covers the main 3 Form API concepts in distinct classes whose names are fully in line.

tim.plunkett’s picture

Issue summary: View changes
StatusFileSize
new50.88 KB

No, honestly now that we've moved the other "processing" code back out, I'm much less attached to it.

I pinged @pwolanin and @larowlan, we talked about it. @pwolanin commented above, and @larowlan pointed out that each name is clear and explanatory, but not any more than the other.

Renamed, and swapped the order of the methods to match #5.2

Status: Needs review » Needs work

The last submitted patch, 17: form-submit-2257835-17.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new50.88 KB
new776 bytes

Duh, bad copy/paste in form.inc

sun’s picture

StatusFileSize
new50.81 KB
new4.07 KB

handleFormSubmission() diverges from FormValidator::validateForm(). Sadly we cannot use submitForm(), because FormBuilder::submitForm() already exists. Therefore:

  1. Renamed handleFormSubmission() to doSubmitForm().
  2. Throw exception when FormBuilder::doSubmitForm() is called directly.

In light of that, I think we should create a follow-up issue to remove the additional interfaces from FormBuilder, but I'm happy to move forward with this for now.

That was my only remaining remark, so if we're fine with that, then I think this is RTBC.

tim.plunkett’s picture

I'm fine with this.

It would have been just as easy for you to leave a review and let me update it, it would have helped me keep my branches clean, and then you could have cleanly RTBC'd it...

sun’s picture

Status: Needs review » Reviewed & tested by the community

I only renamed that method name, so I'm comfortable to RTBC this patch. Thanks!

jibran’s picture

+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -793,78 +744,7 @@ public function validateForm($form_id, &$form, &$form_state) {
    * {@inheritdoc}

@@ -878,33 +758,14 @@ public function executeValidateHandlers(&$form, &$form_state) {
   public function executeSubmitHandlers(&$form, &$form_state) {

I think @deprecated can be added here.

tim.plunkett’s picture

#23, The same thing was done in the validate patch, we have all of the form.inc deprecated stuff to clean up first.

almaudoh’s picture

Issue summary: View changes
catch’s picture

20: form.submitter.20.patch queued for re-testing.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: form.submitter.20.patch, failed testing.

Jalandhar’s picture

Status: Needs work » Needs review
StatusFileSize
new50.78 KB

Here is the Rerolled patch.

Jalandhar’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.x, thanks!

  • Commit 120a1da on 8.x by catch:
    Issue #2257835 by tim.plunkett, sun, Jalandhar: Move form submission...
tim.plunkett’s picture

Assigned: tim.plunkett » Unassigned

Thanks @Jalandhar for rerolling!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.