Completed
Pull Request — master (#31)
by Matthew
06:07
created

WorkerCompilerPass::setupAlias()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.5923

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 8
cts 12
cp 0.6667
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 3
nop 3
crap 4.5923
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 4
    public function process(ContainerBuilder $container)
21
    {
22 4
        if (false === $container->hasDefinition('dtc_queue.worker_manager')) {
23 4
            return;
24
        }
25
26 4
        $this->setupAliases($container);
27
28 4
        $definition = $container->getDefinition('dtc_queue.worker_manager');
29
30 4
        $jobClass = $this->getJobClass($container);
31 3
        $jobArchiveClass = $this->getJobClassArchive($container);
32 3
        $container->setParameter('dtc_queue.class_job', $jobClass);
33 3
        $container->setParameter('dtc_queue.class_job_archive', $jobArchiveClass);
34
35 3
        $managerType = $this->getRunManagerType($container);
36 3
        $jobTimingManagerType = $this->getJobTimingManagerType($container);
37 3
        $container->setParameter('dtc_queue.class_job_timing', $this->getClass(
38 3
            $container,
39 3
            $jobTimingManagerType,
40 3
            'job_timing',
41 3
            'JobTiming',
42
            JobTiming::class
43 3
        ));
44 3
        $container->setParameter('dtc_queue.class_run', $this->getClass($container, $managerType, 'run', 'Run', Run::class));
45 3
        $container->setParameter('dtc_queue.class_run_archive', $this->getClass($container, $managerType, 'run_archive', 'RunArchive', Run::class));
46
47 3
        $this->setupTaggedServices($container, $definition, $jobClass);
48 2
        $eventDispatcher = $container->getDefinition('dtc_queue.event_dispatcher');
49 2
        foreach ($container->findTaggedServiceIds('dtc_queue.event_subscriber') as $id => $attributes) {
50
            $eventSubscriber = $container->getDefinition($id);
51
            $eventDispatcher->addMethodCall('addSubscriber', [$eventSubscriber]);
52 2
        }
53 2
        $this->setupDoctrineManagers($container);
54 2
        $this->addLiveJobs($container);
55 2
    }
56
57
    /**
58
     * @param string $type
59
     */
60 4
    protected function setupAlias(ContainerBuilder $container, $defaultManagerType, $type)
61
    {
62 4
        $definitionName = 'dtc_queue.'.$type.'.'.$defaultManagerType;
63 4
        if (!$container->hasDefinition($definitionName) && !$container->hasAlias($definitionName)) {
64
            throw new InvalidConfigurationException("No $type manager found for dtc_queue.$type.$defaultManagerType");
65
        }
66 4
        if ($container->hasDefinition($definitionName)) {
67 4
            $alias = new Alias('dtc_queue.'.$type.'.'.$defaultManagerType);
68 4
            $alias->setPublic(true);
69 4
            $container->setAlias('dtc_queue.'.$type, $alias);
70
71 4
            return;
72
        }
73
74
        $container->getAlias($definitionName)->setPublic(true);
75
        $container->setAlias('dtc_queue.'.$type, $container->getAlias($definitionName));
76
    }
77
78 4
    protected function setupAliases(ContainerBuilder $container)
79
    {
80 4
        $defaultManagerType = $container->getParameter('dtc_queue.default_manager');
81 4
        $this->setupAlias($container, $defaultManagerType, 'job_manager');
82 4
        $runManagerType = $container->getParameter($this->getRunManagerType($container));
83 4
        $this->setupAlias($container, $runManagerType, 'run_manager');
84 4
        $jobTimingManagerType = $container->getParameter($this->getJobTimingManagerType($container));
85 4
        $this->setupAlias($container, $jobTimingManagerType, 'job_timing_manager');
86 4
    }
87
88
    /**
89
     * @param ContainerBuilder $container
90
     * @param string           $jobClass
91
     */
92 3
    protected function setupTaggedServices(ContainerBuilder $container, Definition $definition, $jobClass)
93
    {
94 3
        $jobManagerRef = array(new Reference('dtc_queue.job_manager'));
95
        // Add each worker to workerManager, make sure each worker has instance to work
96 3
        foreach ($container->findTaggedServiceIds('dtc_queue.worker') as $id => $attributes) {
97 2
            $worker = $container->getDefinition($id);
98 2
            $class = $container->getDefinition($id)->getClass();
99
100 2
            $refClass = new \ReflectionClass($class);
101 2
            $workerClass = 'Dtc\QueueBundle\Model\Worker';
102 2
            if (!$refClass->isSubclassOf($workerClass)) {
103 1
                throw new \InvalidArgumentException(sprintf('Service "%s" must extend class "%s".', $id, $workerClass));
104
            }
105
106
            // Give each worker access to job manager
107 1
            $worker->addMethodCall('setJobManager', $jobManagerRef);
108 1
            $worker->addMethodCall('setJobClass', array($jobClass));
109
110 1
            $definition->addMethodCall('addWorker', array(new Reference($id)));
111 2
        }
112 2
    }
113
114
    /**
115
     * @param ContainerBuilder $container
116
     */
117 2
    protected function setupDoctrineManagers(ContainerBuilder $container)
118
    {
119 2
        $documentManager = $container->getParameter('dtc_queue.document_manager');
120
121 2
        $odmManager = "doctrine_mongodb.odm.{$documentManager}_document_manager";
122 2
        if ($container->has($odmManager)) {
123
            $container->setAlias('dtc_queue.document_manager', $odmManager);
124
        }
125
126 2
        $entityManager = $container->getParameter('dtc_queue.entity_manager');
127
128 2
        $ormManager = "doctrine.orm.{$entityManager}_entity_manager";
129 2
        if ($container->has($ormManager)) {
130
            $container->setAlias('dtc_queue.entity_manager', $ormManager);
131
        }
132 2
    }
133
134
    /**
135
     * @param ContainerBuilder $container
136
     */
137 2
    protected function addLiveJobs(ContainerBuilder $container)
138
    {
139 2
        $jobReflection = new \ReflectionClass($container->getParameter('dtc_queue.class_job'));
140 2
        if ($jobReflection->isInstance(new \Dtc\QueueBundle\Document\Job())) {
141 2
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_waiting.odm');
142 2
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_running.odm');
143 2
        }
144 2
        if ($jobReflection->isInstance(new \Dtc\QueueBundle\Entity\Job())) {
145 1
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_waiting.orm');
146 1
            GridSourceCompilerPass::addGridSource($container, 'dtc_queue.grid_source.jobs_running.orm');
147 1
        }
148 2
    }
149
150
    /**
151
     * @param $managerType
152
     *
153
     * @return null|string
154
     */
155 4
    protected function getDirectory($managerType)
156
    {
157
        switch ($managerType) {
158 4
            case 'mongodb': // deprecated remove in 3.0
159 4
            case 'odm':
160 3
                return 'Document';
161 2
            case 'beanstalkd':
162 1
                return 'Beanstalkd';
163 2
            case 'rabbit_mq':
164 1
                return 'RabbitMQ';
165 2
            case 'orm':
166 1
                return 'Entity';
167
        }
168
169 1
        return null;
170
    }
171
172
    /**
173
     * Determines the job class based on the queue manager type.
174
     *
175
     * @param ContainerBuilder $container
176
     *
177
     * @return mixed|string
178
     *
179
     * @throws InvalidConfigurationException
180
     */
181 4
    protected function getJobClass(ContainerBuilder $container)
182
    {
183 4
        $jobClass = $container->getParameter('dtc_queue.class_job');
184 4
        if (!$jobClass) {
185 4
            if ($directory = $this->getDirectory($managerType = $container->getParameter('dtc_queue.default_manager'))) {
186 3
                $jobClass = 'Dtc\QueueBundle\\'.$directory.'\Job';
187 3
            } else {
188 1
                throw new InvalidConfigurationException('Unknown default_manager type '.$managerType.' - please specify a Job class in the \'class\' configuration parameter');
189
            }
190 3
        }
191
192 3
        $this->testClass($jobClass, Job::class);
193
194 3
        return $jobClass;
195
    }
196
197 4
    protected function getRunManagerType(ContainerBuilder $container)
198
    {
199 4
        $managerType = 'dtc_queue.default_manager';
200 4
        if ($container->hasParameter('dtc_queue.run_manager')) {
201 4
            $managerType = 'dtc_queue.run_manager';
202 4
        }
203
204 4
        return $managerType;
205
    }
206
207 4
    protected function getJobTimingManagerType(ContainerBuilder $container)
208
    {
209 4
        $managerType = $this->getRunManagerType($container);
210 4
        if ($container->hasParameter('dtc_queue.job_timing_manager')) {
211 4
            $managerType = 'dtc_queue.job_timing_manager';
212 4
        }
213
214 4
        return $managerType;
215
    }
216
217
    /**
218
     * @param string $managerType
219
     * @param string $type
220
     * @param string $className
221
     */
222 3
    protected function getClass(ContainerBuilder $container, $managerType, $type, $className, $baseClass)
223
    {
224 3
        $runClass = $container->hasParameter('dtc_queue.class_'.$type) ? $container->getParameter('dtc_queue.class_'.$type) : null;
225 3
        if (!$runClass) {
226 3
            switch ($container->getParameter($managerType)) {
227 3
                case 'mongodb': // deprecated remove in 3.0
228 3
                case 'odm':
229 3
                    $runClass = 'Dtc\\QueueBundle\\Document\\'.$className;
230 3
                    break;
231 1
                case 'orm':
232 1
                    $runClass = 'Dtc\\QueueBundle\\Entity\\'.$className;
233 1
                    break;
234
                default:
235
                    $runClass = $baseClass;
236 3
            }
237 3
        }
238
239 3
        $this->testClass($runClass, $baseClass);
240
241 3
        return $runClass;
242
    }
243
244
    /**
245
     * @throws ClassNotFoundException
246
     * @throws ClassNotSubclassException
247
     */
248 3
    protected function testClass($className, $parent)
249
    {
250 3
        if (!class_exists($className)) {
251
            throw new ClassNotFoundException("Can't find class $className");
252
        }
253
254 3
        $test = new $className();
255 3
        if (!$test instanceof $className) {
256
            throw new ClassNotSubclassException("$className must be instance of (or derived from) $parent");
257
        }
258 3
    }
259
260
    /**
261
     * Determines the job class based on the queue manager type.
262
     *
263
     * @param ContainerBuilder $container
264
     *
265
     * @return mixed|string
266
     *
267
     * @throws ClassNotFoundException
268
     * @throws ClassNotSubclassException
269
     */
270 3
    protected function getJobClassArchive(ContainerBuilder $container)
271
    {
272 3
        $jobArchiveClass = $container->getParameter('dtc_queue.class_job_archive');
273 3
        if (!$jobArchiveClass) {
274 3
            switch ($container->getParameter('dtc_queue.default_manager')) {
275 3
                case 'mongodb': // deprecated remove in 4.0
276 3
                case 'odm':
277 3
                    $jobArchiveClass = 'Dtc\\QueueBundle\\Document\\JobArchive';
278 3
                    break;
279 1
                case 'orm':
280 1
                    $jobArchiveClass = 'Dtc\\QueueBundle\\Entity\\JobArchive';
281 1
                    break;
282 3
            }
283 3
        }
284 3
        if (null !== $jobArchiveClass) {
285 3
            $this->testClass($jobArchiveClass, Job::class);
286 3
        }
287
288 3
        return $jobArchiveClass;
289
    }
290
}
291