Test Setup Failed
Push — master ( 298fd3...56daff )
by Matthew
17:14
created

WorkerCompilerPass   C

Complexity

Total Complexity 60

Size/Duplication

Total Lines 317
Duplicated Lines 18.3 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 60
lcom 1
cbo 4
dl 58
loc 317
rs 6.0975
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
B process() 0 52 6
A setupBeanstalkd() 0 12 3
A setupDoctrineManagers() 0 16 3
F setupRabbitMQ() 0 81 16
C getJobClass() 0 33 8
C getRunClass() 29 29 8
C getRunArchiveClass() 29 29 8
C getJobClassArchive() 0 27 8

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WorkerCompilerPass often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WorkerCompilerPass, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Dtc\QueueBundle\DependencyInjection\Compiler;
4
5
use Dtc\QueueBundle\Model\Job;
6
use Dtc\QueueBundle\Model\Run;
7
use Pheanstalk\Pheanstalk;
8
use Symfony\Component\DependencyInjection\Alias;
9
use Symfony\Component\DependencyInjection\ContainerBuilder;
10
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
11
use Symfony\Component\DependencyInjection\Definition;
12
use Symfony\Component\DependencyInjection\Reference;
13
14
class WorkerCompilerPass implements CompilerPassInterface
15
{
16
    public function process(ContainerBuilder $container)
17
    {
18
        if (false === $container->hasDefinition('dtc_queue.worker_manager')) {
19
            return;
20
        }
21
22
        $defaultManagerType = $container->getParameter('dtc_queue.default_manager');
23
        if (!$container->hasDefinition('dtc_queue.job_manager.'.$defaultManagerType)) {
24
            throw new \Exception("No job manager found for dtc_queue.job_manager.$defaultManagerType");
25
        }
26
27
        $alias = new Alias('dtc_queue.job_manager.'.$defaultManagerType);
28
        $container->setAlias('dtc_queue.job_manager', $alias);
29
30
        // Setup beanstalkd if configuration is present
31
        $this->setupBeanstalkd($container);
32
        $this->setupRabbitMQ($container);
33
34
        $definition = $container->getDefinition('dtc_queue.worker_manager');
35
        $jobManagerRef = array(new Reference('dtc_queue.job_manager'));
36
37
        $jobClass = $this->getJobClass($container);
38
        $jobClassArchive = $this->getJobClassArchive($container);
39
        $container->setParameter('dtc_queue.class_job', $jobClass);
40
        $container->setParameter('dtc_queue.class_job_archive', $jobClassArchive);
41
        $container->setParameter('dtc_queue.class_run', $this->getRunClass($container));
42
        $container->setParameter('dtc_queue.class_run_archive', $this->getRunArchiveClass($container));
43
        // Add each worker to workerManager, make sure each worker has instance to work
44
        foreach ($container->findTaggedServiceIds('dtc_queue.worker') as $id => $attributes) {
45
            $worker = $container->getDefinition($id);
46
            $class = $container->getDefinition($id)->getClass();
47
48
            $refClass = new \ReflectionClass($class);
49
            $workerClass = 'Dtc\QueueBundle\Model\Worker';
50
            if (!$refClass->isSubclassOf($workerClass)) {
51
                throw new \InvalidArgumentException(sprintf('Service "%s" must extend class "%s".', $id, $workerClass));
52
            }
53
54
            // Give each worker access to job manager
55
            $worker->addMethodCall('setJobManager', $jobManagerRef);
56
            $worker->addMethodCall('setJobClass', array($jobClass));
57
58
            $definition->addMethodCall('addWorker', array(new Reference($id)));
59
        }
60
61
        $eventDispatcher = $container->getDefinition('dtc_queue.event_dispatcher');
62
        foreach ($container->findTaggedServiceIds('dtc_queue.event_subscriber') as $id => $attributes) {
63
            $eventSubscriber = $container->getDefinition($id);
64
            $eventDispatcher->addMethodCall('addSubscriber', [$eventSubscriber]);
65
        }
66
        $this->setupDoctrineManagers($container);
67
    }
68
69
    /**
70
     * Sets up beanstalkd instance if appropriate.
71
     *
72
     * @param ContainerBuilder $container
73
     */
74
    public function setupBeanstalkd(ContainerBuilder $container)
75
    {
76
        if ($container->hasParameter('dtc_queue.beanstalkd.host')) {
77
            $definition = new Definition('Pheanstalk\\Pheanstalk', [$container->getParameter('dtc_queue.beanstalkd.host')]);
78
            $container->setDefinition('dtc_queue.beanstalkd', $definition);
79
            $definition = $container->getDefinition('dtc_queue.job_manager.beanstalkd');
80
            $definition->addMethodCall('setBeanstalkd', [new Reference('dtc_queue.beanstalkd')]);
81
            if ($container->hasParameter('dtc_queue.beanstalkd.tube')) {
82
                $definition->addMethodCall('setTube', [$container->getParameter('dtc_queue.beanstalkd.tube')]);
83
            }
84
        }
85
    }
86
87
    public function setupDoctrineManagers(ContainerBuilder $container)
88
    {
89
        $documentManager = $container->getParameter('dtc_queue.document_manager');
90
91
        $odmManager = "doctrine_mongodb.odm.{$documentManager}_document_manager";
92
        if ($container->has($odmManager)) {
93
            $container->setAlias('dtc_queue.document_manager', $odmManager);
94
        }
95
96
        $entityManager = $container->getParameter('dtc_queue.entity_manager');
97
98
        $ormManager = "doctrine.orm.{$entityManager}_entity_manager";
99
        if ($container->has($ormManager)) {
100
            $container->setAlias('dtc_queue.entity_manager', $ormManager);
101
        }
102
    }
103
104
    /**
105
     * Sets up RabbitMQ instance if appropriate.
106
     *
107
     * @param ContainerBuilder $container
108
     */
109
    public function setupRabbitMQ(ContainerBuilder $container)
110
    {
111
        if ($container->hasParameter('dtc_queue.rabbit_mq')) {
112
            $class = 'PhpAmqpLib\\Connection\\AMQPStreamConnection';
113
            $rabbitMqConfig = $container->getParameter('dtc_queue.rabbit_mq');
114
            $arguments = [
115
                $rabbitMqConfig['host'],
116
                $rabbitMqConfig['port'],
117
                $rabbitMqConfig['user'],
118
                $rabbitMqConfig['password'],
119
                $rabbitMqConfig['vhost'],
120
            ];
121
122
            if ($container->hasParameter('dtc_queue.rabbit_mq.ssl') && $container->getParameter('dtc_queue.rabbit_mq.ssl')) {
123
                $class = 'PhpAmqpLib\\Connection\\AMQPSSLConnection';
124
                if ($container->hasParameter('dtc_queue.rabbit_mq.ssl_options')) {
125
                    $arguments[] = $container->getParameter('dtc_queue.rabbit_mq.ssl_options');
126
                } else {
127
                    $arguments[] = [];
128
                }
129
                if ($container->hasParameter('dtc_queue.rabbit_mq.options')) {
130
                    $arguments[] = $container->getParameter('dtc_queue.rabbit_mq.options');
131
                }
132
            } else {
133
                if ($container->hasParameter('dtc_queue.rabbit_mq.options')) {
134
                    $options = $container->getParameter('dtc_queue.rabbit_mq.options');
135
                    if (isset($options['insist'])) {
136
                        $arguments[] = $options['insist'];
137
                    } else {
138
                        $arguments[] = false;
139
                    }
140
                    if (isset($options['login_method'])) {
141
                        $arguments[] = $options['login_method'];
142
                    } else {
143
                        $arguments[] = 'AMQPLAIN';
144
                    }
145
                    if (isset($options['login_response'])) {
146
                        $arguments[] = $options['login_response'];
147
                    } else {
148
                        $arguments[] = null;
149
                    }
150
                    if (isset($options['locale'])) {
151
                        $arguments[] = $options['locale'];
152
                    } else {
153
                        $arguments[] = 'en_US';
154
                    }
155
                    if (isset($options['connection_timeout'])) {
156
                        $arguments[] = $options['connection_timeout'];
157
                    } else {
158
                        $arguments[] = 3.0;
159
                    }
160
                    if (isset($options['read_write_timeout'])) {
161
                        $arguments[] = $options['read_write_timeout'];
162
                    } else {
163
                        $arguments[] = 3.0;
164
                    }
165
                    if (isset($options['context'])) {
166
                        $arguments[] = $options['context'];
167
                    } else {
168
                        $arguments[] = null;
169
                    }
170
                    if (isset($options['keepalive'])) {
171
                        $arguments[] = $options['keepalive'];
172
                    } else {
173
                        $arguments[] = false;
174
                    }
175
                    if (isset($options['heartbeat'])) {
176
                        $arguments[] = $options['heartbeat'];
177
                    } else {
178
                        $arguments[] = 0;
179
                    }
180
                }
181
            }
182
            $definition = new Definition($class, $arguments);
183
            $container->setDefinition('dtc_queue.rabbit_mq', $definition);
184
            $definition = $container->getDefinition('dtc_queue.job_manager.rabbit_mq');
185
            $definition->addMethodCall('setAMQPConnection', [new Reference('dtc_queue.rabbit_mq')]);
186
            $definition->addMethodCall('setQueueArgs', array_values($rabbitMqConfig['queue_args']));
187
            $definition->addMethodCall('setExchangeArgs', array_values($rabbitMqConfig['exchange_args']));
188
        }
189
    }
190
191
    /**
192
     * Determines the job class based on the queue manager type.
193
     *
194
     * @param ContainerBuilder $container
195
     *
196
     * @return mixed|string
197
     *
198
     * @throws \Exception
199
     */
200
    public function getJobClass(ContainerBuilder $container)
201
    {
202
        $jobClass = $container->getParameter('dtc_queue.class_job');
203
        if (!$jobClass) {
204
            switch ($defaultType = $container->getParameter('dtc_queue.default_manager')) {
205
                case 'mongodb':
206
                    $jobClass = 'Dtc\\QueueBundle\\Document\\Job';
207
                    break;
208
                case 'beanstalkd':
209
                    $jobClass = 'Dtc\\QueueBundle\\Beanstalkd\\Job';
210
                    break;
211
                case 'rabbit_mq':
212
                    $jobClass = 'Dtc\\QueueBundle\\RabbitMQ\\Job';
213
                    break;
214
                case 'orm':
215
                    $jobClass = 'Dtc\\QueueBundle\\Entity\\Job';
216
                    break;
217
                default:
218
                    throw new \Exception("Unknown default_manager type $defaultType - please specify a Job class in the 'class' configuration parameter");
219
            }
220
        }
221
222
        if (!class_exists($jobClass)) {
223
            throw new \Exception("Can't find Job class $jobClass");
224
        }
225
226
        $test = new $jobClass();
227
        if (!$test instanceof Job) {
228
            throw new \Exception("$jobClass must be instance of (or derived from) Dtc\\QueueBundle\\Model\\Job");
229
        }
230
231
        return $jobClass;
232
    }
233
234 View Code Duplication
    public function getRunClass(ContainerBuilder $container)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
    {
236
        $runClass = $container->hasParameter('dtc_queue.class_run') ? $container->getParameter('dtc_queue.class_run') : null;
237
        if (!$runClass) {
238
            switch ($defaultType = $container->getParameter('dtc_queue.default_manager')) {
0 ignored issues
show
Unused Code introduced by
$defaultType is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
239
                case 'mongodb':
240
                    $runClass = 'Dtc\\QueueBundle\\Document\\Run';
241
                    break;
242
                case 'orm':
243
                    $runClass = 'Dtc\\QueueBundle\\Entity\\Run';
244
                    break;
245
                default:
246
                    $runClass = 'Dtc\\QueueBundle\\Model\\Run';
247
            }
248
        }
249
250
        if (isset($runClass)) {
251
            if (!class_exists($runClass)) {
252
                throw new \Exception("Can't find Run class $runClass");
253
            }
254
        }
255
256
        $test = new $runClass();
257
        if (!$test instanceof Run) {
258
            throw new \Exception("$runClass must be instance of (or derived from) Dtc\\QueueBundle\\Model\\Run");
259
        }
260
261
        return $runClass;
262
    }
263
264 View Code Duplication
    public function getRunArchiveClass(ContainerBuilder $container)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
265
    {
266
        $runArchiveClass = $container->hasParameter('dtc_queue.class_run_archive') ? $container->getParameter('dtc_queue.class_run_archive') : null;
267
        if (!$runArchiveClass) {
268
            switch ($defaultType = $container->getParameter('dtc_queue.default_manager')) {
0 ignored issues
show
Unused Code introduced by
$defaultType is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
269
                case 'mongodb':
270
                    $runArchiveClass = 'Dtc\\QueueBundle\\Document\\RunArchive';
271
                    break;
272
                case 'orm':
273
                    $runArchiveClass = 'Dtc\\QueueBundle\\Entity\\RunArchive';
274
                    break;
275
                default:
276
                    $runArchiveClass = 'Dtc\\QueueBundle\\Model\\Run';
277
            }
278
        }
279
280
        if (isset($runArchiveClass)) {
281
            if (!class_exists($runArchiveClass)) {
282
                throw new \Exception("Can't find RunArchive class $runArchiveClass");
283
            }
284
        }
285
286
        $test = new $runArchiveClass();
287
        if (!$test instanceof Run) {
288
            throw new \Exception("$runArchiveClass must be instance of (or derived from) Dtc\\QueueBundle\\Model\\Run");
289
        }
290
291
        return $runArchiveClass;
292
    }
293
294
    /**
295
     * Determines the job class based on the queue manager type.
296
     *
297
     * @param ContainerBuilder $container
298
     *
299
     * @return mixed|string
300
     *
301
     * @throws \Exception
302
     */
303
    public function getJobClassArchive(ContainerBuilder $container)
304
    {
305
        $jobArchiveClass = $container->getParameter('dtc_queue.class_job_archive');
306
        if (!$jobArchiveClass) {
307
            switch ($defaultType = $container->getParameter('dtc_queue.default_manager')) {
0 ignored issues
show
Unused Code introduced by
$defaultType is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
308
                case 'mongodb':
309
                    $jobArchiveClass = 'Dtc\\QueueBundle\\Document\\JobArchive';
310
                    break;
311
                case 'orm':
312
                    $jobArchiveClass = 'Dtc\\QueueBundle\\Entity\\JobArchive';
313
                    break;
314
            }
315
        }
316
317
        if ($jobArchiveClass && !class_exists($jobArchiveClass)) {
318
            throw new \Exception("Can't find JobArchive class $jobArchiveClass");
319
        }
320
321
        if ($jobArchiveClass) {
322
            $test = new $jobArchiveClass();
323
            if (!$test instanceof Job) {
324
                throw new \Exception("$jobArchiveClass must be instance of (or derived from) Dtc\\QueueBundle\\Model\\Job");
325
            }
326
        }
327
328
        return $jobArchiveClass;
329
    }
330
}
331