diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 6bb39e9f0e..b2096087bc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * Added `ControllerTrait::isFormValid()` + 4.2.0 ----- @@ -12,7 +17,7 @@ CHANGELOG * Deprecated the `Symfony\Bundle\FrameworkBundle\Controller\Controller` class in favor of `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`. * Enabled autoconfiguration for `Psr\Log\LoggerAwareInterface` * Added new "auto" mode for `framework.session.cookie_secure` to turn it on when HTTPS is used - * Removed the `framework.messenger.encoder` and `framework.messenger.decoder` options. Use the `framework.messenger.serializer.id` option to replace the Messenger serializer. + * Removed the `framework.messenger.encoder` and `framework.messenger.decoder` options. Use the `framework.messenger.serializer.id` option to replace the Messenger serializer. * Deprecated the `ContainerAwareCommand` class in favor of `Symfony\Component\Console\Command\Command` * Made `debug:container` and `debug:autowiring` ignore backslashes in service ids * Deprecated the `Templating\Helper\TranslatorHelper::transChoice()` method, use the `trans()` one instead with a `%count%` parameter @@ -83,17 +88,17 @@ CHANGELOG * Deprecated the `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()` methods. * Deprecated `AddCacheClearerPass`, use tagged iterator arguments instead. * Deprecated `AddCacheWarmerPass`, use tagged iterator arguments instead. - * Deprecated `TranslationDumperPass`, use + * Deprecated `TranslationDumperPass`, use `Symfony\Component\Translation\DependencyInjection\TranslationDumperPass` instead - * Deprecated `TranslationExtractorPass`, use + * Deprecated `TranslationExtractorPass`, use `Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass` instead - * Deprecated `TranslatorPass`, use + * Deprecated `TranslatorPass`, use `Symfony\Component\Translation\DependencyInjection\TranslatorPass` instead * Added `command` attribute to the `console.command` tag which takes the command name as value, using it makes the command lazy * Added `cache:pool:prune` command to allow manual stale cache item pruning of supported PSR-6 and PSR-16 cache pool implementations - * Deprecated `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`, use + * Deprecated `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`, use `Symfony\Component\Translation\Reader\TranslationReader` instead * Deprecated `translation.loader` service, use `translation.reader` instead * `AssetsInstallCommand::__construct()` now takes an instance of diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index 451b83931a..51bc264a6e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -326,6 +326,28 @@ trait ControllerTrait return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options); } + /** + * Handles request and check form validity. + * + * @final + */ + protected function isFormValid(FormInterface $form, Request $request = null): bool + { + if ($form->isSubmitted()) { + throw new \LogicException('The form is already submitted, use $form->isValid() directly.'); + } + + if (!$request) { + $request = $this->container->get('request_stack')->getCurrentRequest(); + } + + if (!$request) { + throw new \LogicException('You must pass a request as second argument because the request stack is empty.'); + } + + return $form->handleRequest($request)->isSubmitted() && $form->isValid(); + } + /** * Shortcut to return the Doctrine Registry service. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php index 41d463f573..0dcbc0e5db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php @@ -517,6 +517,117 @@ abstract class ControllerTraitTest extends TestCase $this->assertEquals($formBuilder, $controller->createFormBuilder('foo')); } + /** + * @expectedException \LogicException + * @expectedExceptionMessage The form is already submitted, use $form->isValid() directly. + */ + public function testIsFormValidWhenAlreadySubmitted() + { + $requestStack = new RequestStack(); + $requestStack->push($request = new Request()); + + $container = new Container(); + $container->set('request_stack', $requestStack); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + $form + ->expects($this->once()) + ->method('isSubmitted') + ->willReturn(true) + ; + + $controller->isFormValid($form); + } + + public function testIsFormValidWhenInvalid() + { + $requestStack = new RequestStack(); + $requestStack->push($request = new Request()); + + $container = new Container(); + $container->set('request_stack', $requestStack); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + $form + ->expects($this->at(0)) + ->method('isSubmitted') + ->willReturn(false) + ; + $form + ->expects($this->once()) + ->method('handleRequest') + ->with($request) + ->willReturn($form) + ; + $form + ->expects($this->at(2)) + ->method('isSubmitted') + ->willReturn(false) + ; + + $this->assertFalse($controller->isFormValid($form)); + } + + public function testIsFormValidWhenValid() + { + $requestStack = new RequestStack(); + $requestStack->push($request = new Request()); + + $container = new Container(); + $container->set('request_stack', $requestStack); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + $form + ->expects($this->at(0)) + ->method('isSubmitted') + ->willReturn(false) + ; + $form + ->expects($this->once()) + ->method('handleRequest') + ->with($request) + ->willReturn($form) + ; + $form + ->expects($this->at(2)) + ->method('isSubmitted') + ->willReturn(true) + ; + $form + ->expects($this->once()) + ->method('isValid') + ->willReturn(true) + ; + + $this->assertTrue($controller->isFormValid($form)); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You must pass a request as second argument because the request stack is empty. + */ + public function testIsFormValidWhenRequestStackIsEmpty() + { + $container = new Container(); + $container->set('request_stack', new RequestStack()); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + + $this->assertTrue($controller->isFormValid($form)); + } + public function testGetDoctrine() { $doctrine = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); @@ -569,5 +680,6 @@ trait TestControllerTrait createFormBuilder as public; getDoctrine as public; addLink as public; + isFormValid as public; } }