Completed
Push — master ( 692985...e555b8 )
by Matthew
18:05
created

CreateJobCommand::setWorkerManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Dtc\QueueBundle\Command;
4
5
use Dtc\QueueBundle\Exception\WorkerNotRegisteredException;
6
use Dtc\QueueBundle\Manager\WorkerManager;
7
use Dtc\QueueBundle\Model\Job;
8
use Symfony\Component\Console\Command\Command;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
class CreateJobCommand extends Command
15
{
16 1
    protected static $defaultName = 'dtc:queue:create_job';
17
18
    /** @var WorkerManager */
19 1
    private $workerManager;
20 1
21 1
    protected function configure()
22 1
    {
23 1
        $this
24
            ->addOption(
25 1
                'json-args',
26 1
                'j',
27 1
                InputOption::VALUE_NONE,
28 1
                'Consume the args as a single JSON-encoded array'
29 1
            )
30
            ->addOption(
31 1
                'php-args',
32 1
                'p',
33 1
                InputOption::VALUE_NONE,
34 1
                'Consume the args as a single PHP-serialized array'
35 1
            )
36
            ->addOption( // For 5.0 this should become the default
37 1
                'interpret-args',
38 1
                null,
39 1
                InputOption::VALUE_NONE,
40 1
                '(beta) Make a best guess as to the type of the argument passed in (DEFAULT for future releases - also note the "interpretation" may change in upcoming releases).'
41 1
            )
42
            ->addArgument(
43 1
                'worker_name',
44 1
                InputArgument::REQUIRED,
45 1
                'Name of worker',
46 1
                null
47 1
            )
48
            ->addArgument(
49 1
                'method',
50 1
                InputArgument::REQUIRED,
51 1
                'Method of worker to invoke',
52 1
                null
53
            )
54 1
            ->addArgument(
55 1
                'args',
56 1
                InputArgument::IS_ARRAY,
57
                'Argument(s) for invoking worker method'
58 1
            )
59
            ->setDescription('Create a job - for expert users')
60 1
            ->setHelp($this->getHelpMessage())
61
            ->setName(self::$defaultName)
62 1
        ;
63 1
    }
64 1
65 1
    private function getHelpMessage()
66 1
    {
67 1
        $helpMessage = sprintf(
68 1
            "%s --json-args %s %s '%s'".PHP_EOL,
69
            $this->getName(), // command
70
            'my-worker-name', // worker_name
71
            'myMethod', // method
72
            json_encode([ // args
73
                'first parameter', // argv[0] (string)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
74
                null, // argv[1] (null)
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
75
                3, // argv[2] (int)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
76
                [ // argv[3] (array)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
77
                    'fourth',
78
                    'param',
79
                    'is',
80 1
                    'an',
81 1
                    'array',
82
                ],
83 1
            ])
84
        );
85
        $helpMessage .= PHP_EOL;
86 1
        $helpMessage .= '';
87
88 1
        return $helpMessage;
89 1
    }
90 1
91
    public function setWorkerManager($workerManager) {
92 1
        $this->workerManager = $workerManager;
93 1
    }
94
95 1
    protected function execute(InputInterface $input, OutputInterface $output)
96
    {
97 1
        $workerName = $input->getArgument('worker_name');
98
        $methodName = $input->getArgument('method');
99 1
100
        $args = $this->getArgs($input);
101
102
        $worker = $this->workerManager->getWorker($workerName);
103 1
104 1
        if (!$worker) {
105 1
            throw new WorkerNotRegisteredException("Worker `{$workerName}` is not registered.");
106
        }
107 1
108 1
        $when = \Dtc\QueueBundle\Util\Util::getMicrotimeDateTime();
109 1
        $batch = true;
110 1
        $priority = 1;
111
112 1
        $jobClass = $worker->getJobManager()->getJobClass();
113 1
        /** @var Job $job */
114
        $job = new $jobClass($worker, $batch, $priority, $when);
115 1
        $job->setMethod($methodName);
0 ignored issues
show
Bug introduced by
It seems like $methodName can also be of type string[]; however, parameter $method of Dtc\QueueBundle\Model\BaseJob::setMethod() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

115
        $job->setMethod(/** @scrutinizer ignore-type */ $methodName);
Loading history...
116
        $job->setArgs($args);
117 1
118 1
        $worker->getJobManager()->save($job);
119 1
        return 0;
120 1
    }
121 1
122
    protected function getArgs(InputInterface $input)
123 1
    {
124 1
        $args = $input->getArgument('args');
125
        $jsonArgs = $input->getOption('json-args');
126 1
        $phpArgs = $input->getOption('php-args');
127 1
        $interpretArgs = $input->getOption('interpret-args');
128
        $this->validateJsonArgs($jsonArgs, $phpArgs, $interpretArgs);
129 1
130 1
        if ($jsonArgs) {
131
            return $this->decodeJsonArgs($args);
132
        }
133
        if ($phpArgs) {
134
            return $this->decodePHPArgs($args);
0 ignored issues
show
Bug introduced by
It seems like $args can also be of type string[]; however, parameter $phpArgs of Dtc\QueueBundle\Command\...ommand::decodePHPArgs() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
            return $this->decodePHPArgs(/** @scrutinizer ignore-type */ $args);
Loading history...
135
        }
136 1
        if ($interpretArgs) {
137
            return $this->interpretArgs($args);
138 1
        }
139 1
140 1
        return $args;
141
    }
142
143
    protected function validateJsonArgs($jsonArgs, $phpArgs, $interpretArgs)
144 1
    {
145 1
        if ($jsonArgs) {
146
            if ($phpArgs || $interpretArgs) {
147 1
                throw new \InvalidArgumentException('Should not have both JSON args plus another type of args');
148
            }
149 1
        }
150 1
151 1
        $this->validatePHPArgs($phpArgs, $interpretArgs);
152
    }
153
154 1
    protected function validatePHPArgs($phpArgs, $interpretArgs)
155
    {
156 1
        if ($phpArgs) {
157
            if ($interpretArgs) {
158 1
                throw new \InvalidArgumentException('Should not have both PHP args plus another type of args');
159 1
            }
160
        }
161
    }
162 1
163
    protected function interpretArgs($args)
164 1
    {
165 1
        if (null === $args || 0 == count($args)) {
166
            return $args;
167
        }
168 1
169
        $finalArgs = [];
170
171 1
        foreach ($args as $arg) {
172
            $finalArgs[] = $this->booleanInterpretation($arg);
173 1
        }
174 1
175
        return $finalArgs;
176 1
    }
177 1
178
    private function booleanInterpretation($arg)
179
    {
180 1
        if ('true' === $arg || 'TRUE' === $arg) {
181
            return true;
182
        }
183 1
        if ('false' === $arg || 'FALSE' === $arg) {
184
            return false;
185 1
        }
186 1
187 1
        return $this->integerInterpretation($arg);
188 1
    }
189
190
    private function integerInterpretation($arg)
191
    {
192
        if (ctype_digit($arg)) {
193
            $intArg = intval($arg);
194 1
            if (strval($intArg) === $arg) {
195
                return $intArg;
196
            }
197 1
            // Must be a super-long number
198
            return $arg;
199 1
        }
200 1
201
        return $this->floatInterpretation($arg);
202 1
    }
203
204
    private function floatInterpretation($arg)
205 1
    {
206
        if (is_numeric($arg)) {
207
            $floatArg = floatval($arg);
208 1
209
            return $floatArg;
210 1
        }
211 1
212
        return $this->nullInterpretation($arg);
213
    }
214 1
215
    private function nullInterpretation($arg)
216
    {
217 1
        if ('null' === $arg || 'NULL' === $arg) {
218
            return null;
219 1
        }
220 1
221
        return $arg;
222 1
    }
223 1
224
    protected function decodeJsonArgs($jsonArgs)
225
    {
226
        if (1 !== count($jsonArgs)) {
227 1
            throw new \InvalidArgumentException('args should be a single string containing a JSON-encoded array when using --json-args');
228
        }
229
        $args = json_decode($jsonArgs[0], true);
230
        if (null === $args) {
231
            throw new \InvalidArgumentException('unable to decode JSON-encoded args: '.$jsonArgs[0]);
232
        }
233
234
        return $this->testArgs('JSON', $args);
235
    }
236 1
237
    /**
238 1
     * @param string $type
239
     * @param array  $args
240
     *
241 1
     * @return mixed
242
     */
243
    protected function testArgs($type, $args)
244
    {
245 1
        if (!is_array($args)) {
0 ignored issues
show
introduced by
The condition is_array($args) is always true.
Loading history...
246
            throw new \InvalidArgumentException('unable to decode '.$type.'-encoded args into an array.');
247
        }
248
        if (array_values($args) !== $args) {
249
            throw new \InvalidArgumentException('Expecting numerically-indexed array in '.$type.' arguments');
250
        }
251
252
        return $args;
253 1
    }
254
255 1
    /**
256 1
     * @param string $phpArgs
257
     *
258 1
     * @return mixed
259
     */
260 1
    protected function decodePHPArgs($phpArgs)
261
    {
262
        if (1 !== count($phpArgs)) {
0 ignored issues
show
Bug introduced by
$phpArgs of type string is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

262
        if (1 !== count(/** @scrutinizer ignore-type */ $phpArgs)) {
Loading history...
263
            throw new \InvalidArgumentException('args should be a single string containing a PHP-encoded array when using --php-args');
264
        }
265
        $args = unserialize($phpArgs[0]);
266
267
        return $this->testArgs('PHP', $args);
268
    }
269
}
270