Completed
Push — 2.x-dev-kit ( 8d77e1 )
by
unknown
28:22 queued 25:50
created

configureDoctrineBackends()   C

Complexity

Conditions 13
Paths 34

Size

Total Lines 65
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 1
Metric Value
c 4
b 2
f 1
dl 0
loc 65
rs 5.9671
cc 13
eloc 36
nc 34
nop 6

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Sonata project.
5
 *
6
 * (c) Thomas Rabaix <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sonata\NotificationBundle\DependencyInjection;
13
14
use Sonata\EasyExtendsBundle\Mapper\DoctrineCollector;
15
use Sonata\NotificationBundle\Model\MessageInterface;
16
use Symfony\Component\Config\FileLocator;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\Definition;
19
use Symfony\Component\DependencyInjection\Loader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
23
/**
24
 * This is the class that loads and manages your bundle configuration.
25
 *
26
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
27
 */
28
class SonataNotificationExtension extends Extension
29
{
30
    /**
31
     * @var int
32
     */
33
    protected $amqpCounter = 0;
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    public function load(array $configs, ContainerBuilder $container)
39
    {
40
        $configuration = new Configuration();
41
        $config = $this->processConfiguration($configuration, $configs);
42
43
        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
44
45
        $loader->load('core.xml');
46
        $loader->load('doctrine_orm.xml');
47
        $loader->load('backend.xml');
48
        $loader->load('consumer.xml');
49
        $loader->load('selector.xml');
50
        $loader->load('event.xml');
51
52
        if ($config['consumers']['register_default']) {
53
            $loader->load('default_consumers.xml');
54
        }
55
56
        $bundles = $container->getParameter('kernel.bundles');
57
58
        if (isset($bundles['FOSRestBundle']) && isset($bundles['NelmioApiDocBundle'])) {
59
            $loader->load('api_controllers.xml');
60
            $loader->load('api_form.xml');
61
        }
62
63
        if ($config['admin']['enabled'] && isset($bundles['SonataDoctrineORMAdminBundle'])) { // for now, only support for ORM
64
            $loader->load('admin.xml');
65
        }
66
67
        if (isset($bundles['LiipMonitorBundle'])) {
68
            $loader->load('checkmonitor.xml');
69
        }
70
71
        $this->checkConfiguration($config);
72
73
        $container->setAlias('sonata.notification.backend', $config['backend']);
74
        $container->setParameter('sonata.notification.backend', $config['backend']);
75
76
        $this->registerDoctrineMapping($config);
77
        $this->registerParameters($container, $config);
78
        $this->configureBackends($container, $config);
79
        $this->configureClass($container, $config);
80
        $this->configureListeners($container, $config);
81
        $this->configureAdmin($container, $config);
82
    }
83
84
    /**
85
     * @param array $config
86
     */
87
    protected function checkConfiguration(array $config)
88
    {
89
        if (isset($config['backends']) && count($config['backends']) > 1) {
90
            throw new \RuntimeException('more than one backend configured, you can have only one backend configuration');
91
        }
92
93
        if (!isset($config['backends']['rabbitmq']) && $config['backend']  === 'sonata.notification.backend.rabbitmq') {
94
            throw new \RuntimeException('Please configure the sonata_notification.backends.rabbitmq section');
95
        }
96
97
        if (!isset($config['backends']['doctrine']) && $config['backend']  === 'sonata.notification.backend.doctrine') {
98
            throw new \RuntimeException('Please configure the sonata_notification.backends.doctrine section');
99
        }
100
    }
101
102
    /**
103
     * @param ContainerBuilder $container
104
     * @param array            $config
105
     */
106
    protected function configureListeners(ContainerBuilder $container, array $config)
107
    {
108
        $ids = $config['iteration_listeners'];
109
110
        // this one clean the unit of work after every iteration
111
        // it must be set on any backend ...
112
        $ids[] = 'sonata.notification.event.doctrine_optimize';
113
114
        if (isset($config['backends']['doctrine']) && $config['backends']['doctrine']['batch_size'] > 1) {
115
            // if the backend is doctrine and the batch size > 1, then
116
            // the unit of work must be cleaned wisely to avoid any issue
117
            // while persisting entities
118
            $ids = array(
119
                'sonata.notification.event.doctrine_backend_optimize',
120
            );
121
        }
122
123
        $container->setParameter('sonata.notification.event.iteration_listeners', $ids);
124
    }
125
126
    /**
127
     * @param ContainerBuilder $container
128
     * @param array            $config
129
     */
130
    public function configureClass(ContainerBuilder $container, $config)
131
    {
132
        // admin configuration
133
        $container->setParameter('sonata.notification.admin.message.entity',       $config['class']['message']);
134
135
        // manager configuration
136
        $container->setParameter('sonata.notification.manager.message.entity',     $config['class']['message']);
137
    }
138
139
    /**
140
     * @param ContainerBuilder $container
141
     * @param array            $config
142
     */
143
    public function configureAdmin(ContainerBuilder $container, $config)
144
    {
145
        $container->setParameter('sonata.notification.admin.message.class',              $config['admin']['message']['class']);
146
        $container->setParameter('sonata.notification.admin.message.controller',         $config['admin']['message']['controller']);
147
        $container->setParameter('sonata.notification.admin.message.translation_domain', $config['admin']['message']['translation']);
148
    }
149
150
    /**
151
     * @param ContainerBuilder $container
152
     * @param array            $config
153
     */
154
    public function registerParameters(ContainerBuilder $container, $config)
155
    {
156
        $container->setParameter('sonata.notification.message.class',        $config['class']['message']);
157
        $container->setParameter('sonata.notification.admin.message.entity', $config['class']['message']);
158
    }
159
160
    /**
161
     * @param ContainerBuilder $container
162
     * @param array            $config
163
     */
164
    public function configureBackends(ContainerBuilder $container, $config)
165
    {
166
        // set the default value, will be erase if required
167
        $container->setAlias('sonata.notification.manager.message', 'sonata.notification.manager.message.default');
168
169
        if (isset($config['backends']['rabbitmq']) && $config['backend']  === 'sonata.notification.backend.rabbitmq') {
170
            $this->configureRabbitmq($container, $config);
171
172
            $container->removeDefinition('sonata.notification.backend.doctrine');
173
        } else {
174
            $container->removeDefinition('sonata.notification.backend.rabbitmq');
175
        }
176
177
        if (isset($config['backends']['doctrine']) && $config['backend']  === 'sonata.notification.backend.doctrine') {
178
            $checkLevel = array(
179
                MessageInterface::STATE_DONE         => $config['backends']['doctrine']['states']['done'],
180
                MessageInterface::STATE_ERROR        => $config['backends']['doctrine']['states']['error'],
181
                MessageInterface::STATE_IN_PROGRESS  => $config['backends']['doctrine']['states']['in_progress'],
182
                MessageInterface::STATE_OPEN         => $config['backends']['doctrine']['states']['open'],
183
            );
184
185
            $pause = $config['backends']['doctrine']['pause'];
186
            $maxAge = $config['backends']['doctrine']['max_age'];
187
            $batchSize = $config['backends']['doctrine']['batch_size'];
188
            $container->setAlias('sonata.notification.manager.message', $config['backends']['doctrine']['message_manager']);
189
190
            $this->configureDoctrineBackends($container, $config, $checkLevel, $pause, $maxAge, $batchSize);
0 ignored issues
show
Documentation introduced by
$checkLevel is of type array, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
191
        }
192
    }
193
194
    /**
195
     * @param ContainerBuilder $container
196
     * @param array            $config
197
     * @param bool             $checkLevel
198
     * @param int              $pause
199
     * @param int              $maxAge
200
     * @param int              $batchSize
201
     *
202
     * @throws \RuntimeException
203
     */
204
    protected function configureDoctrineBackends(ContainerBuilder $container, array $config, $checkLevel, $pause, $maxAge, $batchSize)
205
    {
206
        $queues = $config['queues'];
207
        $qBackends = array();
208
209
        $definition = $container->getDefinition('sonata.notification.backend.doctrine');
210
211
        // no queue defined, set a default one
212
        if (count($queues) == 0) {
213
            $queues = array(array(
214
                'queue'   => 'default',
215
                'default' => true,
216
                'types'   => array(),
217
            ));
218
        }
219
220
        $defaultSet = false;
221
        $declaredQueues = array();
222
223
        foreach ($queues as $pos => &$queue) {
224
            if (in_array($queue['queue'], $declaredQueues)) {
225
                throw new \RuntimeException('The doctrine backend does not support 2 identicals queue name, please rename one queue');
226
            }
227
228
            $declaredQueues[] = $queue['queue'];
229
230
            // make the configuration compatible with old code and rabbitmq
231
            if (isset($queue['routing_key']) && strlen($queue['routing_key']) > 0) {
232
                $queue['types'] = array($queue['routing_key']);
233
            }
234
235
            if (empty($queue['types']) && $queue['default'] === false) {
236
                throw new \RuntimeException('You cannot declared a doctrine queue with no type defined with default = false');
237
            }
238
239
            if (!empty($queue['types']) && $queue['default'] === true) {
240
                throw new \RuntimeException('You cannot declared a doctrine queue with types defined with default = true');
241
            }
242
243
            $id = $this->createDoctrineQueueBackend($container, $definition->getArgument(0), $checkLevel, $pause, $maxAge, $batchSize, $queue['queue'], $queue['types']);
244
            $qBackends[$pos] = array(
245
                'types'   => $queue['types'],
246
                'backend' => new Reference($id),
247
            );
248
249
            if ($queue['default'] === true) {
250
                if ($defaultSet === true) {
251
                    throw new \RuntimeException('You can only set one doctrine default queue in your sonata notification configuration.');
252
                }
253
254
                $defaultSet = true;
255
                $defaultQueue = $queue['queue'];
256
            }
257
        }
258
259
        if ($defaultSet === false) {
260
            throw new \RuntimeException('You need to specify a valid default queue for the doctrine backend!');
261
        }
262
263
        $definition
264
            ->replaceArgument(1, $queues)
265
            ->replaceArgument(2, $defaultQueue)
0 ignored issues
show
Bug introduced by
The variable $defaultQueue does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
266
            ->replaceArgument(3, $qBackends)
267
        ;
268
    }
269
270
    /**
271
     * @param ContainerBuilder $container
272
     * @param string           $manager
273
     * @param bool             $checkLevel
274
     * @param int              $pause
275
     * @param int              $maxAge
276
     * @param int              $batchSize
277
     * @param string           $key
278
     * @param array            $types
279
     *
280
     * @return string
281
     */
282
    protected function createDoctrineQueueBackend(ContainerBuilder $container, $manager, $checkLevel, $pause, $maxAge, $batchSize, $key, array $types = array())
283
    {
284
        if ($key == '') {
285
            $id = 'sonata.notification.backend.doctrine.default_'.$this->amqpCounter++;
286
        } else {
287
            $id = 'sonata.notification.backend.doctrine.'.$key;
288
        }
289
290
        $definition = new Definition('Sonata\NotificationBundle\Backend\MessageManagerBackend', array($manager, $checkLevel, $pause, $maxAge, $batchSize, $types));
291
        $definition->setPublic(false);
292
293
        $container->setDefinition($id, $definition);
294
295
        return $id;
296
    }
297
298
    /**
299
     * @param ContainerBuilder $container
300
     * @param array            $config
301
     */
302
    protected function configureRabbitmq(ContainerBuilder $container, array $config)
303
    {
304
        $queues = $config['queues'];
305
        $connection = $config['backends']['rabbitmq']['connection'];
306
        $exchange = $config['backends']['rabbitmq']['exchange'];
307
        $amqBackends = array();
308
309
        if (count($queues) == 0) {
310
            $queues = array(array(
311
                'queue'                => 'default',
312
                'default'              => true,
313
                'routing_key'          => '',
314
                'recover'              => false,
315
                'dead_letter_exchange' => null,
316
            ));
317
        }
318
319
        $declaredQueues = array();
320
321
        $defaultSet = false;
322
        foreach ($queues as $pos => $queue) {
323
            if (in_array($queue['queue'], $declaredQueues)) {
324
                throw new \RuntimeException('The RabbitMQ backend does not support 2 identicals queue name, please rename one queue');
325
            }
326
327
            $declaredQueues[] = $queue['queue'];
328
329
            $id = $this->createAMQPBackend($container, $exchange, $queue['queue'], $queue['recover'], $queue['routing_key'], $queue['dead_letter_exchange']);
330
331
            $amqBackends[$pos] = array(
332
                'type'    => $queue['routing_key'],
333
                'backend' => new Reference($id),
334
            );
335
336
            if ($queue['default'] === true) {
337
                if ($defaultSet === true) {
338
                    throw new \RuntimeException('You can only set one rabbitmq default queue in your sonata notification configuration.');
339
                }
340
                $defaultSet = true;
341
                $defaultQueue = $queue['routing_key'];
342
            }
343
        }
344
345
        if ($defaultSet === false) {
346
            throw new \RuntimeException('You need to specify a valid default queue for the rabbitmq backend!');
347
        }
348
349
        $container->getDefinition('sonata.notification.backend.rabbitmq')
350
            ->replaceArgument(0, $connection)
351
            ->replaceArgument(1, $queues)
352
            ->replaceArgument(2, $defaultQueue)
0 ignored issues
show
Bug introduced by
The variable $defaultQueue does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
353
            ->replaceArgument(3, $amqBackends)
354
        ;
355
    }
356
357
    /**
358
     * @param ContainerBuilder $container
359
     * @param string           $exchange
360
     * @param string           $name
361
     * @param string           $recover
362
     * @param string           $key
363
     * @param string           $deadLetterExchange
364
     *
365
     * @return string
366
     */
367
    protected function createAMQPBackend(ContainerBuilder $container, $exchange, $name, $recover, $key = '', $deadLetterExchange = null)
368
    {
369
        $id = 'sonata.notification.backend.rabbitmq.'.$this->amqpCounter++;
370
371
        $definition = new Definition('Sonata\NotificationBundle\Backend\AMQPBackend', array($exchange, $name, $recover, $key, $deadLetterExchange));
372
        $definition->setPublic(false);
373
        $container->setDefinition($id, $definition);
374
375
        return $id;
376
    }
377
378
    /**
379
     * @param array $config
380
     */
381
    public function registerDoctrineMapping(array $config)
382
    {
383
        $collector = DoctrineCollector::getInstance();
384
385
        $collector->addIndex($config['class']['message'], 'idx_state', array(
386
            'state',
387
        ));
388
389
        $collector->addIndex($config['class']['message'], 'idx_created_at', array(
390
            'created_at',
391
        ));
392
    }
393
}
394