8000 [FrameworkBundle] Introduce AbstractController::renderForm() · symfony/symfony@27f8f50 · GitHub
[go: up one dir, main page]

Skip to content

Commit 27f8f50

Browse files
committed
[FrameworkBundle] Introduce AbstractController 8000 ::renderForm()
1 parent fef1099 commit 27f8f50

File tree

3 files changed

+51
-107
lines changed

3 files changed

+51
-107
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ CHANGELOG
77
* Deprecate the `session.storage` alias and `session.storage.*` services, use the `session.storage.factory` alias and `session.storage.factory.*` services instead
88
* Deprecate the `framework.session.storage_id` configuration option, use the `framework.session.storage_factory_id` configuration option instead
99
* Deprecate the `session` service and the `SessionInterface` alias, use the `Request::getSession()` or the new `RequestStack::getSession()` methods instead
10-
* Added `AbstractController::handleForm()` to handle a form and set the appropriate HTTP status code
10+
* Added `AbstractController::renderForm()` to render a form and set the appropriate HTTP status code
1111
* Added support for configuring PHP error level to log levels
1212
* Added the `dispatcher` option to `debug:event-dispatcher`
1313
* Added the `event_dispatcher.dispatcher` tag

src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,24 @@ protected function render(string $view, array $parameters = [], Response $respon
266266
return $response;
267267
}
268268

269+
/**
270+
* Renders a view for a form.
271+
*
272+
* The FormView instance is passed to the template in a variable named
273+
* "form" (can be changed via $formVar argument).
274+
* If the form is invalid, a 422 status code is returned.
275+
*/
276+
protected function renderForm(string $view, FormInterface $form, array $parameters = [], Response $response = null, string $formVar = 'form'): Response
277+
{
278+
$response = $this->render($view, [$formVar => $form->createView()] + $parameters, $response);
279+
280+
if ($form->isSubmitted() && !$form->isValid()) {
281+
$response->setStatusCode(422);
282+
}
283+
284+
return $response;
285+
}
286+
269287
/**
270288
* Streams a view.
271289
*/
@@ -290,42 +308,6 @@ protected function stream(string $view, array $parameters = [], StreamedResponse
290308
return $response;
291309
}
292310

293-
/**
294-
* Handles a form.
295-
*
296-
* * if the form is not submitted, $render is called
297-
* * 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
298-
* * if the form is submitted and valid, $onSuccess is called, usually this method saves the data and returns a 303 HTTP redirection
299-
*
300-
* For both callables, instead of "mixed", you can use your form's data class as a type-hint for argument #2.
301-
*
302-
* @param callable(FormInterface, mixed, Request): Response $onSuccess
303-
* @param callable(FormInterface, mixed, Request): Response $render
304-
*/
305-
public function handleForm(FormInterface $form, Request $request, callable $onSuccess, callable $render): Response
306-
{
307-
$form->handleRequest($request);
308-
309-
$submitted = $form->isSubmitted();
310-
$data = $form->getData();
311-
312-
if ($isValid = $submitted && $form->isValid()) {
313-
$response = $onSuccess($form, $data, $request);
314-
} else {
315-
$response = $render($form, $data, $request);
316-
317-
if ($response instanceof Response && $submitted && 200 === $response->getStatusCode()) {
318-
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
319-
}
320-
}
321-
322-
if (!$response instanceof Response) {
323-
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)));
324-
}
325-
326-
return $response;
327-
}
328-
329311
/**
330312
* Returns a NotFoundHttpException.
331313
*

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php

Lines changed: 32 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Symfony\Component\Form\FormConfigInterface;
2424
use Symfony\Component\Form\FormFactoryInterface;
2525
use Symfony\Component\Form\FormInterface;
26+
use Symfony\Component\Form\FormView;
2627
use Symfony\Component\HttpFoundation\BinaryFileResponse;
2728
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
2829
use Symfony\Component\HttpFoundation\File\File;
@@ -411,102 +412,63 @@ public function testRenderTwig()
411412
$this->assertEquals('bar', $controller->render('foo')->getContent());
412413
}
413414

414-
public function testStreamTwig()
415+
public function testRenderFormNew()
415416
{
416-
$twig = $this->createMock(Environment::class);
417+
$formView = new FormView();
418+
419+
$form = $this->getMockBuilder(FormInterface::class)->getMock();
420+
$form->expects($this->once())->method('createView')->willReturn($formView);
421+
422+
$twig = $this->getMockBuilder(Environment::class)->disableOriginalConstructor()->getMock();
423+
$twig->expects($this->once())->method('render')->with('foo', ['form' => $formView, 'bar' => 'bar'])->willReturn('bar');
417424

418425
$container = new Container();
419426
$container->set('twig', $twig);
420427

421428
$controller = $this->createController();
422429
$controller->setContainer($container);
423430

424-
$this->assertInstanceOf(StreamedResponse::class, $controller->stream('foo'));
425-
}
426-
427-
public function testHandleFormNotSubmitted()
428-
{
429-
$form = $this->createMock(FormInterface::class);
430-
$form->expects($this->once())->method('isSubmitted')->willReturn(false);
431-
432-
$controller = $this->createController();
433-
$response = $controller->handleForm(
434-
$form,
435-
Request::create('https://example.com'),
436-
function (FormInterface $form, $data, Request $request): Response {
437-
return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER);
438-
},
439-
function (FormInterface $form, $data, Request $request): Response {
440-
return new Response('rendered');
441-
}
442-
);
431+
$response = $controller->renderForm('foo', $form, ['bar' => 'bar']);
443432

444433
$this->assertTrue($response->isSuccessful());
445-
$this->assertSame('rendered', $response->getContent());
434+
$this->assertSame('bar', $response->getContent());
446435
}
447436

448-
public function testHandleFormInvalid()
437+
public function testRenderFormSubmittedAndInvalid()
449438
{
450-
$form = $this->createMock(FormInterface::class);
439+
$formView = new FormView();
440+
441+
$form = $this->getMockBuilder(FormInterface::class)->getMock();
442+
$form->expects($this->once())->method('createView')->willReturn($formView);
451443
$form->expects($this->once())->method('isSubmitted')->willReturn(true);
452444
$form->expects($this->once())->method('isValid')->willReturn(false);
453445

454-
$controller = $this->createController();
455-
$response = $controller->handleForm(
456-
$form,
457-
Request::create('https://example.com'),
458-
function (FormInterface $form, $data, Request $request): Response {
459-
return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER);
460-
},
461-
function (FormInterface $form, $data, Request $request): Response {
462-
return new Response('rendered');
463-
}
464-
);
465-
466-
$this->assertSame(Response::HTTP_UNPROCESSABLE_ENTITY, $response->getStatusCode());
467-
$this->assertSame('rendered', $response->getContent());
468-
}
446+
$twig = $this->getMockBuilder(Environment::class)->disableOriginalConstructor()->getMock();
447+
$twig->expects($this->once())->method('render')->with('foo', ['myForm' => $formView, 'bar' => 'bar'])->willReturn('bar');
469448

470-
public function testHandleFormValid()
471-
{
472-
$form = $this->createMock(FormInterface::class);
473-
$form->expects($this->once())->method('isSubmitted')->willReturn(true);
474-
$form->expects($this->once())->method('isValid')->willReturn(true);
449+
$container = new Container();
450+
$container->set('twig', $twig);
475451

476452
$controller = $this->createController();
477-
$response = $controller->handleForm(
478-
$form,
479-
Request::create('https://example.com'),
480-
function (FormInterface $form, $data, Request $request): Response {
481-
return new RedirectResponse('https://example.com/redir', Response::HTTP_SEE_OTHER);
482-
},
483-
function (FormInterface $form, $data, Request $request): Response {
484-
return new Response('rendered');
485-
}
486-
);
453+
$controller->setContainer($container);
487454

488-
$this->assertInstanceOf(RedirectResponse::class, $response);
489-
$this->assertSame(Response::HTTP_SEE_OTHER, $response->getStatusCode());
490-
$this->assertSame('https://example.com/redir', $response->getTargetUrl());
455+
$response = $controller->renderForm('foo', $form, ['bar' => 'bar'], null, 'myForm');
456+
457+
$this->assertSame(422, $response->getStatusCode());
458+
$this->assertSame('bar', $response->getContent());
491459
}
492460

493-
public function testHandleFormTypeError()
461+
public function testStreamTwig()
494462
{
495-
$form = $this->createMock(FormInterface::class);
496-
$form->expects($this->once())->method('isSubmitted')->willReturn(true);
497-
$form->expects($this->once())->method('isValid')->willReturn(false);
463+
$twig = $this->createMock(Environment::class);
498464

499-
$controller = $this->createController();
465+
$container = new Container();
466+
$container->set('twig', $twig);
500467

501-
$this->expectException(\TypeError::class);
502-
$this->expectExceptionMessage('The "$render" callable passed to "Symfony\Bundle\FrameworkBundle\Tests\Controller\TestAbstractController::handleForm()" must return a Response, "string" returned.');
468+
$controller = $this->createController();
469+
$controller->setContainer($container);
503470

504-
$response = $controller->handleForm(
505-
$form,
506-
Request::create('https://example.com'),
507-
function () { return 'abc'; },
508-
function () { return 'abc'; }
509-
);
471+
$this->assertInstanceOf(StreamedResponse::class, $controller->stream('foo'));
510472
}
511473

512474
public function testRedirectToRoute()

0 commit comments

Comments
 (0)
0