Completed
Push — master ( 2f0980...94c998 )
by Matthew
33:32 queued 29:55
created

CreateJobCommand::getArgs()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.0072

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 4
nop 1
dl 0
loc 19
ccs 12
cts 13
cp 0.9231
crap 4.0072
rs 9.8666
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
    protected static $defaultName = 'dtc:queue:create_job';
17
18
    /** @var WorkerManager */
19
    private $workerManager;
20
21 1
    protected function configure()
22
    {
23
        $this
24 1
            ->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
            )
30 1
            ->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
            )
36 1
            ->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
            )
42 1
            ->addArgument(
43 1
                'worker_name',
44 1
                InputArgument::REQUIRED,
45 1
                'Name of worker',
46 1
                null
47
            )
48 1
            ->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 1
                'Argument(s) for invoking worker method'
58
            )
59 1
            ->setDescription('Create a job - for expert users')
60 1
            ->setHelp($this->getHelpMessage())
61 1
            ->setName(self::$defaultName)
62
        ;
63 1
    }
64
65 1
    private function getHelpMessage()
66
    {
67 1
        $helpMessage = sprintf(
68 1
            "%s --json-args %s %s '%s'".PHP_EOL,
69 1
            $this->getName(), // command
70 1
            'my-worker-name', // worker_name
71 1
            'myMethod', // method
72
            json_encode([ // args
73 1
                '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
                    'an',
81
                    'array',
82
                ],
83
            ])
84
        );
85 1
        $helpMessage .= PHP_EOL;
86 1
        $helpMessage .= '';
87
88 1
        return $helpMessage;
89
    }
90
91 1
    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 1
        $methodName = $input->getArgument('method');
99
100 1
        $args = $this->getArgs($input);
101
102 1
        $worker = $this->workerManager->getWorker($workerName);
103
104 1
        if (!$worker) {
105
            throw new WorkerNotRegisteredException("Worker `{$workerName}` is not registered.");
106
        }
107
108 1
        $when = \Dtc\QueueBundle\Util\Util::getMicrotimeDateTime();
109 1
        $batch = true;
110 1
        $priority = 1;
111
112 1
        $jobClass = $worker->getJobManager()->getJobClass();
113
        /** @var Job $job */
114 1
        $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 1
        $job->setArgs($args);
117
118 1
        $worker->getJobManager()->save($job);
119 1
        return 0;
120
    }
121
122 1
    protected function getArgs(InputInterface $input)
123
    {
124 1
        $args = $input->getArgument('args');
125 1
        $jsonArgs = $input->getOption('json-args');
126 1
        $phpArgs = $input->getOption('php-args');
127 1
        $interpretArgs = $input->getOption('interpret-args');
128 1
        $this->validateJsonArgs($jsonArgs, $phpArgs, $interpretArgs);
129
130 1
        if ($jsonArgs) {
131 1
            return $this->decodeJsonArgs($args);
132
        }
133 1
        if ($phpArgs) {
134 1
            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 1
            return $this->interpretArgs($args);
138
        }
139
140
        return $args;
141
    }
142
143 1
    protected function validateJsonArgs($jsonArgs, $phpArgs, $interpretArgs)
144
    {
145 1
        if ($jsonArgs) {
146 1
            if ($phpArgs || $interpretArgs) {
147 1
                throw new \InvalidArgumentException('Should not have both JSON args plus another type of args');
148
            }
149
        }
150
151 1
        $this->validatePHPArgs($phpArgs, $interpretArgs);
152 1
    }
153
154 1
    protected function validatePHPArgs($phpArgs, $interpretArgs)
155
    {
156 1
        if ($phpArgs) {
157 1
            if ($interpretArgs) {
158 1
                throw new \InvalidArgumentException('Should not have both PHP args plus another type of args');
159
            }
160
        }
161 1
    }
162
163 1
    protected function interpretArgs($args)
164
    {
165 1
        if (null === $args || 0 == count($args)) {
166 1
            return $args;
167
        }
168
169 1
        $finalArgs = [];
170
171 1
        foreach ($args as $arg) {
172 1
            $finalArgs[] = $this->booleanInterpretation($arg);
173
        }
174
175 1
        return $finalArgs;
176
    }
177
178 1
    private function booleanInterpretation($arg)
179
    {
180 1
        if ('true' === $arg || 'TRUE' === $arg) {
181 1
            return true;
182
        }
183 1
        if ('false' === $arg || 'FALSE' === $arg) {
184 1
            return false;
185
        }
186
187 1
        return $this->integerInterpretation($arg);
188
    }
189
190 1
    private function integerInterpretation($arg)
191
    {
192 1
        if (ctype_digit($arg)) {
193 1
            $intArg = intval($arg);
194 1
            if (strval($intArg) === $arg) {
195 1
                return $intArg;
196
            }
197
            // Must be a super-long number
198
            return $arg;
199
        }
200
201 1
        return $this->floatInterpretation($arg);
202
    }
203
204 1
    private function floatInterpretation($arg)
205
    {
206 1
        if (is_numeric($arg)) {
207 1
            $floatArg = floatval($arg);
208
209 1
            return $floatArg;
210
        }
211
212 1
        return $this->nullInterpretation($arg);
213
    }
214
215 1
    private function nullInterpretation($arg)
216
    {
217 1
        if ('null' === $arg || 'NULL' === $arg) {
218 1
            return null;
219
        }
220
221 1
        return $arg;
222
    }
223
224 1
    protected function decodeJsonArgs($jsonArgs)
225
    {
226 1
        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 1
        $args = json_decode($jsonArgs[0], true);
230 1
        if (null === $args) {
231
            throw new \InvalidArgumentException('unable to decode JSON-encoded args: '.$jsonArgs[0]);
232
        }
233
234 1
        return $this->testArgs('JSON', $args);
235
    }
236
237
    /**
238
     * @param string $type
239
     * @param array  $args
240
     *
241
     * @return mixed
242
     */
243 1
    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 1
        if (array_values($args) !== $args) {
249
            throw new \InvalidArgumentException('Expecting numerically-indexed array in '.$type.' arguments');
250
        }
251
252 1
        return $args;
253
    }
254
255
    /**
256
     * @param string $phpArgs
257
     *
258
     * @return mixed
259
     */
260 1
    protected function decodePHPArgs($phpArgs)
261
    {
262 1
        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 1
            throw new \InvalidArgumentException('args should be a single string containing a PHP-encoded array when using --php-args');
264
        }
265 1
        $args = unserialize($phpArgs[0]);
266
267 1
        return $this->testArgs('PHP', $args);
268
    }
269
}
270