Passed
Push — 5.1 ( 2420e5...326bc3 )
by liu
09:30 queued 01:11
created

Console::all()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | TopThink [ WE CAN DO IT JUST THINK IT ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2015 http://www.topthink.com All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Author: zhangyajun <[email protected]>
8
// +----------------------------------------------------------------------
9
10
namespace think;
11
12
use think\console\Command;
13
use think\console\command\Help as HelpCommand;
14
use think\console\Input;
15
use think\console\input\Argument as InputArgument;
16
use think\console\input\Definition as InputDefinition;
17
use think\console\input\Option as InputOption;
18
use think\console\Output;
19
use think\console\output\driver\Buffer;
20
21
class Console
1 ignored issue
show
Coding Style introduced by
Missing class doc comment
Loading history...
22
{
23
24
    private $name;
0 ignored issues
show
Coding Style introduced by
Private member variable "name" must be prefixed with an underscore
Loading history...
25
    private $version;
0 ignored issues
show
Coding Style introduced by
Private member variable "version" must be prefixed with an underscore
Loading history...
26
27
    /** @var Command[] */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
28
    private $commands = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "commands" must be prefixed with an underscore
Loading history...
29
30
    private $wantHelps = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "wantHelps" must be prefixed with an underscore
Loading history...
31
32
    private $catchExceptions = true;
0 ignored issues
show
Coding Style introduced by
Private member variable "catchExceptions" must be prefixed with an underscore
Loading history...
33
    private $autoExit        = true;
0 ignored issues
show
Coding Style introduced by
Private member variable "autoExit" must be prefixed with an underscore
Loading history...
34
    private $definition;
0 ignored issues
show
Coding Style introduced by
Private member variable "definition" must be prefixed with an underscore
Loading history...
35
    private $defaultCommand;
0 ignored issues
show
Coding Style introduced by
Private member variable "defaultCommand" must be prefixed with an underscore
Loading history...
36
37
    private static $defaultCommands = [
0 ignored issues
show
Coding Style introduced by
Private member variable "defaultCommands" must be prefixed with an underscore
Loading history...
38
        'help'              => "think\\console\\command\\Help",
39
        'list'              => "think\\console\\command\\Lists",
40
        'build'             => "think\\console\\command\\Build",
41
        'clear'             => "think\\console\\command\\Clear",
42
        'make:command'      => "think\\console\\command\\make\\Command",
43
        'make:controller'   => "think\\console\\command\\make\\Controller",
44
        'make:model'        => "think\\console\\command\\make\\Model",
45
        'make:middleware'   => "think\\console\\command\\make\\Middleware",
46
        'make:validate'     => "think\\console\\command\\make\\Validate",
47
        'optimize:autoload' => "think\\console\\command\\optimize\\Autoload",
48
        'optimize:config'   => "think\\console\\command\\optimize\\Config",
49
        'optimize:schema'   => "think\\console\\command\\optimize\\Schema",
50
        'optimize:route'    => "think\\console\\command\\optimize\\Route",
51
        'run'               => "think\\console\\command\\RunServer",
52
        'version'           => "think\\console\\command\\Version",
53
        'route:list'        => "think\\console\\command\\RouteList",
54
    ];
55
56
    /**
57
     * Console constructor.
58
     * @access public
59
     * @param  string     $name    名称
60
     * @param  string     $version 版本
61
     * @param null|string $user    执行用户
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
62
     */
63
    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', $user = null)
64
    {
65
        $this->name    = $name;
66
        $this->version = $version;
67
68
        if ($user) {
69
            $this->setUser($user);
70
        }
71
72
        $this->defaultCommand = 'list';
73
        $this->definition     = $this->getDefaultInputDefinition();
74
    }
75
76
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $user should have a doc-comment as per coding-style.
Loading history...
77
     * 设置执行用户
78
     * @param $user
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
79
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
80
    public function setUser($user)
81
    {
82
        if (DIRECTORY_SEPARATOR == '\\') {
83
            return;
84
        }
85
86
        $user = posix_getpwnam($user);
87
        if ($user) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $user of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
88
            posix_setuid($user['uid']);
89
            posix_setgid($user['gid']);
90
        }
91
    }
92
93
    /**
94
     * 初始化 Console
95
     * @access public
96
     * @param  bool $run 是否运行 Console
97
     * @return int|Console
98
     */
99
    public static function init($run = true)
100
    {
101
        static $console;
102
103
        if (!$console) {
104
            $config  = Container::get('config')->pull('console');
105
            $console = new self($config['name'], $config['version'], $config['user']);
106
107
            $commands = $console->getDefinedCommands($config);
108
109
            // 添加指令集
110
            $console->addCommands($commands);
111
        }
112
113
        if ($run) {
114
            // 运行
115
            return $console->run();
116
        } else {
117
            return $console;
118
        }
119
    }
120
121
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
122
     * @access public
123
     * @param  array $config
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
124
     * @return array
125
     */
126
    public function getDefinedCommands(array $config = [])
127
    {
128
        $commands = self::$defaultCommands;
129
130
        if (!empty($config['auto_path']) && is_dir($config['auto_path'])) {
131
            // 自动加载指令类
132
            $files = scandir($config['auto_path']);
133
134
            if (count($files) > 2) {
0 ignored issues
show
Bug introduced by
It seems like $files can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, 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
            if (count(/** @scrutinizer ignore-type */ $files) > 2) {
Loading history...
135
                $beforeClass = get_declared_classes();
136
137
                foreach ($files as $file) {
138
                    if (pathinfo($file, PATHINFO_EXTENSION) == 'php') {
139
                        include $config['auto_path'] . $file;
140
                    }
141
                }
142
143
                $afterClass = get_declared_classes();
144
                $commands   = array_merge($commands, array_diff($afterClass, $beforeClass));
145
            }
146
        }
147
148
        $file = Container::get('env')->get('app_path') . 'command.php';
149
150
        if (is_file($file)) {
151
            $appCommands = include $file;
152
153
            if (is_array($appCommands)) {
154
                $commands = array_merge($commands, $appCommands);
155
            }
156
        }
157
158
        return $commands;
159
    }
160
161
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
162
     * @access public
163
     * @param  string $command
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
164
     * @param  array  $parameters
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
165
     * @param  string $driver
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
166
     * @return Output|Buffer
167
     */
168
    public static function call($command, array $parameters = [], $driver = 'buffer')
169
    {
170
        $console = self::init(false);
171
172
        array_unshift($parameters, $command);
173
174
        $input  = new Input($parameters);
175
        $output = new Output($driver);
176
177
        $console->setCatchExceptions(false);
178
        $console->find($command)->run($input, $output);
179
180
        return $output;
181
    }
182
183
    /**
184
     * 执行当前的指令
185
     * @access public
186
     * @return int
187
     * @throws \Exception
188
     * @api
189
     */
190
    public function run()
191
    {
192
        $input  = new Input();
193
        $output = new Output();
194
195
        $this->configureIO($input, $output);
196
197
        try {
198
            $exitCode = $this->doRun($input, $output);
199
        } catch (\Exception $e) {
200
            if (!$this->catchExceptions) {
201
                throw $e;
202
            }
203
204
            $output->renderException($e);
205
206
            $exitCode = $e->getCode();
207
            if (is_numeric($exitCode)) {
208
                $exitCode = (int) $exitCode;
209
                if (0 === $exitCode) {
210
                    $exitCode = 1;
211
                }
212
            } else {
213
                $exitCode = 1;
214
            }
215
        }
216
217
        if ($this->autoExit) {
218
            if ($exitCode > 255) {
219
                $exitCode = 255;
220
            }
221
222
            exit($exitCode);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
223
        }
224
225
        return $exitCode;
226
    }
227
228
    /**
229
     * 执行指令
230
     * @access public
231
     * @param  Input  $input
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
232
     * @param  Output $output
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
233
     * @return int
234
     */
235
    public function doRun(Input $input, Output $output)
236
    {
237
        if (true === $input->hasParameterOption(['--version', '-V'])) {
238
            $output->writeln($this->getLongVersion());
239
240
            return 0;
241
        }
242
243
        $name = $this->getCommandName($input);
244
245
        if (true === $input->hasParameterOption(['--help', '-h'])) {
246
            if (!$name) {
247
                $name  = 'help';
248
                $input = new Input(['help']);
249
            } else {
250
                $this->wantHelps = true;
251
            }
252
        }
253
254
        if (!$name) {
255
            $name  = $this->defaultCommand;
256
            $input = new Input([$this->defaultCommand]);
257
        }
258
259
        $command = $this->find($name);
260
261
        $exitCode = $this->doRunCommand($command, $input, $output);
262
263
        return $exitCode;
264
    }
265
266
    /**
267
     * 设置输入参数定义
268
     * @access public
269
     * @param  InputDefinition $definition
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
270
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
271
    public function setDefinition(InputDefinition $definition)
272
    {
273
        $this->definition = $definition;
274
    }
275
276
    /**
277
     * 获取输入参数定义
278
     * @access public
279
     * @return InputDefinition The InputDefinition instance
280
     */
281
    public function getDefinition()
282
    {
283
        return $this->definition;
284
    }
285
286
    /**
287
     * Gets the help message.
288
     * @access public
289
     * @return string A help message.
290
     */
291
    public function getHelp()
292
    {
293
        return $this->getLongVersion();
294
    }
295
296
    /**
297
     * 是否捕获异常
298
     * @access public
299
     * @param  bool $boolean
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
300
     * @api
301
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
302
    public function setCatchExceptions($boolean)
303
    {
304
        $this->catchExceptions = (bool) $boolean;
305
    }
306
307
    /**
308
     * 是否自动退出
309
     * @access public
310
     * @param  bool $boolean
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
311
     * @api
312
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
313
    public function setAutoExit($boolean)
314
    {
315
        $this->autoExit = (bool) $boolean;
316
    }
317
318
    /**
319
     * 获取名称
320
     * @access public
321
     * @return string
322
     */
323
    public function getName()
324
    {
325
        return $this->name;
326
    }
327
328
    /**
329
     * 设置名称
330
     * @access public
331
     * @param  string $name
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
332
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
333
    public function setName($name)
334
    {
335
        $this->name = $name;
336
    }
337
338
    /**
339
     * 获取版本
340
     * @access public
341
     * @return string
342
     * @api
343
     */
344
    public function getVersion()
345
    {
346
        return $this->version;
347
    }
348
349
    /**
350
     * 设置版本
351
     * @access public
352
     * @param  string $version
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
353
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
354
    public function setVersion($version)
355
    {
356
        $this->version = $version;
357
    }
358
359
    /**
360
     * 获取完整的版本号
361
     * @access public
362
     * @return string
363
     */
364
    public function getLongVersion()
365
    {
366
        if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
367
            return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
368
        }
369
370
        return '<info>Console Tool</info>';
371
    }
372
373
    /**
374
     * 注册一个指令 (便于动态创建指令)
375
     * @access public
376
     * @param  string $name     指令名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 5 found
Loading history...
377
     * @return Command
378
     */
379
    public function register($name)
380
    {
381
        return $this->add(new Command($name));
0 ignored issues
show
Bug introduced by
The call to think\Console::add() has too few arguments starting with name. ( Ignorable by Annotation )

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

381
        return $this->/** @scrutinizer ignore-call */ add(new Command($name));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
382
    }
383
384
    /**
385
     * 添加指令集
386
     * @access public
387
     * @param  array $commands
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
388
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
389
    public function addCommands(array $commands)
390
    {
391
        foreach ($commands as $key => $command) {
392
            if (is_subclass_of($command, "\\think\\console\\Command")) {
393
                // 注册指令
394
                $this->add($command, is_numeric($key) ? '' : $key);
395
            }
396
        }
397
    }
398
399
    /**
400
     * 注册一个指令(对象)
401
     * @access public
402
     * @param  mixed    $command    指令对象或者指令类名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
403
     * @param  string   $name       指令名 留空则自动获取
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 7 found
Loading history...
404
     * @return mixed
405
     */
406
    public function add($command, $name)
407
    {
408
        if ($name) {
409
            $this->commands[$name] = $command;
410
            return;
411
        }
412
413
        if (is_string($command)) {
414
            $command = new $command();
415
        }
416
417
        $command->setConsole($this);
418
419
        if (!$command->isEnabled()) {
420
            $command->setConsole(null);
421
            return;
422
        }
423
424
        if (null === $command->getDefinition()) {
425
            throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
426
        }
427
428
        $this->commands[$command->getName()] = $command;
429
430
        foreach ($command->getAliases() as $alias) {
431
            $this->commands[$alias] = $command;
432
        }
433
434
        return $command;
435
    }
436
437
    /**
438
     * 获取指令
439
     * @access public
440
     * @param  string $name 指令名称
441
     * @return Command
442
     * @throws \InvalidArgumentException
443
     */
444
    public function get($name)
445
    {
446
        if (!isset($this->commands[$name])) {
447
            throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
448
        }
449
450
        $command = $this->commands[$name];
451
452
        if (is_string($command)) {
0 ignored issues
show
introduced by
The condition is_string($command) is always false.
Loading history...
453
            $command = new $command();
454
        }
455
456
        $command->setConsole($this);
457
458
        if ($this->wantHelps) {
459
            $this->wantHelps = false;
460
461
            /** @var HelpCommand $helpCommand */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
462
            $helpCommand = $this->get('help');
463
            $helpCommand->setCommand($command);
464
465
            return $helpCommand;
466
        }
467
468
        return $command;
469
    }
470
471
    /**
472
     * 某个指令是否存在
473
     * @access public
474
     * @param  string $name 指令名称
475
     * @return bool
476
     */
477
    public function has($name)
478
    {
479
        return isset($this->commands[$name]);
480
    }
481
482
    /**
483
     * 获取所有的命名空间
484
     * @access public
485
     * @return array
486
     */
487
    public function getNamespaces()
488
    {
489
        $namespaces = [];
490
        foreach ($this->commands as $command) {
491
            $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
492
493
            foreach ($command->getAliases() as $alias) {
494
                $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
495
            }
496
        }
497
498
        return array_values(array_unique(array_filter($namespaces)));
499
    }
500
501
    /**
502
     * 查找注册命名空间中的名称或缩写。
503
     * @access public
504
     * @param  string $namespace
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
505
     * @return string
506
     * @throws \InvalidArgumentException
507
     */
508
    public function findNamespace($namespace)
509
    {
510
        $allNamespaces = $this->getNamespaces();
511
        $expr          = preg_replace_callback('{([^:]+|)}', function ($matches) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
512
            return preg_quote($matches[1]) . '[^:]*';
513
        }, $namespace);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
514
        $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);
515
516
        if (empty($namespaces)) {
517
            $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
518
519
            if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
520
                if (1 == count($alternatives)) {
521
                    $message .= "\n\nDid you mean this?\n    ";
522
                } else {
523
                    $message .= "\n\nDid you mean one of these?\n    ";
524
                }
525
526
                $message .= implode("\n    ", $alternatives);
527
            }
528
529
            throw new \InvalidArgumentException($message);
530
        }
531
532
        $exact = in_array($namespace, $namespaces, true);
533
        if (count($namespaces) > 1 && !$exact) {
534
            throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
535
        }
536
537
        return $exact ? $namespace : reset($namespaces);
538
    }
539
540
    /**
541
     * 查找指令
542
     * @access public
543
     * @param  string $name 名称或者别名
544
     * @return Command
545
     * @throws \InvalidArgumentException
546
     */
547
    public function find($name)
548
    {
549
        $allCommands = array_keys($this->commands);
550
551
        $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
552
            return preg_quote($matches[1]) . '[^:]*';
553
        }, $name);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
554
555
        $commands = preg_grep('{^' . $expr . '}', $allCommands);
556
557
        if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
558
            if (false !== $pos = strrpos($name, ':')) {
559
                $this->findNamespace(substr($name, 0, $pos));
560
            }
561
562
            $message = sprintf('Command "%s" is not defined.', $name);
563
564
            if ($alternatives = $this->findAlternatives($name, $allCommands)) {
565
                if (1 == count($alternatives)) {
566
                    $message .= "\n\nDid you mean this?\n    ";
567
                } else {
568
                    $message .= "\n\nDid you mean one of these?\n    ";
569
                }
570
                $message .= implode("\n    ", $alternatives);
571
            }
572
573
            throw new \InvalidArgumentException($message);
574
        }
575
576
        $exact = in_array($name, $commands, true);
577
        if (count($commands) > 1 && !$exact) {
578
            $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
579
580
            throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
581
        }
582
583
        return $this->get($exact ? $name : reset($commands));
584
    }
585
586
    /**
587
     * 获取所有的指令
588
     * @access public
589
     * @param  string $namespace 命名空间
590
     * @return Command[]
591
     * @api
592
     */
593
    public function all($namespace = null)
594
    {
595
        if (null === $namespace) {
596
            return $this->commands;
597
        }
598
599
        $commands = [];
600
        foreach ($this->commands as $name => $command) {
601
            if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) {
602
                $commands[$name] = $command;
603
            }
604
        }
605
606
        return $commands;
607
    }
608
609
    /**
610
     * 获取可能的指令名
611
     * @access public
612
     * @param  array $names
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
613
     * @return array
614
     */
615
    public static function getAbbreviations($names)
616
    {
617
        $abbrevs = [];
618
        foreach ($names as $name) {
619
            for ($len = strlen($name); $len > 0; --$len) {
620
                $abbrev             = substr($name, 0, $len);
621
                $abbrevs[$abbrev][] = $name;
622
            }
623
        }
624
625
        return $abbrevs;
626
    }
627
628
    /**
629
     * 配置基于用户的参数和选项的输入和输出实例。
630
     * @access protected
631
     * @param  Input  $input  输入实例
632
     * @param  Output $output 输出实例
633
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
634
    protected function configureIO(Input $input, Output $output)
635
    {
636
        if (true === $input->hasParameterOption(['--ansi'])) {
637
            $output->setDecorated(true);
638
        } elseif (true === $input->hasParameterOption(['--no-ansi'])) {
639
            $output->setDecorated(false);
640
        }
641
642
        if (true === $input->hasParameterOption(['--no-interaction', '-n'])) {
643
            $input->setInteractive(false);
644
        }
645
646
        if (true === $input->hasParameterOption(['--quiet', '-q'])) {
647
            $output->setVerbosity(Output::VERBOSITY_QUIET);
648
        } else {
649
            if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
650
                $output->setVerbosity(Output::VERBOSITY_DEBUG);
651
            } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
652
                $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE);
653
            } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
654
                $output->setVerbosity(Output::VERBOSITY_VERBOSE);
655
            }
656
        }
657
    }
658
659
    /**
660
     * 执行指令
661
     * @access protected
662
     * @param  Command $command 指令实例
663
     * @param  Input   $input   输入实例
664
     * @param  Output  $output  输出实例
665
     * @return int
666
     * @throws \Exception
667
     */
668
    protected function doRunCommand(Command $command, Input $input, Output $output)
669
    {
670
        return $command->run($input, $output);
671
    }
672
673
    /**
674
     * 获取指令的基础名称
675
     * @access protected
676
     * @param  Input $input
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
677
     * @return string
678
     */
679
    protected function getCommandName(Input $input)
680
    {
681
        return $input->getFirstArgument();
682
    }
683
684
    /**
685
     * 获取默认输入定义
686
     * @access protected
687
     * @return InputDefinition
688
     */
689
    protected function getDefaultInputDefinition()
690
    {
691
        return new InputDefinition([
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
692
            new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
693
            new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
694
            new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this console version'),
695
            new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
696
            new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
697
            new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
698
            new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
699
            new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
700
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
701
    }
702
703
    public static function addDefaultCommands(array $classnames)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
704
    {
705
        self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);
706
    }
707
708
    /**
709
     * 获取可能的建议
710
     * @access private
711
     * @param  array $abbrevs
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
712
     * @return string
713
     */
714
    private function getAbbreviationSuggestions($abbrevs)
0 ignored issues
show
Coding Style introduced by
Private method name "Console::getAbbreviationSuggestions" must be prefixed with an underscore
Loading history...
715
    {
716
        return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
717
    }
718
719
    /**
720
     * 返回命名空间部分
721
     * @access public
722
     * @param  string $name  指令
723
     * @param  string $limit 部分的命名空间的最大数量
724
     * @return string
725
     */
726
    public function extractNamespace($name, $limit = null)
727
    {
728
        $parts = explode(':', $name);
729
        array_pop($parts);
730
731
        return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
0 ignored issues
show
Bug introduced by
$limit of type string is incompatible with the type integer expected by parameter $length of array_slice(). ( Ignorable by Annotation )

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

731
        return implode(':', null === $limit ? $parts : array_slice($parts, 0, /** @scrutinizer ignore-type */ $limit));
Loading history...
732
    }
733
734
    /**
735
     * 查找可替代的建议
736
     * @access private
737
     * @param  string             $name
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
738
     * @param  array|\Traversable $collection
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
739
     * @return array
740
     */
741
    private function findAlternatives($name, $collection)
0 ignored issues
show
Coding Style introduced by
Private method name "Console::findAlternatives" must be prefixed with an underscore
Loading history...
742
    {
743
        $threshold    = 1e3;
744
        $alternatives = [];
745
746
        $collectionParts = [];
747
        foreach ($collection as $item) {
748
            $collectionParts[$item] = explode(':', $item);
749
        }
750
751
        foreach (explode(':', $name) as $i => $subname) {
752
            foreach ($collectionParts as $collectionName => $parts) {
753
                $exists = isset($alternatives[$collectionName]);
754
                if (!isset($parts[$i]) && $exists) {
755
                    $alternatives[$collectionName] += $threshold;
756
                    continue;
757
                } elseif (!isset($parts[$i])) {
758
                    continue;
759
                }
760
761
                $lev = levenshtein($subname, $parts[$i]);
762
                if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
763
                    $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
764
                } elseif ($exists) {
765
                    $alternatives[$collectionName] += $threshold;
766
                }
767
            }
768
        }
769
770
        foreach ($collection as $item) {
771
            $lev = levenshtein($name, $item);
772
            if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
773
                $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
774
            }
775
        }
776
777
        $alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
778
            return $lev < 2 * $threshold;
779
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
780
        asort($alternatives);
781
782
        return array_keys($alternatives);
783
    }
784
785
    /**
786
     * 设置默认的指令
787
     * @access public
788
     * @param  string $commandName The Command name
789
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
790
    public function setDefaultCommand($commandName)
791
    {
792
        $this->defaultCommand = $commandName;
793
    }
794
795
    /**
796
     * 返回所有的命名空间
797
     * @access private
798
     * @param  string $name
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
799
     * @return array
800
     */
801
    private function extractAllNamespaces($name)
0 ignored issues
show
Coding Style introduced by
Private method name "Console::extractAllNamespaces" must be prefixed with an underscore
Loading history...
802
    {
803
        $parts      = explode(':', $name, -1);
804
        $namespaces = [];
805
806
        foreach ($parts as $part) {
807
            if (count($namespaces)) {
808
                $namespaces[] = end($namespaces) . ':' . $part;
809
            } else {
810
                $namespaces[] = $part;
811
            }
812
        }
813
814
        return $namespaces;
815
    }
816
817
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
818
    {
819
        $data = get_object_vars($this);
820
        unset($data['commands'], $data['definition']);
821
822
        return $data;
823
    }
824
}
825