Completed
Push — interactive-mode ( 898eaf )
by Craig
02:13
created

CLImate::confirm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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\Dynamic\Checkboxes;
9
use League\CLImate\TerminalObject\Dynamic\Confirm;
10
use League\CLImate\TerminalObject\Dynamic\Input;
11
use League\CLImate\TerminalObject\Dynamic\Password;
12
use League\CLImate\TerminalObject\Dynamic\Radio;
13
use League\CLImate\TerminalObject\Dynamic\Spinner;
14
use League\CLImate\TerminalObject\Router\Router;
15
use League\CLImate\Util\Helper;
16
use League\CLImate\Util\Output;
17
use League\CLImate\Util\Reader\ReaderInterface;
18
use League\CLImate\Util\Reader\Stdin;
19
use League\CLImate\Util\UtilFactory;
20
21
/**
22
 * @method CLImate black(string $str = null)
23
 * @method CLImate red(string $str = null)
24
 * @method CLImate green(string $str = null)
25
 * @method CLImate yellow(string $str = null)
26
 * @method CLImate blue(string $str = null)
27
 * @method CLImate magenta(string $str = null)
28
 * @method CLImate cyan(string $str = null)
29
 * @method CLImate lightGray(string $str = null)
30
 * @method CLImate darkGray(string $str = null)
31
 * @method CLImate lightRed(string $str = null)
32
 * @method CLImate lightGreen(string $str = null)
33
 * @method CLImate lightYellow(string $str = null)
34
 * @method CLImate lightBlue(string $str = null)
35
 * @method CLImate lightMagenta(string $str = null)
36
 * @method CLImate lightCyan(string $str = null)
37
 * @method CLImate white(string $str = null)
38
 *
39
 * @method CLImate backgroundBlack(string $str = null)
40
 * @method CLImate backgroundRed(string $str = null)
41
 * @method CLImate backgroundGreen(string $str = null)
42
 * @method CLImate backgroundYellow(string $str = null)
43
 * @method CLImate backgroundBlue(string $str = null)
44
 * @method CLImate backgroundMagenta(string $str = null)
45
 * @method CLImate backgroundCyan(string $str = null)
46
 * @method CLImate backgroundLightGray(string $str = null)
47
 * @method CLImate backgroundDarkGray(string $str = null)
48
 * @method CLImate backgroundLightRed(string $str = null)
49
 * @method CLImate backgroundLightGreen(string $str = null)
50
 * @method CLImate backgroundLightYellow(string $str = null)
51
 * @method CLImate backgroundLightBlue(string $str = null)
52
 * @method CLImate backgroundLightMagenta(string $str = null)
53
 * @method CLImate backgroundLightCyan(string $str = null)
54
 * @method CLImate backgroundWhite(string $str = null)
55
 *
56
 * @method CLImate bold(string $str = null)
57
 * @method CLImate dim(string $str = null)
58
 * @method CLImate underline(string $str = null)
59
 * @method CLImate blink(string $str = null)
60
 * @method CLImate invert(string $str = null)
61
 * @method CLImate hidden(string $str = null)
62
 *
63
 * @method CLImate info(string $str = null)
64
 * @method CLImate comment(string $str = null)
65
 * @method CLImate whisper(string $str = null)
66
 * @method CLImate shout(string $str = null)
67
 * @method CLImate error(string $str = null)
68
 *
69
 * @method mixed out(string $str)
70
 * @method mixed inline(string $str)
71
 * @method mixed table(array $data)
72
 * @method mixed json(mixed $var)
73
 * @method mixed br($count = 1)
74
 * @method mixed tab($count = 1)
75
 * @method mixed draw(string $art)
76
 * @method mixed border(string $char = null, integer $length = null)
77
 * @method mixed dump(mixed $var)
78
 * @method mixed flank(string $output, string $char = null, integer $length = null)
79
 * @method mixed progress(integer $total = null)
80
 * @method Spinner spinner(string $label = null, string ...$characters = null)
81
 * @method mixed padding(integer $length = 0, string $char = '.')
82
 * @method mixed animation(string $art, TerminalObject\Helper\Sleeper $sleeper = null)
83
 * @method mixed columns(array $data, $column_count = null)
84
 * @method mixed clear()
85
 * @method CLImate clearLine()
86
 *
87
 * @method CLImate addArt(string $dir)
88
 */
89
class CLImate
90
{
91
    /**
92
     * An instance of the Style class
93
     *
94
     * @var \League\CLImate\Decorator\Style $style
95
     */
96
    public $style;
97
98
    /**
99
     * An instance of the Terminal Object Router class
100
     *
101
     * @var \League\CLImate\TerminalObject\Router\Router $router
102
     */
103
    protected $router;
104
105
    /**
106
     * An instance of the Settings Manager class
107
     *
108
     * @var \League\CLImate\Settings\Manager $settings
109
     */
110
    protected $settings;
111
112
    /**
113
     * An instance of the Argument Manager class
114
     *
115
     * @var \League\CLImate\Argument\Manager $arguments
116
     */
117
    public $arguments;
118
119
    /**
120
     * An instance of the Output class
121
     *
122
     * @var \League\CLImate\Util\Output $output
123
     */
124
    public $output;
125
126
    /**
127
     * An instance of the Util Factory
128
     *
129
     * @var \League\CLImate\Util\UtilFactory $util
130
     */
131
    protected $util;
132
133
    /** @var ReaderInterface */
134
    private $reader;
135
136
    public function __construct()
137
    {
138
        $this->setStyle(new Style());
139
        $this->setRouter(new Router());
140
        $this->setSettingsManager(new SettingsManager());
141
        $this->setOutput(new Output());
142
        $this->setUtil(new UtilFactory());
143
        $this->setArgumentManager(new ArgumentManager());
144
        $this->setReader(new Stdin());
145
    }
146
147
    /**
148
     * Set the style property
149
     *
150
     * @param \League\CLImate\Decorator\Style $style
151
     */
152
    public function setStyle(Style $style)
153
    {
154
        $this->style = $style;
155
    }
156
157
    /**
158
     * Set the router property
159
     *
160
     * @param \League\CLImate\TerminalObject\Router\Router $router
161
     */
162
    public function setRouter(Router $router)
163
    {
164
        $this->router = $router;
165
    }
166
167
    /**
168
     * Set the settings property
169
     *
170
     * @param \League\CLImate\Settings\Manager $manager
171
     */
172
    public function setSettingsManager(SettingsManager $manager)
173
    {
174
        $this->settings = $manager;
175
    }
176
177
    /**
178
     * Set the arguments property
179
     *
180
     * @param \League\CLImate\Argument\Manager $manager
181
     */
182
    public function setArgumentManager(ArgumentManager $manager)
183
    {
184
        $this->arguments = $manager;
185
    }
186
187
    /**
188
     * Set the output property
189
     *
190
     * @param \League\CLImate\Util\Output $output
191
     */
192
    public function setOutput(Output $output)
193
    {
194
        $this->output = $output;
195
    }
196
197
    /**
198
     * Set the util property
199
     *
200
     * @param \League\CLImate\Util\UtilFactory $util
201
     */
202
    public function setUtil(UtilFactory $util)
203
    {
204
        $this->util = $util;
205
    }
206
207
    /**
208
     * @param ReaderInterface $reader
209
     *
210
     * @return void
211
     */
212
    public function setReader(ReaderInterface $reader): void
213
    {
214
        $this->reader = $reader;
215
    }
216
217
    /**
218
     * @param bool $interactive
219
     *
220
     * @return self
221
     */
222
    public function setInteractive(bool $interactive): self
223
    {
224
        $this->reader->setInteractive($interactive);
225
    }
226
227
    /**
228
     * Extend CLImate with custom methods
229
     *
230
     * @param string|object|array $class
231
     * @param string $key Optional custom key instead of class name
232
     *
233
     * @return \League\CLImate\CLImate
234
     */
235
    public function extend($class, $key = null)
236
    {
237
        $this->router->addExtension($key, $class);
0 ignored issues
show
Bug introduced by
It seems like $class defined by parameter $class on line 235 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...
238
239
        return $this;
240
    }
241
242
    /**
243
     * Force ansi support on
244
     *
245
     * @return \League\CLImate\CLImate
246
     */
247
    public function forceAnsiOn()
248
    {
249
        $this->util->system->forceAnsi();
250
251
        return $this;
252
    }
253
254
    /**
255
     * Force ansi support off
256
     *
257
     * @return \League\CLImate\CLImate
258
     */
259
    public function forceAnsiOff()
260
    {
261
        $this->util->system->forceAnsi(false);
262
263
        return $this;
264
    }
265
266
    /**
267
     * Write line to writer once
268
     *
269
     * @param string|array $writer
270
     *
271
     * @return \League\CLImate\CLImate
272
     */
273
    public function to($writer)
274
    {
275
        $this->output->once($writer);
276
277
        return $this;
278
    }
279
280
    /**
281
     * Output the program's usage statement
282
     *
283
     * @param array $argv
284
     */
285
    public function usage(array $argv = null)
286
    {
287
        return $this->arguments->usage($this, $argv);
288
    }
289
290
    /**
291
     * Set the program's description
292
     *
293
     * @param string $description
294
     *
295
     * @return \League\CLImate\CLImate
296
     */
297
    public function description($description)
298
    {
299
        $this->arguments->description($description);
300
301
        return $this;
302
    }
303
304
    /**
305
     * Check if we have valid output
306
     *
307
     * @param  mixed   $output
308
     *
309
     * @return boolean
310
     */
311
    protected function hasOutput($output)
312
    {
313
        if (!empty($output)) {
314
            return true;
315
        }
316
317
        // Check for type first to avoid errors with objects/arrays/etc
318
        return ((is_string($output) || is_numeric($output)) && strlen($output) > 0);
319
    }
320
321
    /**
322
     * Search for the method within the string
323
     * and route it if we find one.
324
     *
325
     * @param  string $method
326
     * @param  string $name
327
     *
328
     * @return string The new string without the executed method.
329
     */
330
    protected function parseStyleMethod($method, $name)
331
    {
332
        // If the name starts with this method string...
333
        if (substr($name, 0, strlen($method)) == $method) {
334
            // ...remove the method name from the beginning of the string...
335
            $name = substr($name, strlen($method));
336
337
            // ...and trim off any of those underscores hanging around
338
            $name = ltrim($name, '_');
339
340
            $this->style->set($method);
341
        }
342
343
        return $name;
344
    }
345
346
    /**
347
     * Search for any style methods within the name and apply them
348
     *
349
     * @param  string $name
350
     * @param  array $method_search
351
     *
352
     * @return string Anything left over after applying styles
353
     */
354
    protected function applyStyleMethods($name, $method_search = null)
355
    {
356
        // Get all of the possible style attributes
357
        $method_search = $method_search ?: array_keys($this->style->all());
358
359
        $new_name = $this->searchForStyleMethods($name, $method_search);
360
361
        // While we still have a name left and we keep finding methods,
362
        // loop through the possibilities
363
        if (strlen($new_name) > 0 && $new_name != $name) {
364
            return $this->applyStyleMethods($new_name, $method_search);
365
        }
366
367
        return $new_name;
368
    }
369
370
    /**
371
     * Search for style methods in the current name
372
     *
373
     * @param string $name
374
     * @param array $search
375
     * @return string
376
     */
377
    protected function searchForStyleMethods($name, $search)
378
    {
379
        // Loop through the possible methods
380
        foreach ($search as $method) {
381
            // See if we found a valid method
382
            $name = $this->parseStyleMethod($method, $name);
383
        }
384
385
        return $name;
386
    }
387
388
    /**
389
     * Build up the terminal object and return it
390
     *
391
     * @param string $name
392
     * @param array $arguments
393
     *
394
     * @return object|null
395
     */
396
    protected function buildTerminalObject($name, $arguments)
397
    {
398
        // Retrieve the parser for the current set of styles
399
        $parser = $this->style->parser($this->util->system);
400
401
        // Reset the styles
402
        $this->style->reset();
403
404
        // Execute the terminal object
405
        $this->router->settings($this->settings);
406
        $this->router->parser($parser);
407
        $this->router->output($this->output);
408
        $this->router->util($this->util);
409
410
        return $this->router->execute($name, $arguments);
411
    }
412
413
    /**
414
     * Route anything leftover after styles were applied
415
     *
416
     * @param string $name
417
     * @param array $arguments
418
     *
419
     * @return object|null
420
     */
421
    protected function routeRemainingMethod($name, array $arguments)
422
    {
423
        // If we still have something left, let's figure out what it is
424
        if ($this->router->exists($name)) {
425
            $obj = $this->buildTerminalObject($name, $arguments);
426
427
            // If something was returned, return it
428
            if (is_object($obj)) {
429
                return $obj;
430
            }
431
        } elseif ($this->settings->exists($name)) {
432
            $this->settings->add($name, reset($arguments));
433
        // Handle passthroughs to the arguments manager.
434
        } else {
435
            // If we can't find it at this point, let's fail gracefully
436
            $this->out(reset($arguments));
437
        }
438
    }
439
440
    /**
441
     * Magic method for anything called that doesn't exist
442
     *
443
     * @param string $requested_method
444
     * @param array  $arguments
445
     *
446
     * @return \League\CLImate\CLImate|\League\CLImate\TerminalObject\Dynamic\DynamicTerminalObject
447
     *
448
     * List of many of the possible method being called here
449
     * documented at the top of this class.
450
     */
451
    public function __call($requested_method, $arguments)
452
    {
453
        // Apply any style methods that we can find first
454
        $name = $this->applyStyleMethods(Helper::snakeCase($requested_method));
455
456
        // The first argument is the string|array|object we want to echo out
457
        $output = reset($arguments);
458
459
        if (strlen($name)) {
460
            // If we have something left, let's try and route it to the appropriate place
461
            if ($result = $this->routeRemainingMethod($name, $arguments)) {
462
                return $result;
463
            }
464
        } elseif ($this->hasOutput($output)) {
465
            // If we have fulfilled all of the requested methods and we have output, output it
466
            $this->out($output);
467
        }
468
469
        return $this;
470
    }
471
472
473
    /**
474
     * Request some input from the user.
475
     *
476
     * @param string $prompt
477
     *
478
     * @return Input
479
     */
480
    public function input(string $prompt): Input
481
    {
482
        return $this->buildTerminalObject("input", [$prompt, $this->reader]);
483
    }
484
485
486
    /**
487
     * Ask the user to confirm something.
488
     *
489
     * @param string $prompt
490
     *
491
     * @return Confirm
492
     */
493
    public function confirm(string $prompt): Confirm
494
    {
495
        return $this->buildTerminalObject("confirm", [$prompt, $this->reader]);
496
    }
497
498
499
    /**
500
     * Ask the user to input some sensitive content.
501
     *
502
     * @param string $prompt
503
     *
504
     * @return Password
505
     */
506
    public function password(string $prompt): Password
507
    {
508
        return $this->buildTerminalObject("password", [$prompt, $this->reader]);
509
    }
510
511
512
    /**
513
     * Ask the user to choose some checkboxes.
514
     *
515
     * @param string $prompt
516
     * @param array $options
517
     *
518
     * @return Checkboxes
519
     */
520
    public function checkboxes(string $prompt, array $options): Checkboxes
521
    {
522
        return $this->buildTerminalObject("checkboxes", [$prompt, $options, $this->reader]);
523
    }
524
525
526
    /**
527
     * Ask the user to choose an option.
528
     *
529
     * @param string $prompt
530
     * @param array $options
531
     *
532
     * @return Radio
533
     */
534
    public function radio(string $prompt, array $options): Radio
535
    {
536
        return $this->buildTerminalObject("radio", [$prompt, $options, $this->reader]);
537
    }
538
}
539