From 43a51714d4d816b04b5f44c711b6ac504fac7808 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Fri, 23 Mar 2018 09:52:57 +0100 Subject: [PATCH] [Messenger] Added a middleware that validates messages --- .../DependencyInjection/Configuration.php | 12 +++-- .../FrameworkExtension.php | 8 ++++ .../Resources/config/messenger.xml | 6 +++ .../Resources/config/schema/symfony-1.0.xsd | 5 +++ .../DependencyInjection/ConfigurationTest.php | 3 ++ .../Fixtures/php/messenger_validation.php | 11 +++++ .../Fixtures/xml/messenger_validation.xml | 15 +++++++ .../Fixtures/yml/messenger_validation.yml | 5 +++ .../FrameworkExtensionTest.php | 11 +++++ .../Exception/ValidationFailedException.php | 44 +++++++++++++++++++ .../Middleware/ValidationMiddleware.php | 39 ++++++++++++++++ 11 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_validation.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_validation.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_validation.yml create mode 100644 src/Symfony/Component/Messenger/Exception/ValidationFailedException.php create mode 100644 src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 146be09022..154ae76def 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1005,10 +1005,14 @@ class Configuration implements ConfigurationInterface ->arrayNode('middlewares') ->addDefaultsIfNotSet() ->children() - ->arrayNode('doctrine_transaction') - ->canBeEnabled() - ->children() - ->scalarNode('entity_manager_name')->info('The name of the entity manager to use')->defaultNull()->end() + ->arrayNode('doctrine_transaction') + ->canBeEnabled() + ->children() + ->scalarNode('entity_manager_name')->info('The name of the entity manager to use')->defaultNull()->end() + ->end() + ->end() + ->arrayNode('validation') + ->{!class_exists(FullStack::class) && class_exists(Validation::class) ? 'canBeDisabled' : 'canBeEnabled'}() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index ff7dbeaa5d..248ad11eaa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1459,6 +1459,14 @@ class FrameworkExtension extends Extension } else { $container->removeDefinition('messenger.middleware.doctrine_transaction'); } + + if ($config['middlewares']['validation']['enabled']) { + if (!$container->has('validator')) { + throw new LogicException('The Validation middleware is only available when the Validator component is installed and enabled. Try running "composer require symfony/validator".'); + } + } else { + $container->removeDefinition('messenger.middleware.validator'); + } } private function registerCacheConfiguration(array $config, ContainerBuilder $container) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index cbba149b2f..580e2b8f4a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -25,6 +25,12 @@ + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index ab205bd267..fdf9ec5b07 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -371,6 +371,7 @@ + @@ -378,4 +379,8 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 6fc0ebd1cf..1d96df88a6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -258,6 +258,9 @@ class ConfigurationTest extends TestCase 'enabled' => false, 'entity_manager_name' => null, ), + 'validation' => array( + 'enabled' => false, + ), ), ), ); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_validation.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_validation.php new file mode 100644 index 0000000000..9776e0b5b2 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_validation.php @@ -0,0 +1,11 @@ +loadFromExtension('framework', array( + 'messenger' => array( + 'middlewares' => array( + 'validation' => array( + 'enabled' => false, + ), + ), + ), +)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_validation.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_validation.xml new file mode 100644 index 0000000000..66c104d385 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_validation.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_validation.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_validation.yml new file mode 100644 index 0000000000..276182d2bb --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_validation.yml @@ -0,0 +1,5 @@ +framework: + messenger: + middlewares: + validation: + enabled: false diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 2176afdbcf..2ba8907135 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -45,6 +45,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer; use Symfony\Component\Translation\DependencyInjection\TranslatorPass; use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass; +use Symfony\Component\Validator\Validation; use Symfony\Component\Workflow; abstract class FrameworkExtensionTest extends TestCase @@ -532,6 +533,16 @@ abstract class FrameworkExtensionTest extends TestCase $this->assertEquals('foobar', $def->getArgument(1)); } + public function testMessengerValidationDisabled() + { + if (!class_exists(Validation::class)) { + self::markTestSkipped('Skipping tests since Validator component is not installed'); + } + + $container = $this->createContainerFromFile('messenger_validation'); + $this->assertFalse($container->hasDefinition('messenger.middleware.validator')); + } + public function testTranslator() { $container = $this->createContainerFromFile('full'); diff --git a/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php b/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php new file mode 100644 index 0000000000..0e06ceaa05 --- /dev/null +++ b/src/Symfony/Component/Messenger/Exception/ValidationFailedException.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +use Symfony\Component\Validator\ConstraintViolationListInterface; + +/** + * @author Tobias Nyholm + */ +class ValidationFailedException extends \RuntimeException implements ExceptionInterface +{ + private $violations; + private $violatingMessage; + + /** + * @param object $violatingMessage + */ + public function __construct($violatingMessage, ConstraintViolationListInterface $violations) + { + $this->violatingMessage = $violatingMessage; + $this->violations = $violations; + + parent::__construct(sprintf('Message of type "%s" failed validation.', get_class($this->violatingMessage))); + } + + public function getViolatingMessage() + { + return $this->violatingMessage; + } + + public function getViolations(): ConstraintViolationListInterface + { + return $this->violations; + } +} diff --git a/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php b/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php new file mode 100644 index 0000000000..38264a1757 --- /dev/null +++ b/src/Symfony/Component/Messenger/Middleware/ValidationMiddleware.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Exception\ValidationFailedException; +use Symfony\Component\Messenger\MiddlewareInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; + +/** + * @author Tobias Nyholm + */ +class ValidationMiddleware implements MiddlewareInterface +{ + private $validator; + + public function __construct(ValidatorInterface $validator) + { + $this->validator = $validator; + } + + public function handle($message, callable $next) + { + $violations = $this->validator->validate($message); + if (count($violations)) { + throw new ValidationFailedException($message, $violations); + } + + return $next($message); + } +}