minor #41181 [FrameworkBundle] improve AbstractController::handleForm() (nicolas-grekas)

This PR was merged into the 5.3-dev branch.

Discussion
----------

[FrameworkBundle] improve AbstractController::handleForm()

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Tickets       | (
| License       | MIT
| Doc PR        | -

Related to #41178

Commits
-------

7c69682775 [FrameworkBundle] improve AbstractController::handleForm()
This commit is contained in:
Nicolas Grekas 2021-05-12 08:36:51 +02:00
commit 1921c78c7f
2 changed files with 40 additions and 14 deletions

View File

@ -297,23 +297,30 @@ abstract class AbstractController implements ServiceSubscriberInterface
* * if the form is submitted but invalid, $render is called and a 422 HTTP status code is set if the current status hasn't been customized * * if the form is submitted but invalid, $render is called and a 422 HTTP status code is set if the current status hasn't been customized
* * if the form is submitted and valid, $onSuccess is called, usually this method saves the data and returns a 303 HTTP redirection * * if the form is submitted and valid, $onSuccess is called, usually this method saves the data and returns a 303 HTTP redirection
* *
* @param callable(FormInterface, mixed): Response $onSuccess * For both callables, instead of "mixed", you can use your form's data class as a type-hint for argument #2.
* @param callable(FormInterface, mixed): Response $render *
* @param callable(FormInterface, mixed, Request): Response $onSuccess
* @param callable(FormInterface, mixed, Request): Response $render
*/ */
public function handleForm(FormInterface $form, Request $request, callable $onSuccess, callable $render): Response public function handleForm(FormInterface $form, Request $request, callable $onSuccess, callable $render): Response
{ {
$form->handleRequest($request); $form->handleRequest($request);
$submitted = $form->isSubmitted(); $submitted = $form->isSubmitted();
$data = $form->getData(); $data = $form->getData();
if ($submitted && $form->isValid()) {
return $onSuccess($form, $data); if ($isValid = $submitted && $form->isValid()) {
$response = $onSuccess($form, $data, $request);
} else {
$response = $render($form, $data, $request);
if ($submitted && 200 === $response->getStatusCode()) {
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
}
} }
$response = $render($form, $data); if (!$response instanceof Response) {
if ($submitted && 200 === $response->getStatusCode()) { throw new \TypeError(sprintf('The "%s" callable passed to "%s::handleForm()" must return a Response, "%s" returned.', $isValid ? '$onSuccess' : '$render', get_debug_type($this), get_debug_type($response)));
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
} }
return $response; return $response;

View File

@ -433,10 +433,10 @@ class AbstractControllerTest extends TestCase
$response = $controller->handleForm( $response = $controller->handleForm(
$form, $form,
Request::create('https://example.com'), Request::create('https://example.com'),
function (FormInterface $form, $data): Response { function (FormInterface $form, $data, Request $request): Response {
return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER); return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER);
}, },
function (FormInterface $form, $data): Response { function (FormInterface $form, $data, Request $request): Response {
return new Response('rendered'); return new Response('rendered');
} }
); );
@ -455,10 +455,10 @@ class AbstractControllerTest extends TestCase
$response = $controller->handleForm( $response = $controller->handleForm(
$form, $form,
Request::create('https://example.com'), Request::create('https://example.com'),
function (FormInterface $form): Response { function (FormInterface $form, $data, Request $request): Response {
return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER); return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER);
}, },
function (FormInterface $form): Response { function (FormInterface $form, $data, Request $request): Response {
return new Response('rendered'); return new Response('rendered');
} }
); );
@ -477,10 +477,10 @@ class AbstractControllerTest extends TestCase
$response = $controller->handleForm( $response = $controller->handleForm(
$form, $form,
Request::create('https://example.com'), Request::create('https://example.com'),
function (FormInterface $form): Response { function (FormInterface $form, $data, Request $request): Response {
return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER); return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER);
}, },
function (FormInterface $form): Response { function (FormInterface $form, $data, Request $request): Response {
return new Response('rendered'); return new Response('rendered');
} }
); );
@ -490,6 +490,25 @@ class AbstractControllerTest extends TestCase
$this->assertSame('https://example.com/redir', $response->getTargetUrl()); $this->assertSame('https://example.com/redir', $response->getTargetUrl());
} }
public function testHandleFormTypeError()
{
$form = $this->createMock(FormInterface::class);
$form->expects($this->once())->method('isSubmitted')->willReturn(true);
$form->expects($this->once())->method('isValid')->willReturn(true);
$controller = $this->createController();
$this->expectException(\TypeError::class);
$this->expectExceptionMessage('The "$onSuccess" callable passed to "Symfony\Bundle\FrameworkBundle\Tests\Controller\TestAbstractController::handleForm()" must return a Response, "string" returned.');
$response = $controller->handleForm(
$form,
Request::create('https://example.com'),
function () { return 'abc'; },
function () { return 'abc'; }
);
}
public function testRedirectToRoute() public function testRedirectToRoute()
{ {
$router = $this->createMock(RouterInterface::class); $router = $this->createMock(RouterInterface::class);