Completed
Push — commands ( 7b5fcb )
by Craig
06:02
created

CLImate::command()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace League\CLImate;
4
5
use League\CLImate\Argument\Manager as ArgumentManager;
6
use League\CLImate\Decorator\Style;
7
use League\CLImate\Settings\Manager as SettingsManager;
8
use League\CLImate\TerminalObject\Router\Router;
9
use League\CLImate\Util\Helper;
10
use League\CLImate\Util\Output;
11
use League\CLImate\Util\UtilFactory;
12
13
/**
14
 * @method mixed black(string $str = null)
15
 * @method mixed red(string $str = null)
16
 * @method mixed green(string $str = null)
17
 * @method mixed yellow(string $str = null)
18
 * @method mixed blue(string $str = null)
19
 * @method mixed magenta(string $str = null)
20
 * @method mixed cyan(string $str = null)
21
 * @method mixed lightGray(string $str = null)
22
 * @method mixed darkGray(string $str = null)
23
 * @method mixed lightRed(string $str = null)
24
 * @method mixed lightGreen(string $str = null)
25
 * @method mixed lightYellow(string $str = null)
26
 * @method mixed lightBlue(string $str = null)
27
 * @method mixed lightMagenta(string $str = null)
28
 * @method mixed lightCyan(string $str = null)
29
 * @method mixed white(string $str = null)
30
 *
31
 * @method mixed backgroundBlack(string $str = null)
32
 * @method mixed backgroundRed(string $str = null)
33
 * @method mixed backgroundGreen(string $str = null)
34
 * @method mixed backgroundYellow(string $str = null)
35
 * @method mixed backgroundBlue(string $str = null)
36
 * @method mixed backgroundMagenta(string $str = null)
37
 * @method mixed backgroundCyan(string $str = null)
38
 * @method mixed backgroundLightGray(string $str = null)
39
 * @method mixed backgroundDarkGray(string $str = null)
40
 * @method mixed backgroundLightRed(string $str = null)
41
 * @method mixed backgroundLightGreen(string $str = null)
42
 * @method mixed backgroundLightYellow(string $str = null)
43
 * @method mixed backgroundLightBlue(string $str = null)
44
 * @method mixed backgroundLightMagenta(string $str = null)
45
 * @method mixed backgroundLightCyan(string $str = null)
46
 * @method mixed backgroundWhite(string $str = null)
47
 *
48
 * @method mixed bold(string $str = null)
49
 * @method mixed dim(string $str = null)
50
 * @method mixed underline(string $str = null)
51
 * @method mixed blink(string $str = null)
52
 * @method mixed invert(string $str = null)
53
 * @method mixed hidden(string $str = null)
54
 *
55
 * @method mixed info(string $str = null)
56
 * @method mixed comment(string $str = null)
57
 * @method mixed whisper(string $str = null)
58
 * @method mixed shout(string $str = null)
59
 * @method mixed error(string $str = null)
60
 *
61
 * @method mixed out(string $str)
62
 * @method mixed inline(string $str)
63
 * @method mixed table(array $data)
64
 * @method mixed json(mixed $var)
65
 * @method mixed br($count = 1)
66
 * @method mixed tab($count = 1)
67
 * @method mixed draw(string $art)
68
 * @method mixed border(string $char = null, integer $length = null)
69
 * @method mixed dump(mixed $var)
70
 * @method mixed flank(string $output, string $char = null, integer $length = null)
71
 * @method mixed progress(integer $total = null)
72
 * @method mixed padding(integer $length = 0, string $char = '.')
73
 * @method mixed input(string $prompt, Util\Reader\ReaderInterface $reader = null)
74
 * @method mixed confirm(string $prompt, Util\Reader\ReaderInterface $reader = null)
75
 * @method mixed password(string $prompt, Util\Reader\ReaderInterface $reader = null)
76
 * @method mixed checkboxes(string $prompt, array $options, Util\Reader\ReaderInterface $reader = null)
77
 * @method mixed radio(string $prompt, array $options, Util\Reader\ReaderInterface $reader = null)
78
 * @method mixed animation(string $art, TerminalObject\Helper\Sleeper $sleeper = null)
79
 * @method mixed columns(array $data, $column_count = null)
80
 * @method mixed clear()
81
 *
82
 * @method CLImate addArt(string $dir)
83
 */
84
class CLImate
85
{
86
    /**
87
     * An instance of the Style class
88
     *
89
     * @var \League\CLImate\Decorator\Style $style
90
     */
91
    public $style;
92
93
    /**
94
     * An instance of the Terminal Object Router class
95
     *
96
     * @var \League\CLImate\TerminalObject\Router\Router $router
97
     */
98
    protected $router;
99
100
    /**
101
     * An instance of the Settings Manager class
102
     *
103
     * @var \League\CLImate\Settings\Manager $settings
104
     */
105
    protected $settings;
106
107
    /**
108
     * An instance of the Argument Manager class
109
     *
110
     * @var \League\CLImate\Argument\Manager $arguments
111
     */
112
    public $arguments;
113
114
    /**
115
     * An instance of the Output class
116
     *
117
     * @var \League\CLImate\Util\Output $output
118
     */
119
    public $output;
120
121
    /**
122
     * An instance of the Util Factory
123
     *
124
     * @var \League\CLImate\Util\UtilFactory $util
125
     */
126
    protected $util;
127
128 944
    public function __construct()
129
    {
130 944
        $this->setStyle(new Style());
131 944
        $this->setRouter(new Router());
132 944
        $this->setSettingsManager(new SettingsManager());
133 944
        $this->setOutput(new Output());
134 944
        $this->setUtil(new UtilFactory());
135 944
        $this->setArgumentManager(new ArgumentManager());
136 944
    }
137
138
    /**
139
     * Set the style property
140
     *
141
     * @param \League\CLImate\Decorator\Style $style
142
     */
143 944
    public function setStyle(Style $style)
144
    {
145 944
        $this->style = $style;
146 944
    }
147
148
    /**
149
     * Set the router property
150
     *
151
     * @param \League\CLImate\TerminalObject\Router\Router $router
152
     */
153 944
    public function setRouter(Router $router)
154
    {
155 944
        $this->router = $router;
156 944
    }
157
158
    /**
159
     * Set the settings property
160
     *
161
     * @param \League\CLImate\Settings\Manager $manager
162
     */
163 944
    public function setSettingsManager(SettingsManager $manager)
164
    {
165 944
        $this->settings = $manager;
166 944
    }
167
168
    /**
169
     * Set the arguments property
170
     *
171
     * @param \League\CLImate\Argument\Manager $manager
172
     */
173 944
    public function setArgumentManager(ArgumentManager $manager)
174
    {
175 944
        $this->arguments = $manager;
176 944
    }
177
178
    /**
179
     * Set the output property
180
     *
181
     * @param \League\CLImate\Util\Output $output
182
     */
183 944
    public function setOutput(Output $output)
184
    {
185 944
        $this->output = $output;
186 944
    }
187
188
    /**
189
     * Set the util property
190
     *
191
     * @param \League\CLImate\Util\UtilFactory $util
192
     */
193 944
    public function setUtil(UtilFactory $util)
194
    {
195 944
        $this->util = $util;
196 944
    }
197
198
    /**
199
     * Extend CLImate with custom methods
200
     *
201
     * @param string|object|array $class
202
     * @param string $key Optional custom key instead of class name
203
     *
204
     * @return \League\CLImate\CLImate
205
     */
206 36
    public function extend($class, $key = null)
207
    {
208 36
        $this->router->addExtension($key, $class);
0 ignored issues
show
Bug introduced by
It seems like $class defined by parameter $class on line 206 can also be of type array or object; however, League\CLImate\TerminalO...\Router::addExtension() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
209
210 28
        return $this;
211
    }
212
213
    /**
214
     * Force ansi support on
215
     *
216
     * @return \League\CLImate\CLImate
217
     */
218 4
    public function forceAnsiOn()
219
    {
220 4
        $this->util->system->forceAnsi();
221
222 4
        return $this;
223
    }
224
225
    /**
226
     * Force ansi support off
227
     *
228
     * @return \League\CLImate\CLImate
229
     */
230 4
    public function forceAnsiOff()
231
    {
232 4
        $this->util->system->forceAnsi(false);
233
234 4
        return $this;
235
    }
236
237
    /**
238
     * Write line to writer once
239
     *
240
     * @param string|array $writer
241
     *
242
     * @return \League\CLImate\CLImate
243
     */
244 4
    public function to($writer)
245
    {
246 4
        $this->output->once($writer);
247
248 4
        return $this;
249
    }
250
251
    /**
252
     * Output the program's usage statement
253
     *
254
     * @param array $argv
255
     */
256 4
    public function usage(array $argv = null)
257
    {
258 4
        return $this->arguments->usage($this, $argv);
259
    }
260
261
    public function command($name)
262
    {
263
        return new Command($name, $this);
264
    }
265
266
    /**
267
     * Set the program's description
268
     *
269
     * @param string $description
270
     *
271
     * @return \League\CLImate\CLImate
272
     */
273 4
    public function description($description)
274
    {
275 4
        $this->arguments->description($description);
276
277 4
        return $this;
278
    }
279
280
    /**
281
     * Check if we have valid output
282
     *
283
     * @param  mixed   $output
284
     *
285
     * @return boolean
286
     */
287 76
    protected function hasOutput($output)
288
    {
289 76
        if (!empty($output)) {
290 48
            return true;
291
        }
292
293
        // Check for type first to avoid errors with objects/arrays/etc
294 40
        return ((is_string($output) || is_numeric($output)) && strlen($output) > 0);
295
    }
296
297
    /**
298
     * Search for the method within the string
299
     * and route it if we find one.
300
     *
301
     * @param  string $method
302
     * @param  string $name
303
     *
304
     * @return string The new string without the executed method.
305
     */
306 564
    protected function parseStyleMethod($method, $name)
307
    {
308
        // If the name starts with this method string...
309 564
        if (substr($name, 0, strlen($method)) == $method) {
310
            // ...remove the method name from the beginning of the string...
311 112
            $name = substr($name, strlen($method));
312
313
            // ...and trim off any of those underscores hanging around
314 112
            $name = ltrim($name, '_');
315
316 112
            $this->style->set($method);
317 112
        }
318
319 564
        return $name;
320
    }
321
322
    /**
323
     * Search for any style methods within the name and apply them
324
     *
325
     * @param  string $name
326
     * @param  array $method_search
327
     *
328
     * @return string Anything left over after applying styles
329
     */
330 564
    protected function applyStyleMethods($name, $method_search = null)
331
    {
332
        // Get all of the possible style attributes
333 564
        $method_search = $method_search ?: array_keys($this->style->all());
334
335 564
        $new_name = $this->searchForStyleMethods($name, $method_search);
336
337
        // While we still have a name left and we keep finding methods,
338
        // loop through the possibilities
339 564
        if (strlen($new_name) > 0 && $new_name != $name) {
340 36
            return $this->applyStyleMethods($new_name, $method_search);
341
        }
342
343 564
        return $new_name;
344
    }
345
346
    /**
347
     * Search for style methods in the current name
348
     *
349
     * @param string $name
350
     * @param array $search
351
     * @return string
352
     */
353 564
    protected function searchForStyleMethods($name, $search)
354
    {
355
        // Loop through the possible methods
356 564
        foreach ($search as $method) {
357
            // See if we found a valid method
358 564
            $name = $this->parseStyleMethod($method, $name);
359 564
        }
360
361 564
        return $name;
362
    }
363
364
    /**
365
     * Build up the terminal object and return it
366
     *
367
     * @param string $name
368
     * @param array $arguments
369
     *
370
     * @return object|null
371
     */
372 564
    protected function buildTerminalObject($name, $arguments)
373
    {
374
        // Retrieve the parser for the current set of styles
375 564
        $parser = $this->style->parser($this->util->system);
376
377
        // Reset the styles
378 564
        $this->style->reset();
379
380
        // Execute the terminal object
381 564
        $this->router->settings($this->settings);
382 564
        $this->router->parser($parser);
383 564
        $this->router->output($this->output);
384 564
        $this->router->util($this->util);
385
386 564
        return $this->router->execute($name, $arguments);
387
    }
388
389
    /**
390
     * Route anything leftover after styles were applied
391
     *
392
     * @param string $name
393
     * @param array $arguments
394
     *
395
     * @return object|null
396
     */
397 564
    protected function routeRemainingMethod($name, array $arguments)
398
    {
399
        // If we still have something left, let's figure out what it is
400 564
        if ($this->router->exists($name)) {
401 564
            $obj = $this->buildTerminalObject($name, $arguments);
402
403
            // If something was returned, return it
404 564
            if (is_object($obj)) {
405 220
                return $obj;
406
            }
407 388
        } elseif ($this->settings->exists($name)) {
408 44
            $this->settings->add($name, reset($arguments));
409
        // Handle passthroughs to the arguments manager.
410 44
        } else {
411
            // If we can't find it at this point, let's fail gracefully
412 4
            $this->out(reset($arguments));
413
        }
414 388
    }
415
416
    /**
417
     * Magic method for anything called that doesn't exist
418
     *
419
     * @param string $requested_method
420
     * @param array  $arguments
421
     *
422
     * @return \League\CLImate\CLImate|\League\CLImate\TerminalObject\Dynamic\DynamicTerminalObject
423
     *
424
     * List of many of the possible method being called here
425
     * documented at the top of this class.
426
     */
427 564
    public function __call($requested_method, $arguments)
428
    {
429
        // Apply any style methods that we can find first
430 564
        $name = $this->applyStyleMethods(Helper::snakeCase($requested_method));
431
432
        // The first argument is the string|array|object we want to echo out
433 564
        $output = reset($arguments);
434
435 564
        if (strlen($name)) {
436
            // If we have something left, let's try and route it to the appropriate place
437 564
            if ($result = $this->routeRemainingMethod($name, $arguments)) {
438 220
                return $result;
439
            }
440 388
        } elseif ($this->hasOutput($output)) {
441
            // If we have fulfilled all of the requested methods and we have output, output it
442 48
            $this->out($output);
443 48
        }
444
445 388
        return $this;
446
    }
447
}
448