Verified Commit 7a9558ff authored by Jess's avatar Jess
Browse files

Issue #3465041 by prudloff, xjm, smustgrave, larowlan:...

Issue #3465041 by prudloff, xjm, smustgrave, larowlan: FormState::getTriggeringElement() behaves inconsistently when request is malformed

(cherry picked from commit 3d825df1)
parent 6c3d519e
Loading
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1314,10 +1314,14 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$
        $buttons[] = $element;
        $form_state->setButtons($buttons);
        if ($this->buttonWasClicked($element, $form_state)) {
          // A correctly formatted request should only have one triggering
          // element.
          if (empty($form_state->getTriggeringElement())) {
            $form_state->setTriggeringElement($element);
          }
        }
      }
    }

    // Set the element's value in $form_state->getValues(), but only, if its key
    // does not exist yet (a #value_callback may have already populated it).
+51 −0
Original line number Diff line number Diff line
@@ -966,6 +966,57 @@ public static function providerTestFormTokenCacheability() {
    ];
  }

  /**
   * Tests the detection of the triggering element.
   */
  public function testTriggeringElement(): void {
    $form_arg = 'Drupal\Tests\Core\Form\TestForm';

    // No triggering element.
    $form_state = new FormState();
    $this->formBuilder->buildForm($form_arg, $form_state);
    $this->assertNull($form_state->getTriggeringElement());

    // When no op is provided, default to the first button element.
    $form_state = new FormState();
    $form_state->setMethod('GET');
    $form_state->setUserInput(['form_id' => 'test_form']);
    $this->formBuilder->buildForm($form_arg, $form_state);
    $triggeringElement = $form_state->getTriggeringElement();
    $this->assertIsArray($triggeringElement);
    $this->assertSame('op', $triggeringElement['#name']);
    $this->assertSame('Submit', $triggeringElement['#value']);

    // A single triggering element.
    $form_state = new FormState();
    $form_state->setMethod('GET');
    $form_state->setUserInput(['form_id' => 'test_form', 'op' => 'Submit']);
    $this->formBuilder->buildForm($form_arg, $form_state);
    $triggeringElement = $form_state->getTriggeringElement();
    $this->assertIsArray($triggeringElement);
    $this->assertSame('op', $triggeringElement['#name']);

    // A different triggering element.
    $form_state = new FormState();
    $form_state->setMethod('GET');
    $form_state->setUserInput(['form_id' => 'test_form', 'other_action' => 'Other action']);
    $this->formBuilder->buildForm($form_arg, $form_state);
    $triggeringElement = $form_state->getTriggeringElement();
    $this->assertIsArray($triggeringElement);
    $this->assertSame('other_action', $triggeringElement['#name']);

    // Two triggering elements.
    $form_state = new FormState();
    $form_state->setMethod('GET');
    $form_state->setUserInput(['form_id' => 'test_form', 'op' => 'Submit', 'other_action' => 'Other action']);
    $this->formBuilder->buildForm($form_arg, $form_state);

    // Verify that only the first triggering element is respected.
    $triggeringElement = $form_state->getTriggeringElement();
    $this->assertIsArray($triggeringElement);
    $this->assertSame('op', $triggeringElement['#name']);
  }

}

class TestForm implements FormInterface {
+5 −0
Original line number Diff line number Diff line
@@ -36,5 +36,10 @@ function test_form_id() {
    '#type' => 'submit',
    '#value' => 'Submit',
  ];
  $form['actions']['other_action'] = [
    '#type' => 'submit',
    '#name' => 'other_action',
    '#value' => 'Other action',
  ];
  return $form;
}