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) |
|
|
|
|
74
|
|
|
null, // argv[1] (null) |
|
|
|
|
75
|
|
|
3, // argv[2] (int) |
|
|
|
|
76
|
|
|
[ // argv[3] (array) |
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
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)) { |
|
|
|
|
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)) { |
|
|
|
|
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
|
|
|
|
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.