├── .styleci.yml ├── BernardBundle.php ├── Collector └── ProducerCollector.php ├── Command └── DebugCommand.php ├── DependencyInjection ├── BernardExtension.php ├── Compiler │ ├── NormalizerPass.php │ └── ReceiverPass.php └── Configuration.php ├── EventListener └── SchemaListener.php ├── LICENSE ├── Normalizer └── DefaultMessageNormalizer.php ├── README.md ├── Resources ├── config │ ├── collector.xml │ ├── commands.xml │ └── services.xml └── views │ ├── Collector │ └── producer.html.twig │ └── Icon │ └── bernard.svg ├── Tests └── DependencyInjection │ ├── BernardExtensionTest.php │ ├── Compiler │ ├── NormalizerPassTest.php │ └── ReceiverPassTest.php │ └── ConfigurationTest.php └── composer.json /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: symfony 2 | risky: false 3 | 4 | disabled: 5 | - yoda_style 6 | -------------------------------------------------------------------------------- /BernardBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new ReceiverPass()) 17 | ->addCompilerPass(new NormalizerPass()) 18 | ; 19 | } 20 | 21 | public function registerCommands(Application $application) 22 | { 23 | parent::registerCommands($application); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Collector/ProducerCollector.php: -------------------------------------------------------------------------------- 1 | data = [ 17 | 'messageCount' => 0, 18 | 'messages' => [], 19 | ]; 20 | } 21 | 22 | /** 23 | * Collects data for the given Request and Response. 24 | * 25 | * @param Request $request A Request instance 26 | * @param Response $response A Response instance 27 | * @param \Exception $exception An Exception instance 28 | */ 29 | public function collect(Request $request, Response $response, \Exception $exception = null) 30 | { 31 | // We don't collect anything from the request data 32 | } 33 | 34 | /** 35 | * Returns the name of the collector. 36 | * 37 | * @return string The collector name 38 | */ 39 | public function getName() 40 | { 41 | return 'bernard'; 42 | } 43 | 44 | public function onBernardProduce(EnvelopeEvent $event) 45 | { 46 | $envelope = $event->getEnvelope(); 47 | 48 | $this->data['messages'][(string) $event->getQueue()][] = [ 49 | 'name' => $envelope->getName(), 50 | 'message' => $this->cloneVar($envelope->getMessage()), 51 | 'timestamp' => $envelope->getTimestamp(), 52 | 'class' => $envelope->getClass(), 53 | ]; 54 | 55 | ++$this->data['messageCount']; 56 | } 57 | 58 | public static function getSubscribedEvents() 59 | { 60 | return array( 61 | BernardEvents::PRODUCE => 'onBernardProduce', 62 | ); 63 | } 64 | 65 | public function getMessageCount() 66 | { 67 | return $this->data['messageCount']; 68 | } 69 | 70 | public function getDistinctQueueCount() 71 | { 72 | return count($this->data['messages']); 73 | } 74 | 75 | public function getAllMessages() 76 | { 77 | return $this->data['messages']; 78 | } 79 | 80 | /** 81 | * Resets this data collector to its initial state. 82 | */ 83 | public function reset() 84 | { 85 | $this->data = [ 86 | 'messageCount' => 0, 87 | 'messages' => [], 88 | ]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Command/DebugCommand.php: -------------------------------------------------------------------------------- 1 | setName(null === $router ? 'bernard:debug' : $router); 29 | 30 | return; 31 | } 32 | 33 | $this->router = $router; 34 | } 35 | 36 | public function configure() 37 | { 38 | $this 39 | ->setName('bernard:debug') 40 | ->setDescription('Displays a table of receivers that are registered with "bernard.receiver" tag.') 41 | ; 42 | } 43 | 44 | protected function execute(InputInterface $input, OutputInterface $output) 45 | { 46 | if (null === $this->router) { 47 | $this->router = $this->getContainer()->get('bernard.router'); 48 | } 49 | 50 | $r = new \ReflectionProperty($this->router, 'receivers'); 51 | $r->setAccessible(true); 52 | 53 | $rows = []; 54 | foreach ($r->getValue($this->router) as $key => $val) { 55 | $rows[] = [$key, $val]; 56 | } 57 | 58 | $table = new Table($output); 59 | $table 60 | ->setHeaders(['Message', 'Service']) 61 | ->addRows($rows) 62 | ->render() 63 | ; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /DependencyInjection/BernardExtension.php: -------------------------------------------------------------------------------- 1 | load('services.xml'); 17 | $loader->load('commands.xml'); 18 | 19 | switch ($config['driver']) { 20 | case 'doctrine': 21 | $this->registerDoctrineConfiguration($config['options'], $container); 22 | 23 | break; 24 | 25 | case 'file': 26 | $this->registerFlatFileConfiguration($config['options'], $container); 27 | 28 | break; 29 | 30 | case 'phpamqp': 31 | $this->registerPhpAmqpConfiguration($config['options'], $container); 32 | 33 | break; 34 | 35 | case 'phpredis': 36 | $this->registerPhpRedisConfiguration($config['options'], $container); 37 | 38 | break; 39 | 40 | case 'predis': 41 | $this->registerPredisConfiguration($config['options'], $container); 42 | 43 | break; 44 | 45 | case 'ironmq': 46 | $this->registerIronMQConfiguration($config['options'], $container); 47 | 48 | break; 49 | 50 | case 'sqs': 51 | $this->registerSqsConfiguration($config['options'], $container); 52 | 53 | break; 54 | 55 | case 'pheanstalk': 56 | $this->registerPheanstalkConfiguration($config['options'], $container); 57 | 58 | break; 59 | } 60 | 61 | if ($config['driver'] === 'custom') { 62 | $container->setAlias('bernard.driver', $config['options']['custom_service']); 63 | } else { 64 | $container->setAlias('bernard.driver', 'bernard.driver.'.$config['driver']); 65 | } 66 | 67 | $this->registerListeners($config['listeners'], $container); 68 | 69 | if ($container->getParameter('kernel.debug')) { 70 | $loader->load('collector.xml'); 71 | } 72 | } 73 | 74 | private function registerDoctrineConfiguration($config, ContainerBuilder $container) 75 | { 76 | $container->setAlias('bernard.dbal.connection', 'doctrine.dbal.'.$config['connection'].'_connection'); 77 | $container 78 | ->getDefinition('bernard.listener.doctrine_schema') 79 | ->addTag('doctrine.event_listener', [ 80 | 'lazy' => true, 81 | 'event' => 'postGenerateSchema', 82 | 'connection' => $config['connection'], 83 | ] 84 | ); 85 | } 86 | 87 | private function registerFlatFileConfiguration(array $config, ContainerBuilder $container) 88 | { 89 | $container->getDefinition('bernard.driver.file')->replaceArgument(0, $config['directory']); 90 | } 91 | 92 | private function registerPhpAmqpConfiguration(array $config, ContainerBuilder $container) 93 | { 94 | $container->getDefinition('bernard.driver.phpamqp')->replaceArgument(0, new Reference($config['phpamqp_service'])) 95 | ->replaceArgument(1, $config['phpamqp_exchange']) 96 | ->replaceArgument(2, $config['phpamqp_default_message_parameters']); 97 | } 98 | 99 | private function registerPhpRedisConfiguration(array $config, ContainerBuilder $container) 100 | { 101 | $container->getDefinition('bernard.driver.phpredis')->replaceArgument(0, new Reference($config['phpredis_service'])); 102 | } 103 | 104 | private function registerPredisConfiguration(array $config, ContainerBuilder $container) 105 | { 106 | $container->getDefinition('bernard.driver.predis')->replaceArgument(0, new Reference($config['predis_service'])); 107 | } 108 | 109 | private function registerIronMQConfiguration(array $config, ContainerBuilder $container) 110 | { 111 | $container->getDefinition('bernard.driver.ironmq')->replaceArgument(0, new Reference($config['ironmq_service'])); 112 | } 113 | 114 | private function registerSqsConfiguration(array $config, ContainerBuilder $container) 115 | { 116 | $container->getDefinition('bernard.driver.sqs')->replaceArgument(0, new Reference($config['sqs_service'])) 117 | ->replaceArgument(1, $config['sqs_queue_map']) 118 | ->replaceArgument(2, $config['prefetch']); 119 | } 120 | 121 | private function registerPheanstalkConfiguration(array $config, ContainerBuilder $container) 122 | { 123 | $container->getDefinition('bernard.driver.pheanstalk')->replaceArgument(0, new Reference($config['pheanstalk_service'])); 124 | } 125 | 126 | private function registerListeners(array $config, ContainerBuilder $container) 127 | { 128 | foreach ($config as $id => $params) { 129 | if (empty($params) || (is_array($params) && !$params['enabled'])) { 130 | $container->removeDefinition('bernard.listener.'.$id); 131 | 132 | continue; 133 | } 134 | 135 | // Enable listener. 136 | $listener = $container->getDefinition('bernard.listener.'.$id); 137 | $listener->addTag('kernel.event_subscriber'); 138 | 139 | if ($id === 'logger') { 140 | $listener->replaceArgument(0, new Reference($params['service'])); 141 | } elseif ($id === 'failure') { 142 | $listener->replaceArgument(1, $params['queue_name']); 143 | } 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/NormalizerPass.php: -------------------------------------------------------------------------------- 1 | findTaggedServiceIds('bernard.normalizer'))); 16 | 17 | $container->getDefinition('bernard.normalizer')->replaceArgument(0, $normalizers); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/ReceiverPass.php: -------------------------------------------------------------------------------- 1 | findTaggedServiceIds('bernard.receiver') as $id => $tags) { 15 | foreach ($tags as $attrs) { 16 | if (!isset($attrs['message'])) { 17 | throw new \RuntimeException(sprintf('Each tag named "bernard.receiver" of service "%s" must have at "message" attribute that species the message name it is associated with.', $id)); 18 | } 19 | 20 | $receivers[$attrs['message']] = $id; 21 | } 22 | } 23 | 24 | $container->getDefinition('bernard.router')->replaceArgument(1, $receivers); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 16 | } else { 17 | // BC layer for symfony/config 4.1 and older 18 | $root = $tree->root('bernard'); 19 | } 20 | 21 | $root 22 | ->children() 23 | ->enumNode('driver') 24 | ->isRequired() 25 | ->cannotBeEmpty() 26 | ->values(['doctrine', 'file', 'phpamqp', 'phpredis', 'predis', 'ironmq', 'sqs', 'pheanstalk', 'custom']) 27 | ->end() 28 | 29 | ->arrayNode('options') 30 | ->addDefaultsIfNotSet() 31 | ->children() 32 | ->scalarNode('connection')->defaultValue('default')->end() 33 | ->scalarNode('directory')->defaultValue('%kernel.cache_dir%/bernard')->end() 34 | ->scalarNode('phpamqp_service')->defaultValue('old_sound_rabbit_mq.connection.default')->end() 35 | ->scalarNode('phpamqp_exchange')->defaultNull()->end() 36 | ->arrayNode('phpamqp_default_message_parameters') 37 | ->useAttributeAsKey('name') 38 | ->prototype('scalar')->end() 39 | ->end() 40 | ->scalarNode('phpredis_service')->defaultValue('snc_redis.bernard')->end() 41 | ->scalarNode('predis_service')->defaultValue('snc_redis.bernard')->end() 42 | ->scalarNode('ironmq_service')->defaultNull()->end() 43 | ->scalarNode('sqs_service')->defaultNull()->end() 44 | ->arrayNode('sqs_queue_map') 45 | ->useAttributeAsKey('name') 46 | ->prototype('scalar')->end() 47 | ->end() 48 | ->scalarNode('prefetch')->defaultNull()->end() 49 | ->scalarNode('pheanstalk_service')->defaultNull()->end() 50 | ->scalarNode('custom_service')->defaultNull()->end() 51 | ->end() 52 | ->end() 53 | 54 | ->arrayNode('listeners') 55 | ->addDefaultsIfNotSet() 56 | ->children() 57 | ->booleanNode('error_log')->defaultFalse()->end() 58 | ->arrayNode('logger') 59 | ->canBeEnabled() 60 | ->children() 61 | ->scalarNode('service')->defaultValue('logger')->end() 62 | ->end() 63 | ->beforeNormalization() 64 | ->ifString() 65 | ->then(function ($v) { 66 | return ['enabled' => true, 'service' => $v]; 67 | }) 68 | ->end() 69 | ->end() 70 | ->arrayNode('failure') 71 | ->canBeEnabled() 72 | ->children() 73 | ->scalarNode('queue_name')->defaultValue('failed')->end() 74 | ->end() 75 | ->beforeNormalization() 76 | ->ifString() 77 | ->then(function ($v) { 78 | return ['enabled' => true, 'queue_name' => $v]; 79 | }) 80 | ->end() 81 | ->end() 82 | ->end() 83 | ->end() 84 | ->end() 85 | ; 86 | 87 | $this 88 | ->validateDriver($root, 'file', 'directory') 89 | ->validateDriver($root, 'phpamqp', 'connection') 90 | ->validateDriver($root, 'phpamqp', 'phpamqp_exchange') 91 | ->validateDriver($root, 'phpredis', 'phpredis_service') 92 | ->validateDriver($root, 'predis', 'predis_service') 93 | ->validateDriver($root, 'ironmq', 'ironmq_service') 94 | ->validateDriver($root, 'sqs', 'sqs_service') 95 | ->validateDriver($root, 'pheanstalk', 'pheanstalk_service') 96 | ->validateDriver($root, 'custom', 'custom_service') 97 | ; 98 | 99 | return $tree; 100 | } 101 | 102 | /** 103 | * @param NodeDefinition $node 104 | * @param string $driver 105 | * @param string $option 106 | * 107 | * @return self 108 | */ 109 | private function validateDriver(NodeDefinition $node, $driver, $option) 110 | { 111 | $node 112 | ->validate() 113 | ->ifTrue(function ($v) use ($driver, $option) { 114 | return $driver === $v['driver'] && empty($v['options'][$option]); 115 | }) 116 | ->thenInvalid(sprintf('The "%s" option must be defined when using the "%s" driver.', $option, $driver)) 117 | ->end() 118 | ; 119 | 120 | return $this; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /EventListener/SchemaListener.php: -------------------------------------------------------------------------------- 1 | getSchema()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Bernard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Normalizer/DefaultMessageNormalizer.php: -------------------------------------------------------------------------------- 1 | 1 and you may run into invisibility timeout problems with that 185 | ``` 186 | 187 | ### Pheanstalk 188 | 189 | To use Pheanstalk (pda/pheanstalk), configure your driver like this: 190 | 191 | ``` yaml 192 | services: 193 | my.pheanstalk.connection: 194 | class: Pheanstalk\Pheanstalk 195 | arguments: 196 | - %some.parameter.containing.pheanstalk.host% 197 | 198 | bernard: 199 | driver: pheanstalk 200 | options: 201 | pheanstalk_service: my.pheanstalk.connection 202 | ``` 203 | -------------------------------------------------------------------------------- /Resources/config/collector.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/config/commands.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Resources/views/Collector/producer.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@WebProfiler/Profiler/layout.html.twig' %} 2 | 3 | {% block toolbar %} 4 | {% if collector.messageCount > 0 %} 5 | {% set icon %} 6 | {{ include('@Bernard/Icon/bernard.svg') }} 7 | {{ collector.messageCount }} 8 | {% endset %} 9 | 10 | {% set text %} 11 |
12 | Total messages: 13 | {{ collector.messageCount }} 14 |
15 |
16 | Total distinct queues: 17 | {{ collector.distinctQueueCount }} 18 |
19 | {% endset %} 20 | 21 | {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, name: 'bernard' }) }} 22 | {% endif %} 23 | {% endblock %} 24 | 25 | {% block menu %} 26 | 27 | {{ include('@Bernard/Icon/bernard.svg') }} 28 | Bernard 29 | 30 | {% endblock %} 31 | 32 | {% block panel %} 33 |

Bernard

34 | 35 | {% if collector.messageCount > 0 %} 36 |
37 | {% for queue,messages in collector.allMessages %} 38 |

Queue: {{ queue }}

39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {% for message in messages %} 49 | 50 | 51 | 62 | 63 | 64 | {% endfor %} 65 | 66 |
#MessageProduced at
{{ loop.index }} 52 | {% set context_id = 'context-' ~ queue ~ '-' ~ loop.index %} 53 | 54 | {{ message.class }} 55 | 56 | Show message 57 | 58 | 61 | {{ message.timestamp|date('d/m/Y H:i:s') }}
67 | {% endfor %} 68 |
69 | {% else %} 70 |
71 |

No messages were produced.

72 |
73 | {% endif %} 74 | {% endblock %} 75 | -------------------------------------------------------------------------------- /Resources/views/Icon/bernard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/BernardExtensionTest.php: -------------------------------------------------------------------------------- 1 | extension = new BernardExtension(); 19 | $this->container = new ContainerBuilder(); 20 | 21 | $this->container->setParameter('kernel.debug', true); 22 | } 23 | 24 | public function testServicesExists() 25 | { 26 | $config = ['driver' => 'doctrine']; 27 | $this->extension->load([$config], $this->container); 28 | 29 | // Make sure we don't have a dependencies on a real driver. 30 | $this->container->set('bernard.driver', $this->createMock('Bernard\Driver')); 31 | $this->container->set('event_dispatcher', $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface')); 32 | 33 | // Real services. 34 | $this->assertInstanceOf('Bernard\Producer', $this->container->get('bernard.producer')); 35 | $this->assertInstanceOf('Bernard\Consumer', $this->container->get('bernard.consumer')); 36 | $this->assertInstanceOf('Bernard\Command\ConsumeCommand', $this->container->get('bernard.command.consume')); 37 | $this->assertInstanceOf('Bernard\Command\ProduceCommand', $this->container->get('bernard.command.produce')); 38 | } 39 | 40 | public function testListenersAreNotRegisteredByDefault() 41 | { 42 | $config = ['driver' => 'doctrine']; 43 | $this->extension->load([$config], $this->container); 44 | 45 | foreach (['error_log', 'logger', 'failure'] as $listener) { 46 | $this->assertFalse($this->container->hasDefinition('bernard.listener.'.$listener)); 47 | } 48 | } 49 | 50 | public function testListenersHaveSubscriberTag() 51 | { 52 | $config = [ 53 | 'driver' => 'doctrine', 54 | 'listeners' => [ 55 | 'error_log' => true, 56 | 'logger' => true, 57 | 'failure' => true, 58 | ], 59 | ]; 60 | $this->extension->load([$config], $this->container); 61 | 62 | foreach (['error_log', 'logger', 'failure'] as $listener) { 63 | $definition = $this->container->getDefinition('bernard.listener.'.$listener); 64 | $this->assertTrue($definition->hasTag('kernel.event_subscriber')); 65 | } 66 | } 67 | 68 | public function testDoctrineEventListenerIsAdded() 69 | { 70 | $config = [ 71 | 'driver' => 'doctrine', 72 | 'options' => [ 73 | 'connection' => 'bernard', 74 | ], 75 | ]; 76 | $this->extension->load([$config], $this->container); 77 | 78 | $definition = $this->container->getDefinition('bernard.listener.doctrine_schema'); 79 | 80 | $expected = [ 81 | 'event' => 'postGenerateSchema', 82 | 'connection' => 'bernard', 83 | 'lazy' => true, 84 | ]; 85 | 86 | $this->assertTrue($definition->hasTag('doctrine.event_listener')); 87 | $this->assertEquals([$expected], $definition->getTag('doctrine.event_listener')); 88 | $this->assertEquals('doctrine.dbal.bernard_connection', $this->container->getAlias('bernard.dbal.connection')); 89 | } 90 | 91 | public function testDirectoryIsAddedToFileDriver() 92 | { 93 | $config = [ 94 | 'driver' => 'file', 95 | 'options' => [ 96 | 'directory' => __DIR__, 97 | ], 98 | ]; 99 | $this->extension->load([$config], $this->container); 100 | 101 | $definition = $this->container->getDefinition('bernard.driver.file'); 102 | 103 | $this->assertCount(1, $definition->getArguments()); 104 | $this->assertEquals(__DIR__, $definition->getArgument(0)); 105 | } 106 | 107 | public function testDriverIsAliased() 108 | { 109 | $config = ['driver' => 'doctrine']; 110 | $this->extension->load([$config], $this->container); 111 | 112 | $alias = $this->container->getAlias('bernard.driver'); 113 | 114 | $this->assertInstanceOf('Symfony\Component\DependencyInjection\Alias', $alias); 115 | $this->assertEquals('bernard.driver.doctrine', (string) $alias); 116 | } 117 | 118 | public function testSqsDriverCanBeBuildFromConfiguration() 119 | { 120 | $configuredClientService = 'sqs-client-service'; 121 | $configuredQueueMap = ['name1' => 'url1', 'name2' => 'url2']; 122 | $configuredPrefetchValue = 1; 123 | 124 | $config = [ 125 | 'driver' => 'sqs', 126 | 'options' => [ 127 | 'sqs_service' => $configuredClientService, 128 | 'sqs_queue_map' => $configuredQueueMap, 129 | 'prefetch' => $configuredPrefetchValue, 130 | ], 131 | ]; 132 | 133 | $this->extension->load([$config], $this->container); 134 | $driverDefinition = $this->container->getDefinition('bernard.driver.sqs'); 135 | 136 | $this->assertCount(3, $driverDefinition->getArguments()); 137 | $this->assertEquals($configuredClientService, $driverDefinition->getArgument(0)); 138 | $this->assertEquals($configuredQueueMap, $driverDefinition->getArgument(1)); 139 | $this->assertEquals($configuredPrefetchValue, $driverDefinition->getArgument(2)); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/NormalizerPassTest.php: -------------------------------------------------------------------------------- 1 | container = new ContainerBuilder(); 16 | $this->container 17 | ->register('bernard.normalizer', 'Normalt\Normalizer\AggregateNormalizer') 18 | ->addArgument([]) 19 | ; 20 | } 21 | 22 | public function testRegister() 23 | { 24 | $this->container->register('normalizer_one', 'stdClass')->addTag('bernard.normalizer'); 25 | $this->container->register('normalizer_two', 'stdClass')->addTag('bernard.normalizer'); 26 | 27 | $pass = new NormalizerPass(); 28 | $pass->process($this->container); 29 | 30 | $refs = $this->container->getDefinition('bernard.normalizer')->getArgument(0); 31 | 32 | $this->assertCount(2, $refs); 33 | $this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $refs[0]); 34 | $this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $refs[1]); 35 | $this->assertEquals('normalizer_one', (string) $refs[0]); 36 | $this->assertEquals('normalizer_two', (string) $refs[1]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/ReceiverPassTest.php: -------------------------------------------------------------------------------- 1 | container = new ContainerBuilder(); 17 | $this->container 18 | ->register('bernard.router', 'Bernard\Router\ContainerAwareRouter') 19 | ->setArguments([new Reference('service_container'), []]) 20 | ; 21 | } 22 | 23 | public function testRegisterMultipleTags() 24 | { 25 | $this->container->register('test_receiver', 'stdClass') 26 | ->addTag('bernard.receiver', ['message' => 'ImportUsers']) 27 | ->addTag('bernard.receiver', ['message' => 'SendNewsletter']) 28 | ->addTag('bernard.receiver', ['message' => 'DeleteWorld']) 29 | ; 30 | 31 | $pass = new ReceiverPass(); 32 | $pass->process($this->container); 33 | 34 | $arguments = $this->container->getDefinition('bernard.router')->getArguments(); 35 | 36 | $expected = [ 37 | 'ImportUsers' => 'test_receiver', 38 | 'SendNewsletter' => 'test_receiver', 39 | 'DeleteWorld' => 'test_receiver', 40 | ]; 41 | 42 | $this->assertCount(2, $arguments); 43 | $this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $arguments[0]); 44 | $this->assertEquals('service_container', (string) $arguments[0]); 45 | $this->assertEquals($expected, $arguments[1]); 46 | } 47 | 48 | /** 49 | * @expectedException \RuntimeException 50 | */ 51 | public function testExceptionWhenNameAttributeIsMissing() 52 | { 53 | $this->container->register('test_receiver', 'stdClass')->addTag('bernard.receiver', []); 54 | 55 | $pass = new ReceiverPass(); 56 | $pass->process($this->container); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/ConfigurationTest.php: -------------------------------------------------------------------------------- 1 | processConfig(['driver' => 'doctrine']); 13 | 14 | $this->assertEquals([ 15 | 'error_log' => false, 16 | 'logger' => [ 17 | 'enabled' => false, 18 | 'service' => 'logger', 19 | ], 20 | 'failure' => [ 21 | 'enabled' => false, 22 | 'queue_name' => 'failed', 23 | ], 24 | ], $config['listeners']); 25 | 26 | $this->assertEquals([ 27 | 'prefetch' => null, 28 | 'connection' => 'default', 29 | 'directory' => '%kernel.cache_dir%/bernard', 30 | 'phpamqp_service' => 'old_sound_rabbit_mq.connection.default', 31 | 'phpamqp_exchange' => null, 32 | 'phpamqp_default_message_parameters' => [], 33 | 'phpredis_service' => 'snc_redis.bernard', 34 | 'predis_service' => 'snc_redis.bernard', 35 | 'ironmq_service' => null, 36 | 'sqs_service' => null, 37 | 'sqs_queue_map' => [], 38 | 'pheanstalk_service' => null, 39 | 'custom_service' => null, 40 | ], $config['options']); 41 | } 42 | 43 | /** 44 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 45 | * @expectedExceptionMessage The child node "driver" at path "bernard" must be configured. 46 | */ 47 | public function testEmpty() 48 | { 49 | $this->processConfig([]); 50 | } 51 | 52 | /** 53 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 54 | */ 55 | public function testInvalidDriver() 56 | { 57 | $this->processConfig(['driver' => 'non_existent']); 58 | } 59 | 60 | /** 61 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 62 | * @expectedExceptionMessage The "phpamqp_exchange" option must be defined when using the "phpamqp" driver. 63 | */ 64 | public function testPhpAmqpDriverRequiresExchangeOptionToBeSet() 65 | { 66 | $this->processConfig(['driver' => 'phpamqp']); 67 | } 68 | 69 | /** 70 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 71 | * @expectedExceptionMessage The "ironmq_service" option must be defined when using the "ironmq" driver. 72 | */ 73 | public function testIronMqDriverRequiresServiceOptionToBeSet() 74 | { 75 | $this->processConfig(['driver' => 'ironmq']); 76 | } 77 | 78 | /** 79 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 80 | * @expectedExceptionMessage The "sqs_service" option must be defined when using the "sqs" driver. 81 | */ 82 | public function testSqsDriverRequiresServiceOptionToBeSet() 83 | { 84 | $this->processConfig(['driver' => 'sqs']); 85 | } 86 | 87 | /** 88 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 89 | * @expectedExceptionMessage The "pheanstalk_service" option must be defined when using the "pheanstalk" driver. 90 | */ 91 | public function testPheanstalkDriverRequiresServiceOptionToBeSet() 92 | { 93 | $this->processConfig(['driver' => 'pheanstalk']); 94 | } 95 | 96 | /** 97 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 98 | * @expectedExceptionMessage The "custom_service" option must be defined when using the "custom" driver. 99 | */ 100 | public function testCustomDriverRequiresServiceOptionToBeSet() 101 | { 102 | $this->processConfig(['driver' => 'custom']); 103 | } 104 | 105 | /** 106 | * @param array $config 107 | * 108 | * @return array 109 | */ 110 | private function processConfig(array $config) 111 | { 112 | return (new Processor())->processConfiguration(new Configuration(), [$config]); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "bernard/bernard-bundle", 3 | "description" : "Integrates Bernard into a Symfony2 application.", 4 | "type" : "symfony-bundle", 5 | "homepage" : "http://bernard.readthedocs.org/", 6 | "license" : "MIT", 7 | 8 | "autoload" : { 9 | "psr-4" : { "Bernard\\BernardBundle\\" : "" }, 10 | "exclude-from-classmap": [ 11 | "/Tests/" 12 | ] 13 | }, 14 | 15 | "require" : { 16 | "php": "^5.6|^7.0", 17 | "bernard/bernard": "1.0.0-alpha9", 18 | "symfony/framework-bundle": "^2.8|^3.2|^4.0|^5.0" 19 | }, 20 | 21 | "require-dev" : { 22 | "symfony/console": "^2.8|^3.0|^4.0", 23 | "symfony/finder": "^2.8|^3.0|^4.0", 24 | "symfony/phpunit-bridge": "^3.3" 25 | }, 26 | 27 | "extra" : { 28 | "branch-alias" : { 29 | "dev-master" : "2.0.x-dev" 30 | } 31 | } 32 | } 33 | --------------------------------------------------------------------------------