Passed
Push — master ( 82017d...f35517 )
by Matthew
08:19
created

CreateJobCommand::getHelpMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1.0007

Importance

Changes 0
Metric Value
cc 1
eloc 16
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 24
ccs 10
cts 11
cp 0.9091
crap 1.0007
rs 9.7333
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
    {
93 1
        $this->workerManager = $workerManager;
94 1
    }
95
96 1
    protected function execute(InputInterface $input, OutputInterface $output)
97
    {
98 1
        $workerName = $input->getArgument('worker_name');
99 1
        $methodName = $input->getArgument('method');
100
101 1
        $args = $this->getArgs($input);
102
103 1
        $worker = $this->workerManager->getWorker($workerName);
104
105 1
        if (!$worker) {
106
            throw new WorkerNotRegisteredException("Worker `{$workerName}` is not registered.");
107
        }
108
109 1
        $when = \Dtc\QueueBundle\Util\Util::getMicrotimeDateTime();
110 1
        $batch = true;
111 1
        $priority = 1;
112
113 1
        $jobClass = $worker->getJobManager()->getJobClass();
114
        /** @var Job $job */
115 1
        $job = new $jobClass($worker, $batch, $priority, $when);
116 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

116
        $job->setMethod(/** @scrutinizer ignore-type */ $methodName);
Loading history...
117 1
        $job->setArgs($args);
118
119 1
        $worker->getJobManager()->save($job);
120
121 1
        return 0;
122
    }
123
124 1
    protected function getArgs(InputInterface $input)
125
    {
126 1
        $args = $input->getArgument('args');
127 1
        $jsonArgs = $input->getOption('json-args');
128 1
        $phpArgs = $input->getOption('php-args');
129 1
        $interpretArgs = $input->getOption('interpret-args');
130 1
        $this->validateJsonArgs($jsonArgs, $phpArgs, $interpretArgs);
131
132 1
        if ($jsonArgs) {
133 1
            return $this->decodeJsonArgs($args);
134
        }
135 1
        if ($phpArgs) {
136 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

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

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