diff --git a/Event/RequestListener.php b/Event/RequestListener.php index 7701c4b6..76061716 100644 --- a/Event/RequestListener.php +++ b/Event/RequestListener.php @@ -17,9 +17,12 @@ use Sulu\Bundle\FormBundle\Form\HandlerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Contracts\Service\ResetInterface; -class RequestListener +class RequestListener implements ResetInterface { /** * @var BuilderInterface @@ -41,6 +44,14 @@ class RequestListener */ protected $eventDispatcher; + /** + * Flag set to true when an invalid form is submitted, + * so we can set the http return code to 422. + * + * @var bool + */ + protected $invalidSubmittedForm = false; + /** * RequestListener constructor. */ @@ -73,10 +84,16 @@ public function onKernelRequest(RequestEvent $event): void try { $form = $this->formBuilder->buildByRequest($request); - if (!$form || !$form->isSubmitted() || !$form->isValid()) { + if (!$form || !$form->isSubmitted()) { // do nothing when no form was found or not valid return; } + + if (!$form->isValid()) { + $this->invalidSubmittedForm = true; + + return; + } } catch (\Exception $e) { // Catch all exception on build form by request return; @@ -96,4 +113,24 @@ public function onKernelRequest(RequestEvent $event): void $event->setResponse($response); } } + + public function onKernelResponse(ResponseEvent $event): void + { + if (\method_exists($event, 'isMainRequest') ? !$event->isMainRequest() : !$event->isMasterRequest()) { + // do nothing if it's not the master request + return; + } + + if ($this->invalidSubmittedForm) { + $response = $event->getResponse(); + $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); + + $event->setResponse($response); + } + } + + public function reset(): void + { + $this->invalidSubmittedForm = false; + } } diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 751051a4..f1f69cdd 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -104,6 +104,8 @@ + + diff --git a/Tests/Functional/Mail/HelperTestCase.php b/Tests/Functional/Mail/HelperTestCase.php index a6ab71f6..72340b26 100644 --- a/Tests/Functional/Mail/HelperTestCase.php +++ b/Tests/Functional/Mail/HelperTestCase.php @@ -72,13 +72,22 @@ protected function doSendForm(Form $form): void $formSelector = \sprintf('form[name=%s]', $formName); $this->assertEquals(1, $crawler->filter($formSelector)->count()); + $formElm = $crawler->filter($formSelector)->first()->form([ + $formName . '[email]' => '', + $formName . '[email1]' => '', + ]); + + $this->client->enableProfiler(); + $crawler = $this->client->submit($formElm); + $this->assertResponseStatusCodeSame(422); + $formElm = $crawler->filter($formSelector)->first()->form([ $formName . '[email]' => 'test@example.org', $formName . '[email1]' => 'jon@example.org', ]); - $this->client->enableProfiler(); $this->client->submit($formElm); + $this->assertResponseStatusCodeSame(302); $this->assertResponseRedirects('?send=true'); } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 7ba44698..e2f04931 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -805,6 +805,11 @@ parameters: count: 1 path: Event/RequestListener.php + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\HttpKernel\\\\Event\\\\ResponseEvent\\:\\:isMasterRequest\\(\\)\\.$#" + count: 1 + path: Event/RequestListener.php + - message: "#^In method \"Sulu\\\\Bundle\\\\FormBundle\\\\Event\\\\RequestListener\\:\\:onKernelRequest\", caught \"Exception\" must be rethrown\\. Either catch a more specific exception or add a \"throw\" clause in the \"catch\" block to propagate the exception\\. More info\\: http\\://bit\\.ly/failloud$#" count: 1