Passed
Pull Request — master (#101)
by
unknown
12:23
created

CreateJobCommand::nullInterpretation()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
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 Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
7
use Symfony\Component\Console\Input\InputArgument;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Input\InputOption;
10
use Symfony\Component\Console\Output\OutputInterface;
11
12
class CreateJobCommand extends ContainerAwareCommand
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...d\ContainerAwareCommand has been deprecated: since Symfony 4.2, use {@see Command} instead. ( Ignorable by Annotation )

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

12
class CreateJobCommand extends /** @scrutinizer ignore-deprecated */ ContainerAwareCommand
Loading history...
13
{
14
    protected static $defaultName = 'dtc:queue:create_job';
15
16 1
    protected function configure()
17
    {
18 1
        $this
19 1
            ->addOption(
20 1
                'json-args',
21 1
                'j',
22 1
                InputOption::VALUE_NONE,
23
                'Consume the args as a single JSON-encoded array'
24 1
            )
25 1
            ->addOption(
26 1
                'php-args',
27 1
                'p',
28 1
                InputOption::VALUE_NONE,
29
                'Consume the args as a single PHP-serialized array'
30 1
            )
31 1
            ->addOption( // For 5.0 this should become the default
32 1
                'interpret-args',
33 1
                null,
34 1
                InputOption::VALUE_NONE,
35
                '(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).'
36 1
            )
37 1
            ->addArgument(
38 1
                'worker_name',
39 1
                InputArgument::REQUIRED,
40 1
                'Name of worker',
41
                null
42 1
            )
43 1
            ->addArgument(
44 1
                'method',
45 1
                InputArgument::REQUIRED,
46 1
                'Method of worker to invoke',
47
                null
48 1
            )
49 1
            ->addArgument(
50 1
                'args',
51 1
                InputArgument::IS_ARRAY,
52
                'Argument(s) for invoking worker method'
53 1
            )
54 1
            ->setDescription('Create a job - for expert users')
55 1
            ->setHelp($this->getHelpMessage())
56 1
            ->setName(self::$defaultName)
57
        ;
58 1
    }
59
60 1
    private function getHelpMessage()
61
    {
62 1
        $helpMessage = sprintf(
63 1
            "%s --json-args %s %s '%s'".PHP_EOL,
64 1
            $this->getName(), // command
65 1
            'my-worker-name', // worker_name
66 1
            'myMethod', // method
67 1
            json_encode([ // args
68 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...
69 1
                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...
70 1
                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...
71
                [ // 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...
72 1
                    'fourth',
73 1
                    'param',
74 1
                    'is',
75 1
                    'an',
76 1
                    'array',
77 1
                ],
78 1
            ])
79 1
        );
80 1
        $helpMessage .= PHP_EOL;
81 1
        $helpMessage .= '';
82
83 1
        return $helpMessage;
84
    }
85
86 1
    protected function execute(InputInterface $input, OutputInterface $output)
87
    {
88 1
        $container = $this->getContainer();
89 1
        $jobManager = $container->get('dtc_queue.manager.job');
90 1
        $workerManager = $container->get('dtc_queue.manager.worker');
91
92 1
        $workerName = $input->getArgument('worker_name');
93 1
        $methodName = $input->getArgument('method');
94
95 1
        $args = $this->getArgs($input);
96
97 1
        $worker = $workerManager->getWorker($workerName);
98
99 1
        if (!$worker) {
100
            throw new WorkerNotRegisteredException("Worker `{$workerName}` is not registered.");
101
        }
102
103 1
        $when = \Dtc\QueueBundle\Util\Util::getMicrotimeDateTime();
104 1
        $batch = true;
105 1
        $priority = 1;
106
107 1
        $jobClass = $worker->getJobManager()->getJobClass();
108 1
        $job = new $jobClass($worker, $batch, $priority, $when);
109 1
        $job->setMethod($methodName);
110 1
        $job->setArgs($args);
111
112 1
        $jobManager->save($job);
113 1
    }
114
115 1
    protected function getArgs(InputInterface $input)
116
    {
117 1
        $args = $input->getArgument('args');
118 1
        $jsonArgs = $input->getOption('json-args');
119 1
        $phpArgs = $input->getOption('php-args');
120 1
        $interpretArgs = $input->getOption('interpret-args');
121 1
        $this->validateJsonArgs($jsonArgs, $phpArgs, $interpretArgs);
122
123 1
        if ($jsonArgs) {
124 1
            return $this->decodeJsonArgs($args);
125
        }
126 1
        if ($phpArgs) {
127 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

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

255
        if (1 !== count(/** @scrutinizer ignore-type */ $phpArgs)) {
Loading history...
256 1
            throw new \InvalidArgumentException('args should be a single string containing a PHP-encoded array when using --php-args');
257
        }
258 1
        $args = unserialize($phpArgs[0]);
259
260 1
        return $this->testArgs('PHP', $args);
261
    }
262
}
263