Skip to content

Commit 45ca5ed

Browse files
committed
[FrameworkBundle] Add BC layer and FormView handling after #46854
1 parent 58117d7 commit 45ca5ed

File tree

6 files changed

+99
-7
lines changed

6 files changed

+99
-7
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
* Add `resolve-env` option to `debug:config` command to display actual values of environment variables in dumped configuration
88
* Add `NotificationAssertionsTrait`
99
* Add option `framework.catch_all_throwables` to allow `Symfony\Component\HttpKernel\HttpKernel` to catch all kinds of `Throwable`
10-
* Make `AbstractController::render()` able to deal with forms and deprecate `renderForm()`
10+
* Make `AbstractController::render()` able to deal with forms and deprecate `renderForm()` when `framework.form.controllers_render_form_views` is `true`
1111
* Deprecate the `Symfony\Component\Serializer\Normalizer\ObjectNormalizer` and
1212
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` autowiring aliases, type-hint against
1313
`Symfony\Component\Serializer\Normalizer\NormalizerInterface` or implement `NormalizerAwareInterface` instead

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

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Form\FormBuilderInterface;
2020
use Symfony\Component\Form\FormFactoryInterface;
2121
use Symfony\Component\Form\FormInterface;
22+
use Symfony\Component\Form\FormView;
2223
use Symfony\Component\HttpFoundation\BinaryFileResponse;
2324
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
2425
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -58,6 +59,9 @@ abstract class AbstractController implements ServiceSubscriberInterface
5859
*/
5960
protected $container;
6061

62+
// To be removed in 7.0
63+
private bool $renderFormViews = false;
64+
6165
/**
6266
* @required
6367
*/
@@ -70,6 +74,14 @@ public function setContainer(ContainerInterface $container): ?ContainerInterface
7074
return $previous;
7175
}
7276

77+
/**
78+
* @internal To be removed in 7.0
79+
*/
80+
public function setRenderFormViews(bool $renderFormViews): void
81+
{
82+
$this->renderFormViews = $renderFormViews;
83+
}
84+
7385
/**
7486
* Gets a container parameter by its name.
7587
*/
@@ -233,9 +245,11 @@ protected function renderView(string $view, array $parameters = []): string
233245
throw new \LogicException('You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
234246
}
235247

236-
foreach ($parameters as $k => $v) {
237-
if ($v instanceof FormInterface) {
238-
$parameters[$k] = $v->createView();
248+
if ($this->renderFormViews) {
249+
foreach ($parameters as $k => $v) {
250+
if ($v instanceof FormInterface) {
251+
$parameters[$k] = $v->createView();
252+
}
239253
}
240254
}
241255

@@ -256,9 +270,12 @@ protected function render(string $view, array $parameters = [], Response $respon
256270
$response = new Response();
257271
}
258272

259-
if (200 === $response->getStatusCode()) {
273+
if ($this->renderFormViews && 200 === $response->getStatusCode()) {
260274
foreach ($parameters as $v) {
261-
if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
275+
if (
276+
$v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()
277+
|| $v instanceof FormView && (!$v->vars['valid'] ?? true)
278+
) {
262279
$response->setStatusCode(422);
263280
break;
264281
}
@@ -281,7 +298,12 @@ protected function renderForm(string $view, array $parameters = [], Response $re
281298
{
282299
trigger_deprecation('symfony/framework-bundle', '6.2', 'The "%s::renderForm()" method is deprecated, use "render()" instead.', get_debug_type($this));
283300

284-
return $this->render($view, $parameters, $response);
301+
$oldValue = $this->renderFormViews;
302+
$this->renderFormViews = true;
303+
$response = $this->render($view, $parameters, $response);
304+
$this->renderFormViews = $oldValue;
305+
306+
return $response;
285307
}
286308

287309
/**

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,21 @@ private function addFormSection(ArrayNodeDefinition $rootNode, callable $enableI
239239
->end()
240240
// to be deprecated in Symfony 6.1
241241
->booleanNode('legacy_error_messages')->end()
242+
// to be deprecated in Symfony 7.1
243+
->booleanNode('controllers_render_form_views')
244+
->info('Enables "AbstractController::render()" method to convert FormInterface to FormView and setting 422 status code when invalid.')
245+
->defaultFalse()
246+
->validate()
247+
->always()
248+
->then(function ($v) {
249+
if (false === $v) {
250+
trigger_deprecation('symfony/framework-bundle', '6.2', 'Setting the "framework.form.controllers_render_form_views" option to "false" is deprecated. It will have no effect as of Symfony 7.0.');
251+
}
252+
253+
return $v;
254+
})
255+
->end()
256+
->end()
242257
->end()
243258
->end()
244259
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ class FrameworkExtension extends Extension
259259
private bool $notifierConfigEnabled = false;
260260
private bool $serializerConfigEnabled = false;
261261
private bool $propertyAccessConfigEnabled = false;
262+
// To be removed in 7.0
263+
private bool $controllersRenderFormViews = false;
262264
private static bool $lockConfigEnabled = false;
263265

264266
/**
@@ -596,6 +598,7 @@ public function load(array $configs, ContainerBuilder $container)
596598
$container->registerForAutoconfiguration(ValueResolverInterface::class)
597599
->addTag('controller.argument_value_resolver');
598600
$container->registerForAutoconfiguration(AbstractController::class)
601+
->addMethodCall('setRenderFormViews', [$this->controllersRenderFormViews])
599602
->addTag('controller.service_arguments');
600603
$container->registerForAutoconfiguration(DataCollectorInterface::class)
601604
->addTag('data_collector');
@@ -746,6 +749,8 @@ private function registerFormConfiguration(array $config, ContainerBuilder $cont
746749
->clearTag('kernel.reset')
747750
;
748751
}
752+
753+
$this->controllersRenderFormViews = $config['form']['controllers_render_form_views'];
749754
}
750755

751756
private function registerHttpCacheConfiguration(array $config, ContainerBuilder $container, bool $httpMethodOverride)

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,29 @@ public function testRenderTwig()
392392
$this->assertEquals('bar', $controller->render('foo')->getContent());
393393
}
394394

395+
/**
396+
* @group legacy
397+
*/
395398
public function testRenderViewWithForm()
399+
{
400+
$form = $this->getMockBuilder(FormInterface::class)->getMock();
401+
$form->expects($this->never())->method('createView');
402+
403+
$twig = $this->getMockBuilder(Environment::class)->disableOriginalConstructor()->getMock();
404+
$twig->expects($this->once())->method('render')->with('foo', ['bar' => $form])->willReturn('bar');
405+
406+
$container = new Container();
407+
$container->set('twig', $twig);
408+
409+
$controller = $this->createController();
410+
$controller->setContainer($container);
411+
412+
$content = $controller->renderView('foo', ['bar' => $form]);
413+
414+
$this->assertSame('bar', $content);
415+
}
416+
417+
public function testRenderViewWithFormHandlesFormView()
396418
{
397419
$formView = new FormView();
398420

@@ -407,13 +429,39 @@ public function testRenderViewWithForm()
407429

408430
$controller = $this->createController();
409431
$controller->setContainer($container);
432+
$controller->setRenderFormViews(true);
410433

411434
$content = $controller->renderView('foo', ['bar' => $form]);
412435

413436
$this->assertSame('bar', $content);
414437
}
415438

439+
/**
440+
* @group legacy
441+
*/
416442
public function testRenderWithFormSubmittedAndInvalid()
443+
{
444+
$form = $this->getMockBuilder(FormInterface::class)->getMock();
445+
$form->expects($this->never())->method('createView');
446+
$form->expects($this->never())->method('isSubmitted');
447+
$form->expects($this->never())->method('isValid');
448+
449+
$twig = $this->getMockBuilder(Environment::class)->disableOriginalConstructor()->getMock();
450+
$twig->expects($this->once())->method('render')->with('foo', ['bar' => $form])->willReturn('bar');
451+
452+
$container = new Container();
453+
$container->set('twig', $twig);
454+
455+
$controller = $this->createController();
456+
$controller->setContainer($container);
457+
458+
$response = $controller->render('foo', ['bar' => $form]);
459+
460+
$this->assertSame(200, $response->getStatusCode());
461+
$this->assertSame('bar', $response->getContent());
462+
}
463+
464+
public function testRenderWithFormSubmittedAndInvalidHandlesStatusCode()
417465
{
418466
$formView = new FormView();
419467

@@ -430,6 +478,7 @@ public function testRenderWithFormSubmittedAndInvalid()
430478

431479
$controller = $this->createController();
432480
$controller->setContainer($container);
481+
$controller->setRenderFormViews(true);
433482

434483
$response = $controller->render('foo', ['bar' => $form]);
435484

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ protected static function getBundleDefaultConfig()
453453
'enabled' => null, // defaults to csrf_protection.enabled
454454
'field_name' => '_token',
455455
],
456+
'controllers_render_form_views' => false,
456457
],
457458
'esi' => ['enabled' => false],
458459
'ssi' => ['enabled' => false],

0 commit comments

Comments
 (0)