Completed
Push — master ( 5fe2ea...bba9f0 )
by Matthew
13:23
created

WorkerCompilerPass   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 10
dl 0
loc 266
ccs 0
cts 188
cp 0
rs 8.3673
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
B process() 0 36 3
A setupAlias() 0 17 4
A setupAliases() 0 9 1
A setupTaggedServices() 0 21 3
A setupDoctrineManagers() 0 16 3
A addLiveJobs() 0 12 3
B getDirectory() 0 16 6
A getJobClass() 0 15 3
A getRunManagerType() 0 9 2
A getJobTimingManagerType() 0 9 2
B getClass() 0 21 6
A testClass() 0 11 3
B getJobClassArchive() 0 20 6

How to fix   Complexity   

Complex Class

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\GridBundle\DependencyInjection\Compiler\GridSourceCompilerPass;
6
use Dtc\QueueBundle\Model\Job;
7
use Dtc\QueueBundle\Model\JobTiming;
8
use Dtc\QueueBundle\Model\Run;
9
use Dtc\QueueBundle\Exception\ClassNotFoundException;
10
use Dtc\QueueBundle\Exception\ClassNotSubclassException;
11
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
12
use Symfony\Component\DependencyInjection\Alias;
13
use Symfony\Component\DependencyInjection\ContainerBuilder;
14
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15
use Symfony\Component\DependencyInjection\Definition;
16
use Symfony\Component\DependencyInjection\Reference;
17
18
class WorkerCompilerPass implements CompilerPassInterface
19
{
20
    public function process(ContainerBuilder $container)
21
    {
22
        if (false === $container->hasDefinition('dtc_queue.worker_manager')) {
23
            return;
24
        }
25
26
        $this->setupAliases($container);
27
28
        $definition = $container->getDefinition('dtc_queue.worker_manager');
29
30
        $jobClass = $this->getJobClass($container);
31
        $jobArchiveClass = $this->getJobClassArchive($container);
32
        $container->setParameter('dtc_queue.class_job', $jobClass);
33
        $container->setParameter('dtc_queue.class_job_archive', $jobArchiveClass);
34
35
        $managerType = $this->getRunManagerType($container);
36
        $jobTimingManagerType = $this->getJobTimingManagerType($container);
37
        $container->setParameter('dtc_queue.class_job_timing', $this->getClass(
38
            $container,
39
            $jobTimingManagerType,
40
            'job_timing',
41
            'JobTiming',
42
            JobTiming::class
43
        ));
44
        $container->setParameter('dtc_queue.class_run', $this->getClass($container, $managerType, 'run', 'Run', Run::class));
45
        $container->setParameter('dtc_queue.class_run_archive', $this->getClass($container, $managerType, 'run_archive', 'RunArchive', Run::class));
46
47
        $this->setupTaggedServices($container, $definition, $jobClass);
48
        $eventDispatcher = $container->getDefinition('dtc_queue.event_dispatcher');
49
        foreach ($container->findTaggedServiceIds('dtc_queue.event_subscriber') as $id => $attributes) {
50
            $eventSubscriber = $container->getDefinition($id);
51
            $eventDispatcher->addMethodCall('addSubscriber', [$eventSubscriber]);
52
        }
53
        $this->setupDoctrineManagers($container);
54
        $this->addLiveJobs($container);
55
    }
56
57
    protected function setupAlias(ContainerBuilder $container, $defaultManagerType, $type)
58
    {
59
        $definitionName = 'dtc_queue.'.$type.'.'.$defaultManagerType;
60
        if (!$container->hasDefinition($definitionName) && !$container->hasAlias($definitionName)) {
61
            throw new InvalidConfigurationException("No $type manager found for dtc_queue.$type.$defaultManagerType");
62
        }
63
        if ($container->hasDefinition($definitionName)) {
64
            $alias = new Alias('dtc_queue.'.$type.'.'.$defaultManagerType);
65
            $alias->setPublic(true);
66
            $container->setAlias('dtc_queue.'.$type, $alias);
67
68
            return;
69
        }
70
71
        $container->getAlias($definitionName)->setPublic(true);
72
        $container->setAlias('dtc_queue.'.$type, $container->getAlias($definitionName));
73
    }
74
75
    protected function setupAliases(ContainerBuilder $container)
76
    {
77
        $defaultManagerType = $container->getParameter('dtc_queue.default_manager');
78
        $this->setupAlias($container, $defaultManagerType, 'job_manager');
79
        $runManagerType = $container->getParameter($this->getRunManagerType($container));
80
        $this->setupAlias($container, $runManagerType, 'run_manager');
81
        $jobTimingManagerType = $container->getParameter($this->getJobTimingManagerType($container));
82
        $this->setupAlias($container, $jobTimingManagerType, 'job_timing_manager');
83
    }
84
85
    /**
86
     * @param ContainerBuilder $container
87
     * @param Reference[]      $jobManagerRef
0 ignored issues
show
Bug introduced by
There is no parameter named $jobManagerRef. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
88
     * @param string           $jobClass
89
     */
90
    protected function setupTaggedServices(ContainerBuilder $container, Definition $definition, $jobClass)
91
    {
92
        $jobManagerRef = array(new Reference('dtc_queue.job_manager'));
93
        // Add each worker to workerManager, make sure each worker has instance to work
94
        foreach ($container->findTaggedServiceIds('dtc_queue.worker') as $id => $attributes) {
95
            $worker = $container->getDefinition($id);
96
            $class = $container->getDefinition($id)->getClass();
97
98
            $refClass = new \ReflectionClass($class);
99
            $workerClass = 'Dtc\QueueBundle\Model\Worker';
100
            if (!$refClass->isSubclassOf($workerClass)) {
101
                throw new \InvalidArgumentException(sprintf('Service "%s" must extend class "%s".', $id, $workerClass));
102
            }
103
104
            // Give each worker access to job manager
105
            $worker->addMethodCall('setJobManager', $jobManagerRef);
106
            $worker->addMethodCall('setJobClass', array($jobClass));
107
108
            $definition->addMethodCall('addWorker', array(new Reference($id)));
109
        }
110
    }
111
112
    /**
113
     * @param ContainerBuilder $container
114
     */
115
    protected function setupDoctrineManagers(ContainerBuilder $container)
116
    {
117
        $documentManager = $container->getParameter('dtc_queue.document_manager');
118
119
        $odmManager = "doctrine_mongodb.odm.{$documentManager}_document_manager";
120
        if ($container->has($odmManager)) {
121
            $container->setAlias('dtc_queue.document_manager', $odmManager);
122
        }
123
124
        $entityManager = $container->getParameter('dtc_queue.entity_manager');
125
126
        $ormManager = "doctrine.orm.{$entityManager}_entity_manager";
127
        if ($container->has($ormManager)) {
128
            $container->setAlias('dtc_queue.entity_manager', $ormManager);
129
        }
130
    }
131
132
    /**
133
     * @param ContainerBuilder $container
134
     */
135
    protected function addLiveJobs(ContainerBuilder $container)
136
    {
137
        $jobReflection = new \ReflectionClass($container->getParameter('dtc_queue.class_job'));
138
        if ($jobReflection->isInstance(new \Dtc\QueueBundle\Document\Job())) {
139
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_waiting.odm');
140
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_running.odm');
141
        }
142
        if ($jobReflection->isInstance(new \Dtc\QueueBundle\Entity\Job())) {
143
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_waiting.orm');
144
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_running.orm');
145
        }
146
    }
147
148
    /**
149
     * @param $managerType
150
     *
151
     * @return null|string
152
     */
153
    protected function getDirectory($managerType)
154
    {
155
        switch ($managerType) {
156
            case 'mongodb': // deprecated remove in 3.0
157
            case 'odm':
158
                return 'Document';
159
            case 'beanstalkd':
160
                return 'Beanstalkd';
161
            case 'rabbit_mq':
162
                return 'RabbitMQ';
163
            case 'orm':
164
                return 'Entity';
165
        }
166
167
        return null;
168
    }
169
170
    /**
171
     * Determines the job class based on the queue manager type.
172
     *
173
     * @param ContainerBuilder $container
174
     *
175
     * @return mixed|string
176
     *
177
     * @throws InvalidConfigurationException
178
     */
179
    protected function getJobClass(ContainerBuilder $container)
180
    {
181
        $jobClass = $container->getParameter('dtc_queue.class_job');
182
        if (!$jobClass) {
183
            if ($directory = $this->getDirectory($managerType = $container->getParameter('dtc_queue.default_manager'))) {
184
                $jobClass = 'Dtc\QueueBundle\\'.$directory.'\Job';
185
            } else {
186
                throw new InvalidConfigurationException('Unknown default_manager type '.$managerType.' - please specify a Job class in the \'class\' configuration parameter');
187
            }
188
        }
189
190
        $this->testClass($jobClass, Job::class);
191
192
        return $jobClass;
193
    }
194
195
    protected function getRunManagerType(ContainerBuilder $container)
196
    {
197
        $managerType = 'dtc_queue.default_manager';
198
        if ($container->hasParameter('dtc_queue.run_manager')) {
199
            $managerType = 'dtc_queue.run_manager';
200
        }
201
202
        return $managerType;
203
    }
204
205
    protected function getJobTimingManagerType(ContainerBuilder $container)
206
    {
207
        $managerType = $this->getRunManagerType($container);
208
        if ($container->hasParameter('dtc_queue.job_timing_manager')) {
209
            $managerType = 'dtc_queue.job_timing_manager';
210
        }
211
212
        return $managerType;
213
    }
214
215
    protected function getClass(ContainerBuilder $container, $managerType, $type, $className, $baseClass)
216
    {
217
        $runClass = $container->hasParameter('dtc_queue.class_'.$type) ? $container->getParameter('dtc_queue.class_'.$type) : null;
218
        if (!$runClass) {
219
            switch ($container->getParameter($managerType)) {
220
                case 'mongodb': // deprecated remove in 3.0
221
                case 'odm':
222
                    $runClass = 'Dtc\\QueueBundle\\Document\\'.$className;
223
                    break;
224
                case 'orm':
225
                    $runClass = 'Dtc\\QueueBundle\\Entity\\'.$className;
226
                    break;
227
                default:
228
                    $runClass = $baseClass;
229
            }
230
        }
231
232
        $this->testClass($runClass, $baseClass);
233
234
        return $runClass;
235
    }
236
237
    /**
238
     * @throws ClassNotFoundException
239
     * @throws ClassNotSubclassException
240
     */
241
    protected function testClass($className, $parent)
242
    {
243
        if (!class_exists($className)) {
244
            throw new ClassNotFoundException("Can't find class $className");
245
        }
246
247
        $test = new $className();
248
        if (!$test instanceof $className) {
249
            throw new ClassNotSubclassException("$className must be instance of (or derived from) $parent");
250
        }
251
    }
252
253
    /**
254
     * Determines the job class based on the queue manager type.
255
     *
256
     * @param ContainerBuilder $container
257
     *
258
     * @return mixed|string
259
     *
260
     * @throws ClassNotFoundException
261
     * @throws ClassNotSubclassException
262
     */
263
    protected function getJobClassArchive(ContainerBuilder $container)
264
    {
265
        $jobArchiveClass = $container->getParameter('dtc_queue.class_job_archive');
266
        if (!$jobArchiveClass) {
267
            switch ($container->getParameter('dtc_queue.default_manager')) {
268
                case 'mongodb': // deprecated remove in 4.0
269
                case 'odm':
270
                    $jobArchiveClass = 'Dtc\\QueueBundle\\Document\\JobArchive';
271
                    break;
272
                case 'orm':
273
                    $jobArchiveClass = 'Dtc\\QueueBundle\\Entity\\JobArchive';
274
                    break;
275
            }
276
        }
277
        if (null !== $jobArchiveClass) {
278
            $this->testClass($jobArchiveClass, Job::class);
279
        }
280
281
        return $jobArchiveClass;
282
    }
283
}
284