Passed
Pull Request — master (#32)
by Jitendra
02:58
created

Extension::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
c 0
b 0
f 0
rs 9.9666
cc 1
nc 1
nop 3
1
<?php
2
3
namespace PhalconExt\Cli;
4
5
use Ahc\Cli\ArgvParser;
6
use Phalcon\Cli\Task;
0 ignored issues
show
Bug introduced by
The type Phalcon\Cli\Task was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Phalcon\DiInterface;
0 ignored issues
show
Bug introduced by
The type Phalcon\DiInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use PhalconExt\Di\ProvidesDi;
9
10
trait Extension
11
{
12
    use ProvidesDi;
13
14
    /** @var ArgvParser[] Registered tasks */
15
    protected $tasks = [];
16
17
    protected $argv = [];
18
19
    protected $name;
20
21
    protected $version = '0.0.1';
22
23
    public function __construct(DiInterface $di, string $name, string $version = '0.0.1')
24
    {
25
        parent::__construct($di);
26
27
        $di->setShared('application', $this);
28
        $di->setShared('console', $this);
29
30
        $this->name    = $name;
31
        $this->version = $version;
32
    }
33
34
    public function handle(array $argv = null)
35
    {
36
        $this->argv = $argv ?? $_SERVER['argv'];
37
38
        $this->bindEvents();
39
40
        $parameters   = $this->getTaskParameters($this->argv);
41
        $this->taskId = $parameters['task'] . ':' . $parameters['action'];
0 ignored issues
show
Bug Best Practice introduced by
The property taskId does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
42
43
        parent::handle($parameters);
44
    }
45
46
    public function addTask(string $task, string $descr = '', bool $allowUnknown = false): ArgvParser
47
    {
48
        $taskId = \str_ireplace(['task', 'action'], '', $task);
49
50
        if (isset($this->tasks[$taskId])) {
51
            throw new \InvalidArgumentException(
52
                \sprintf('The task "%s" is already registered', $taskId)
53
            );
54
        }
55
56
        return $this->tasks[$taskId] = $this->newTask($taskId, $descr, $allowUnknown);
57
    }
58
59
    protected function getTaskParameters(array $argv)
60
    {
61
        $taskAction = [];
62
        foreach (\array_slice($argv, 1) as $i => $value) {
63
            if ($value[0] === '-') {
64
                break;
65
            }
66
            if (!isset($taskAction[1])) {
67
                $task = \str_ireplace(['task', 'action'], '', $value);
68
                unset($argv[$i]);
69
70
                $taskAction = \explode(':', $task, 2);
71
            }
72
        }
73
74
        // Respect phalcon default.
75
        $taskAction += ['main', 'main'];
76
77
        return [
78
            'task'   => $taskAction[0],
79
            'action' => $taskAction[1],
80
            // For BC, still send params to handle()
81
            'params' => \array_values($argv),
82
        ];
83
    }
84
85
    protected function newTask(string $taskId, string $descr = '', bool $allowUnknown = false)
86
    {
87
        $task = new ArgvParser($taskId, $descr, $allowUnknown);
88
89
        return $task->version($this->version)->onExit(function () {
90
            return false;
91
        });
92
    }
93
94
    protected function bindEvents()
95
    {
96
        $evm = $this->di('eventsManager');
97
98
        $evm->attach('dispatch', $this);
99
        $this->setEventsManager($evm);
0 ignored issues
show
Bug introduced by
It seems like setEventsManager() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

99
        $this->/** @scrutinizer ignore-call */ 
100
               setEventsManager($evm);
Loading history...
100
101
        $this->di('dispatcher')->setEventsManager($evm);
102
    }
103
104
    public function beforeExecuteRoute()
105
    {
106
        if ($this->isGlobalHelp()) {
107
            return $this->globalHelp();
108
        }
109
110
        $parser = isset($this->tasks[$this->taskId])
111
            ? $this->tasks[$this->taskId]
112
            // Allow unknown as it is not explicitly defined with $cli->addTask()
113
            : $this->newTask($this->taskId, '', true);
114
115
        if ($this->isHelp()) {
116
            return $parser->emit('help');
117
        }
118
119
        $parser->parse($this->argv);
120
121
        $this->di()->setShared('argv', $parser);
122
123
        return true;
124
    }
125
126
    protected function isGlobalHelp(): bool
127
    {
128
        // For a specific help, it would be [cmd, task, action, --help]
129
        // If it is just [cmd, --help] then we deduce it is global help!
130
131
        $isGlobal = \substr($this->argv[1] ?? '-', 0, 1) === '-'
132
            && \substr($this->argv[2] ?? '-', 0, 1) === '-';
133
134
        return $isGlobal && $this->isHelp();
135
    }
136
137
    protected function isHelp(): bool
138
    {
139
        return \array_search('--help', $this->argv) || \array_search('-h', $this->argv);
140
    }
141
142
    protected function globalHelp()
143
    {
144
        $this->loadAllTasks();
145
146
        ($w = $this->di('cliWriter'))
147
            ->bold("{$this->name}, version {$this->version}", true)->eol()
148
            ->boldGreen('Commands:', true);
149
150
        $commands = [];
151
        foreach ($this->tasks as $task) {
152
            $commands[$task->getName()] = $task->getDesc();
153
        }
154
155
        $maxLen = \max(\array_map('strlen', \array_keys($commands)));
156
157
        foreach ($commands as $name => $desc) {
158
            $w->bold('  ' . \str_pad($name, $maxLen + 2))->comment($desc, true);
159
        }
160
161
        $w->eol()->yellow('Run `<command> --help` for specific help', true);
162
163
        return false;
164
    }
165
166
    protected function loadAllTasks()
167
    {
168
        if ($tasks = $this->di('config')->path('console.tasks')) {
169
            $classes = $tasks->toArray();
170
        } elseif ($this->di()->has('loader')) {
171
            $classes = \array_keys($this->di('loader')->getClasses());
172
        }
173
174
        foreach ($classes as $class) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $classes does not seem to be defined for all execution paths leading up to this point.
Loading history...
175
            if (\substr($class, -4) === 'Task') {
176
                // Force load!
177
                $this->di->resolve($class);
178
            }
179
        }
180
    }
181
}
182