Passed
Push — master ( 567a82...0a2149 )
by Timm
01:53
created

Cmd::fillOptionCollection()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
c 0
b 0
f 0
dl 0
loc 20
rs 8.8333
eloc 12
nc 9
nop 3
ccs 12
cts 12
cp 1
crap 7
1
<?php
2
3
4
namespace Stefaminator\Cli;
5
6
7
use Exception;
8
use GetOptionKit\OptionCollection;
9
use GetOptionKit\OptionResult;
10
11
abstract class Cmd {
12
13
    /**
14
     * @var Cmd
15
     */
16
    public $parent;
17
18
    /**
19
     * @var Cmd[]
20
     */
21
    public $children = [];
22
23
    /**
24
     * @var string
25
     */
26
    public $cmd;
27
28
    /**
29
     * @var string
30
     */
31
    private $description = '';
32
33
    /**
34
     * @var array
35
     */
36
    private $argSpecs = [];
37
38
    /**
39
     * @var string[]
40
     */
41
    public $arguments = [];
42
43
    /**
44
     * @var array
45
     */
46
    public $optSpecs = [];
47
48
    /**
49
     * @var OptionCollection
50
     */
51
    private $optionCollection;
52
53
    /**
54
     * @var OptionResult|null
55
     */
56
    public $optionResult;
57
58
    /**
59
     * @var Exception
60
     */
61
    public $optionParseException;
62
63
64
    /**
65
     * The constructor.
66
     * @param string|null $cmd
67
     */
68 22
    public function __construct(string $cmd = null) {
69 22
        $this->cmd = $cmd;
70 22
        $this->init();
71 22
    }
72
73
74 4
    public function runHelp(): void {
75 4
        (new Help($this))->run();
76 4
    }
77
78
    /**
79
     * Run the cmd
80
     */
81
    abstract public function init(): void;
82
83
    /**
84
     * Run the cmd
85
     */
86
    abstract public function run(): void;
87
88
    /**
89
     * Overwrite this method for extended help
90
     */
91 3
    public function help(): void {
92
93 3
    }
94
95 2
    public function description(): string {
96 2
        return $this->description;
97
    }
98
99 1
    public function arguments(): array {
100 1
        return $this->arguments;
101
    }
102
103 5
    public function argSpecs(): array {
104 5
        return $this->argSpecs;
105
    }
106
107 22
    public function optionCollection(): OptionCollection {
108
109 22
        if ($this->optionCollection !== null) {
110 4
            return $this->optionCollection;
111
        }
112
113 22
        $specs = (array)$this->optSpecs;
114
115 22
        $collection = new OptionCollection();
116
117 22
        foreach ($specs as $k => $v) {
118
            try {
119 22
                $this->fillOptionCollection($collection, $k, $v);
120 6
            } catch (Exception $e) {
121
                // Option Specs seems to be invalid.
122
                // Continue with other options without interruption.
123
            }
124
        }
125
126 22
        $this->optionCollection = $collection;
127 22
        return $this->optionCollection;
128
    }
129
130
    /**
131
     * @param OptionCollection $collection
132
     * @param string $spec
133
     * @param array $config
134
     * @throws Exception
135
     */
136 22
    private function fillOptionCollection(OptionCollection $collection, string $spec, array $config): void {
137
138 22
        $opt = $collection->add($spec, $config['description']??'');
139
140 22
        if (array_key_exists('isa', $config)) {
141 12
            if(array_key_exists('regex', $config) && strtolower($config['isa']) === 'regex') {
142 6
                $opt->isa('regex', $config['regex']);
143
            } else {
144 12
                $opt->isa($config['isa']);
145
            }
146
        }
147
148 22
        if (array_key_exists('default', $config)) {
149 10
            $opt->defaultValue($config['default']);
150 10
            return;
151
        }
152
153 22
        if (array_key_exists('incremental', $config) && $config['incremental'] === true) {
154 6
            $opt->incremental();
155 6
            return;
156
        }
157
158 22
    }
159
160 4
    public function getProvidedOption(string $key) {
161 4
        if ($this->optionResult !== null) {
162 3
            return $this->optionResult->get($key);
163
        }
164 1
        return null;
165
    }
166
167 1
    public function getAllProvidedOptions(): array {
168 1
        $r = [];
169 1
        if ($this->optionResult !== null) {
170 1
            $keys = array_keys($this->optionResult->keys);
171 1
            foreach ($keys as $key) {
172 1
                $r[$key] = $this->getProvidedOption($key);
173
            }
174
        }
175 1
        return $r;
176
    }
177
178
    /**
179
     * @param string $key
180
     * @return bool
181
     */
182 4
    public function hasProvidedOption(string $key): bool {
183 4
        return $this->optionResult !== null && $this->optionResult->has($key);
184
    }
185
186 17
    public function hasChild(string $cmd): bool {
187 17
        return array_key_exists($cmd, $this->children);
188
    }
189
190 17
    public function getChild(string $cmd): ?self {
191 17
        if ($this->hasChild($cmd)) {
192 11
            return $this->children[$cmd];
193
        }
194 8
        return null;
195
    }
196
197 16
    public function addChild(Cmd $runner): self {
198
199 16
        $runner->parent = $this;
200 16
        $this->children[$runner->cmd] = $runner;
201
202 16
        return $this;
203
    }
204
205 16
    protected function setDescription(string $description): self {
206 16
        $this->description = $description;
207 16
        return $this;
208
    }
209
210 22
    protected function addOption(string $specString, array $config): self {
211
212 22
        $this->optSpecs[$specString] = $config;
213
214 22
        return $this;
215
    }
216
217 22
    protected function addArgument(string $specString, array $config): self {
218
219 22
        foreach ($this->argSpecs as $k => $v) {
220 22
            if (array_key_exists('multiple', $v)) {
221 6
                unset($this->argSpecs[$k]['multiple']);
222
            }
223
        }
224
225 22
        $config['index'] = count($this->argSpecs);
226
227 22
        $this->argSpecs[$specString] = $config;
228
229 22
        return $this;
230
    }
231
232
233 6
    public function handleOptionParseException(): bool {
234
235 6
        if ($this->optionParseException === null) {
236 5
            return false;
237
        }
238
239 1
        self::eol();
240 1
        self::echo('Uups, something went wrong!', Color::FOREGROUND_COLOR_RED);
241 1
        self::eol();
242 1
        self::echo($this->optionParseException->getMessage(), Color::FOREGROUND_COLOR_RED);
243 1
        self::eol();
244
245 1
        $this->runHelp();
246
247 1
        return true;
248
    }
249
250
251
    public const EOL = "\n";
252
253
254 6
    public static function eol(): void {
255 6
        echo self::EOL;
256 6
    }
257
258 6
    public static function echo(string $str, ?string $foreground_color = null): void {
259
260 6
        $lines = preg_split("/\r\n|\n|\r/", $str);
261
262 6
        $output = [];
263 6
        foreach ($lines as $line) {
264 6
            if ($foreground_color !== null) {
265 6
                $line = Color::getColoredString($line, $foreground_color);
266
            }
267 6
            $output[] = $line;
268
        }
269
270 6
        echo implode(self::EOL, $output);
271 6
    }
272
273
}