Completed
Push — 3.x-dev-kit ( cc4dbe )
by
unknown
03:15
created

configureDoctrineBackends()   C

Complexity

Conditions 13
Paths 34

Size

Total Lines 65
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 3 Features 1
Metric Value
c 5
b 3
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 package.
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 ContainerBuilder $container
86
     * @param array            $config
87
     */
88
    public function configureClass(ContainerBuilder $container, $config)
89
    {
90
        // admin configuration
91
        $container->setParameter('sonata.notification.admin.message.entity', $config['class']['message']);
92
93
        // manager configuration
94
        $container->setParameter('sonata.notification.manager.message.entity', $config['class']['message']);
95
    }
96
97
    /**
98
     * @param ContainerBuilder $container
99
     * @param array            $config
100
     */
101
    public function configureAdmin(ContainerBuilder $container, $config)
102
    {
103
        $container->setParameter('sonata.notification.admin.message.class', $config['admin']['message']['class']);
104
        $container->setParameter('sonata.notification.admin.message.controller', $config['admin']['message']['controller']);
105
        $container->setParameter('sonata.notification.admin.message.translation_domain', $config['admin']['message']['translation']);
106
    }
107
108
    /**
109
     * @param ContainerBuilder $container
110
     * @param array            $config
111
     */
112
    public function registerParameters(ContainerBuilder $container, $config)
113
    {
114
        $container->setParameter('sonata.notification.message.class', $config['class']['message']);
115
        $container->setParameter('sonata.notification.admin.message.entity', $config['class']['message']);
116
    }
117
118
    /**
119
     * @param ContainerBuilder $container
120
     * @param array            $config
121
     */
122
    public function configureBackends(ContainerBuilder $container, $config)
123
    {
124
        // set the default value, will be erase if required
125
        $container->setAlias('sonata.notification.manager.message', 'sonata.notification.manager.message.default');
126
127
        if (isset($config['backends']['rabbitmq']) && $config['backend']  === 'sonata.notification.backend.rabbitmq') {
128
            $this->configureRabbitmq($container, $config);
129
130
            $container->removeDefinition('sonata.notification.backend.doctrine');
131
        } else {
132
            $container->removeDefinition('sonata.notification.backend.rabbitmq');
133
        }
134
135
        if (isset($config['backends']['doctrine']) && $config['backend']  === 'sonata.notification.backend.doctrine') {
136
            $checkLevel = array(
137
                MessageInterface::STATE_DONE => $config['backends']['doctrine']['states']['done'],
138
                MessageInterface::STATE_ERROR => $config['backends']['doctrine']['states']['error'],
139
                MessageInterface::STATE_IN_PROGRESS => $config['backends']['doctrine']['states']['in_progress'],
140
                MessageInterface::STATE_OPEN => $config['backends']['doctrine']['states']['open'],
141
            );
142
143
            $pause = $config['backends']['doctrine']['pause'];
144
            $maxAge = $config['backends']['doctrine']['max_age'];
145
            $batchSize = $config['backends']['doctrine']['batch_size'];
146
            $container->setAlias('sonata.notification.manager.message', $config['backends']['doctrine']['message_manager']);
147
148
            $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...
149
        }
150
    }
151
152
    /**
153
     * @param array $config
154
     */
155
    public function registerDoctrineMapping(array $config)
156
    {
157
        $collector = DoctrineCollector::getInstance();
158
159
        $collector->addIndex($config['class']['message'], 'idx_state', array(
160
            'state',
161
        ));
162
163
        $collector->addIndex($config['class']['message'], 'idx_created_at', array(
164
            'created_at',
165
        ));
166
    }
167
168
    /**
169
     * @param array $config
170
     */
171
    protected function checkConfiguration(array $config)
172
    {
173
        if (isset($config['backends']) && count($config['backends']) > 1) {
174
            throw new \RuntimeException('more than one backend configured, you can have only one backend configuration');
175
        }
176
177
        if (!isset($config['backends']['rabbitmq']) && $config['backend']  === 'sonata.notification.backend.rabbitmq') {
178
            throw new \RuntimeException('Please configure the sonata_notification.backends.rabbitmq section');
179
        }
180
181
        if (!isset($config['backends']['doctrine']) && $config['backend']  === 'sonata.notification.backend.doctrine') {
182
            throw new \RuntimeException('Please configure the sonata_notification.backends.doctrine section');
183
        }
184
    }
185
186
    /**
187
     * @param ContainerBuilder $container
188
     * @param array            $config
189
     */
190
    protected function configureListeners(ContainerBuilder $container, array $config)
191
    {
192
        $ids = $config['iteration_listeners'];
193
194
        // this one clean the unit of work after every iteration
195
        // it must be set on any backend ...
196
        $ids[] = 'sonata.notification.event.doctrine_optimize';
197
198
        if (isset($config['backends']['doctrine']) && $config['backends']['doctrine']['batch_size'] > 1) {
199
            // if the backend is doctrine and the batch size > 1, then
200
            // the unit of work must be cleaned wisely to avoid any issue
201
            // while persisting entities
202
            $ids = array(
203
                'sonata.notification.event.doctrine_backend_optimize',
204
            );
205
        }
206
207
        $container->setParameter('sonata.notification.event.iteration_listeners', $ids);
208
    }
209
210
    /**
211
     * @param ContainerBuilder $container
212
     * @param array            $config
213
     * @param bool             $checkLevel
214
     * @param int              $pause
215
     * @param int              $maxAge
216
     * @param int              $batchSize
217
     *
218
     * @throws \RuntimeException
219
     */
220
    protected function configureDoctrineBackends(ContainerBuilder $container, array $config, $checkLevel, $pause, $maxAge, $batchSize)
221
    {
222
        $queues = $config['queues'];
223
        $qBackends = array();
224
225
        $definition = $container->getDefinition('sonata.notification.backend.doctrine');
226
227
        // no queue defined, set a default one
228
        if (count($queues) == 0) {
229
            $queues = array(array(
230
                'queue' => 'default',
231
                'default' => true,
232
                'types' => array(),
233
            ));
234
        }
235
236
        $defaultSet = false;
237
        $declaredQueues = array();
238
239
        foreach ($queues as $pos => &$queue) {
240
            if (in_array($queue['queue'], $declaredQueues)) {
241
                throw new \RuntimeException('The doctrine backend does not support 2 identicals queue name, please rename one queue');
242
            }
243
244
            $declaredQueues[] = $queue['queue'];
245
246
            // make the configuration compatible with old code and rabbitmq
247
            if (isset($queue['routing_key']) && strlen($queue['routing_key']) > 0) {
248
                $queue['types'] = array($queue['routing_key']);
249
            }
250
251
            if (empty($queue['types']) && $queue['default'] === false) {
252
                throw new \RuntimeException('You cannot declared a doctrine queue with no type defined with default = false');
253
            }
254
255
            if (!empty($queue['types']) && $queue['default'] === true) {
256
                throw new \RuntimeException('You cannot declared a doctrine queue with types defined with default = true');
257
            }
258
259
            $id = $this->createDoctrineQueueBackend($container, $definition->getArgument(0), $checkLevel, $pause, $maxAge, $batchSize, $queue['queue'], $queue['types']);
260
            $qBackends[$pos] = array(
261
                'types' => $queue['types'],
262
                'backend' => new Reference($id),
263
            );
264
265
            if ($queue['default'] === true) {
266
                if ($defaultSet === true) {
267
                    throw new \RuntimeException('You can only set one doctrine default queue in your sonata notification configuration.');
268
                }
269
270
                $defaultSet = true;
271
                $defaultQueue = $queue['queue'];
272
            }
273
        }
274
275
        if ($defaultSet === false) {
276
            throw new \RuntimeException('You need to specify a valid default queue for the doctrine backend!');
277
        }
278
279
        $definition
280
            ->replaceArgument(1, $queues)
281
            ->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...
282
            ->replaceArgument(3, $qBackends)
283
        ;
284
    }
285
286
    /**
287
     * @param ContainerBuilder $container
288
     * @param string           $manager
289
     * @param bool             $checkLevel
290
     * @param int              $pause
291
     * @param int              $maxAge
292
     * @param int              $batchSize
293
     * @param string           $key
294
     * @param array            $types
295
     *
296
     * @return string
297
     */
298
    protected function createDoctrineQueueBackend(ContainerBuilder $container, $manager, $checkLevel, $pause, $maxAge, $batchSize, $key, array $types = array())
299
    {
300
        if ($key == '') {
301
            $id = 'sonata.notification.backend.doctrine.default_'.$this->amqpCounter++;
302
        } else {
303
            $id = 'sonata.notification.backend.doctrine.'.$key;
304
        }
305
306
        $definition = new Definition('Sonata\NotificationBundle\Backend\MessageManagerBackend', array($manager, $checkLevel, $pause, $maxAge, $batchSize, $types));
307
        $definition->setPublic(false);
308
309
        $container->setDefinition($id, $definition);
310
311
        return $id;
312
    }
313
314
    /**
315
     * @param ContainerBuilder $container
316
     * @param array            $config
317
     */
318
    protected function configureRabbitmq(ContainerBuilder $container, array $config)
319
    {
320
        $queues = $config['queues'];
321
        $connection = $config['backends']['rabbitmq']['connection'];
322
        $exchange = $config['backends']['rabbitmq']['exchange'];
323
        $amqBackends = array();
324
325
        if (count($queues) == 0) {
326
            $queues = array(array(
327
                'queue' => 'default',
328
                'default' => true,
329
                'routing_key' => '',
330
                'recover' => false,
331
                'dead_letter_exchange' => null,
332
            ));
333
        }
334
335
        $declaredQueues = array();
336
337
        $defaultSet = false;
338
        foreach ($queues as $pos => $queue) {
339
            if (in_array($queue['queue'], $declaredQueues)) {
340
                throw new \RuntimeException('The RabbitMQ backend does not support 2 identicals queue name, please rename one queue');
341
            }
342
343
            $declaredQueues[] = $queue['queue'];
344
345
            $id = $this->createAMQPBackend($container, $exchange, $queue['queue'], $queue['recover'], $queue['routing_key'], $queue['dead_letter_exchange']);
346
347
            $amqBackends[$pos] = array(
348
                'type' => $queue['routing_key'],
349
                'backend' => new Reference($id),
350
            );
351
352
            if ($queue['default'] === true) {
353
                if ($defaultSet === true) {
354
                    throw new \RuntimeException('You can only set one rabbitmq default queue in your sonata notification configuration.');
355
                }
356
                $defaultSet = true;
357
                $defaultQueue = $queue['routing_key'];
358
            }
359
        }
360
361
        if ($defaultSet === false) {
362
            throw new \RuntimeException('You need to specify a valid default queue for the rabbitmq backend!');
363
        }
364
365
        $container->getDefinition('sonata.notification.backend.rabbitmq')
366
            ->replaceArgument(0, $connection)
367
            ->replaceArgument(1, $queues)
368
            ->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...
369
            ->replaceArgument(3, $amqBackends)
370
        ;
371
    }
372
373
    /**
374
     * @param ContainerBuilder $container
375
     * @param string           $exchange
376
     * @param string           $name
377
     * @param string           $recover
378
     * @param string           $key
379
     * @param string           $deadLetterExchange
380
     *
381
     * @return string
382
     */
383
    protected function createAMQPBackend(ContainerBuilder $container, $exchange, $name, $recover, $key = '', $deadLetterExchange = null)
384
    {
385
        $id = 'sonata.notification.backend.rabbitmq.'.$this->amqpCounter++;
386
387
        $definition = new Definition('Sonata\NotificationBundle\Backend\AMQPBackend', array($exchange, $name, $recover, $key, $deadLetterExchange));
388
        $definition->setPublic(false);
389
        $container->setDefinition($id, $definition);
390
391
        return $id;
392
    }
393
}
394