feature #26648 [Messenger] Added a middleware that validates messages (Nyholm)
This PR was squashed before being merged into the 4.1-dev branch (closes #26648).
Discussion
----------
[Messenger] Added a middleware that validates messages
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets |
| License | MIT
| Doc PR | coming
This is inspired by [Fervo](https://github.com/fervo/ValidatedMessage). It runs the validator over messages implementing the `ValidatedMessageInterface`.
Commits
-------
43a51714d4
[Messenger] Added a middleware that validates messages
This commit is contained in:
commit
56cd3d2f31
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -25,6 +25,12 @@
|
||||
<tag name="message_bus_middleware" priority="-10" />
|
||||
</service>
|
||||
|
||||
<service id="messenger.middleware.validator" class="Symfony\Component\Messenger\Middleware\ValidationMiddleware">
|
||||
<argument type="service" id="validator" />
|
||||
|
||||
<tag name="message_bus_middleware" priority="100" />
|
||||
</service>
|
||||
|
||||
<service id="messenger.middleware.doctrine_transaction" class="Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware">
|
||||
<argument type="service" id="doctrine" />
|
||||
<argument /> <!-- Entity manager name -->
|
||||
|
@ -371,6 +371,7 @@
|
||||
<xsd:complexType name="messenger_middleware">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="doctrine-transaction" type="messenger_doctrine_transaction" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="validation" type="messenger_validation" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
@ -378,4 +379,8 @@
|
||||
<xsd:attribute name="entity-manager-name" type="xsd:string" />
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="messenger_validation">
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
|
@ -258,6 +258,9 @@ class ConfigurationTest extends TestCase
|
||||
'enabled' => false,
|
||||
'entity_manager_name' => null,
|
||||
),
|
||||
'validation' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
$container->loadFromExtension('framework', array(
|
||||
'messenger' => array(
|
||||
'middlewares' => array(
|
||||
'validation' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:framework="http://symfony.com/schema/dic/symfony"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
|
||||
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
|
||||
|
||||
<framework:config>
|
||||
<framework:messenger>
|
||||
<framework:middlewares>
|
||||
<framework:validation enabled="false"/>
|
||||
</framework:middlewares>
|
||||
</framework:messenger>
|
||||
</framework:config>
|
||||
</container>
|
@ -0,0 +1,5 @@
|
||||
framework:
|
||||
messenger:
|
||||
middlewares:
|
||||
validation:
|
||||
enabled: false
|
@ -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');
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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 <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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 <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user