Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b003dd8

Browse filesBrowse files
committed
[FrameworkBundle] Introduce AbstractController::renderForm()
1 parent fef1099 commit b003dd8
Copy full SHA for b003dd8

File tree

3 files changed

+48
-108
lines changed
Filter options

3 files changed

+48
-108
lines changed

‎src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+1-1Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
+14-36Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,20 @@ protected function render(string $view, array $parameters = [], Response $respon
266266
return $response;
267267
}
268268

269+
/**
270+
* Renders a view for a form.
271+
*/
272+
protected function renderForm(string $view, FormInterface $form, array $parameters = [], Response $response = null, string $formVariableName = 'form'): Response
273+
{
274+
$response = $this->render($view, [$formVariableName => $form->createView()] + $parameters, $response);
275+
276+
if ($form->isSubmitted() && !$form->isValid()) {
277+
$response->setStatusCode(422);
278+
}
279+
280+
return $response;
281+
}
282+
269283
/**
270284
* Streams a view.
271285
*/
@@ -290,42 +304,6 @@ protected function stream(string $view, array $parameters = [], StreamedResponse
290304
return $response;
291305
}
292306

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-
329307
/**
330308
* Returns a NotFoundHttpException.
331309
*

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
+33-71Lines changed: 33 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
use Symfony\Component\Form\Form;
2222
use Symfony\Component\Form\FormBuilderInterface;
2323
use Symfony\Component\Form\FormConfigInterface;
24+
use Symfony\Component\Form\FormError;
2425
use Symfony\Component\Form\FormFactoryInterface;
2526
use Symfony\Component\Form\FormInterface;
27+
use Symfony\Component\Form\FormView;
2628
use Symfony\Component\HttpFoundation\BinaryFileResponse;
2729
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
2830
use Symfony\Component\HttpFoundation\File\File;
@@ -411,102 +413,62 @@ public function testRenderTwig()
411413
$this->assertEquals('bar', $controller->render('foo')->getContent());
412414
}
413415

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

418426
$container = new Container();
419427
$container->set('twig', $twig);
420428

421429
$controller = $this->createController();
422430
$controller->setContainer($container);
423431

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-
);
432+
$response = $controller->renderForm('foo', $form, ['bar' => 'bar']);
443433

444434
$this->assertTrue($response->isSuccessful());
445-
$this->assertSame('rendered', $response->getContent());
435+
$this->assertSame('bar', $response->getContent());
446436
}
447437

448-
public function testHandleFormInvalid()
438+
public function testRenderFormSubmittedAndInvalid()
449439
{
450-
$form = $this->createMock(FormInterface::class);
440+
$formView = new FormView();
441+
442+
$form = $this->getMockBuilder(FormInterface::class)->getMock();
443+
$form->expects($this->once())->method('createView')->willReturn($formView);
451444
$form->expects($this->once())->method('isSubmitted')->willReturn(true);
452445
$form->expects($this->once())->method('isValid')->willReturn(false);
453446

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-
}
447+
$twig = $this->getMockBuilder(Environment::class)->disableOriginalConstructor()->getMock();
448+
$twig->expects($this->once())->method('render')->with('foo', ['myForm' => $formView, 'bar' => 'bar'])->willReturn('bar');
469449

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);
450+
$container = new Container();
451+
$container->set('twig', $twig);
475452

476453
$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-
);
454+
$controller->setContainer($container);
487455

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

493-
public function testHandleFormTypeError()
458+
$this->assertSame(422, $response->getStatusCode());
459+
$this->assertSame('bar', $response->getContent());
460+
}
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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.