Passed
Pull Request — master (#93)
by
unknown
07:39
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 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
13
{
14
    protected static $defaultName = 'dtc:queue:create_job';
15
16 1
    protected function configure()
17
    {
18
        $this
19 1
            ->addOption(
20 1
                'json-args',
21 1
                'j',
22 1
                InputOption::VALUE_NONE,
23 1
                'Consume the args as a single JSON-encoded array'
24
            )
25 1
            ->addOption(
26 1
                'php-args',
27 1
                'p',
28 1
                InputOption::VALUE_NONE,
29 1
                'Consume the args as a single PHP-serialized array'
30
            )
31 1
            ->addOption( // For 5.0 this should become the default
32 1
                'interpret-args',
33 1
                null,
34 1
                InputOption::VALUE_NONE,
35 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).'
36
            )
37 1
            ->addArgument(
38 1
                'worker_name',
39 1
                InputArgument::REQUIRED,
40 1
                'Name of worker',
41 1
                null
42
            )
43 1
            ->addArgument(
44 1
                'method',
45 1
                InputArgument::REQUIRED,
46 1
                'Method of worker to invoke',
47 1
                null
48
            )
49 1
            ->addArgument(
50 1
                'args',
51 1
                InputArgument::IS_ARRAY,
52 1
                'Argument(s) for invoking worker method'
53
            )
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)
69
                null, // argv[1] (null)
70
                3, // argv[2] (int)
71
                [ // argv[3] (array)
72
                    'fourth',
73
                    'param',
74
                    'is',
75
                    'an',
76
                    'array',
77
                ],
78
            ])
79
        );
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);
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
        }
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
        }
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
        }
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