Cli::newLine()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Console;
24
25
use Exception;
26
use Syscodes\Collections\Arr;
27
use Syscodes\Core\Http\Exceptions\LenevorException;
28
29
/**
30
 * Set of static methods useful for CLI request handling.
31
 * 
32
 * @author Alexander Campo <[email protected]>
33
 */
34
class Cli
35
{
36
	/**
37
 	 * Background color identifier.
38
 	 *
39
 	 * @var array $backgroundColors
40
 	 */
41
 	protected static $backgroundColors = [
42
 		'black'      => '40',
43
 		'red'        => '41',
44
 		'green'      => '42',
45
 		'yellow'     => '43',
46
 		'blue'       => '44',
47
 		'magenta'    => '45',
48
 		'cyan'       => '46',
49
 		'light_gray' => '47'
50
 	];
51
52
	/**
53
	 * Foreground color identifier.
54
 	 *
55
 	 * @var array $foregroundColors
56
	 */
57
	protected static $foregroundColors = [
58
		'black'         => '0;30',
59
		'dark_gray'     => '1;30',
60
		'blue'          => '0;34',
61
		'dark_blue'     => '1;34',
62
		'light_blue'    => '1;34',
63
		'green'         => '0;32',
64
		'light_green'   => '1;32',
65
		'cyan'          => '0;36', 
66
		'light_cyan'    => '1;36',
67
		'red'           => '0;31',
68
		'light_red'     => '1;31',
69
		'purple'        => '0;35',
70
		'light_purple'  => '1;35',
71
		'light_yellow'  => '0;33',
72
		'yellow'        => '1;33',
73
		'light_gray'    => '0;37',
74
		'white'         => '1;37'
75
 	];
76
77
	/**
78
	 * Indicates that you do not use any color for foreground or background.
79
	 *
80
	 * @var bool $noColor
81
	 */
82
	public static $noColor = false;
83
84
	/**
85
	 * String of arguments to be used in console.
86
	 *
87
	 * @var array $options
88
	 */
89
	protected static $options = [];
90
91
	/**
92
	 * Readline Support for command line.
93
	 *
94
	 * @var bool $readlineSupport
95
	 */
96
	public static $readlineSupport = false;
97
98
	/**
99
	 * List of array segments.
100
	 *
101
	 * @var array $segments
102
	 */
103
	protected static $segments = [];
104
105
 	/**
106
 	 * The standar STDERR is where the application writes its error messages.
107
 	 *
108
 	 * @var string $stderr 
109
 	 */
110
 	protected static $stderr;
111
112
 	/**
113
 	 * The estandar STDOUT is where the application records its output messages.
114
 	 *
115
 	 * @var resource $stdout
116
 	 */
117
 	protected static $stdout;
118
119
 	/**
120
	 * Message that tells the user that he is waiting to receive an order.
121
	 *
122
	 * @var string $waitMsg
123
	 */
124
	public static $waitMsg = 'Press any key to continue...';
125
126
	/**
127
	 * Static constructor. Parses all the CLI params.
128
	 * 
129
	 * @return \Syscodes\Contracts\Core\Lenevor  $core
0 ignored issues
show
Bug introduced by
The type Syscodes\Contracts\Core\Lenevor 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...
130
	 * 
131
	 * @throws \Exception
132
	 */
133
 	public static function initialize()
134
 	{
135
 		// Readline is an extension for PHP that makes interactive the command console
136
 		static::$readlineSupport = extension_loaded('readline');
137
138
 		// clear segments & options to keep testing clean
139
 		static::$options  = [];
140
 		static::$segments = [];
141
142
 		static::parseCommandLine();
143
144
 		// Writes its error messages
145
 		static::$stderr = STDERR;
146
147
 		// Records its output messages
148
 		static::$stdout = STDOUT;
149
 	}
150
151
 	/**
152
 	 * Beeps a certain number of times.
153
	 *
154
	 * @param  int  $num  The number of times to beep
155
	 *
156
 	 * @return int
157
 	 */
158
 	public static function bell(int $num = 1)
159
 	{
160
 		echo str_repeat("\x07", $num);
161
 	}
162
163
 	/**
164
 	 * Clears the screen of output.
165
 	 *
166
 	 * @return void
167
 	 */
168
 	public static function clearScreen()
169
 	{
170
 		static::isWindows()
171
 			// Windows doesn't work for this, but their terminal is tiny so shove this in
172
 			? static::newLine(40)
173
 			// Anything with a flair of Unix will handle these magic characters
174
 			: fwrite(static::$stdout, chr(27)."[H".chr(27)."[2J");
175
 	}
176
177
 	/**
178
 	 * Returns the given text with the correct color codes for a foreground and
179
	 * optionally a background color.
180
 	 *
181
 	 * @param  string  $text  The text to color
182
 	 * @param  string  $foreground  The foreground color
183
 	 * @param  string  $background  The background color
184
 	 * @param  string  $format  Other formatting to apply. Currently only 'underline' is understood
185
 	 *
186
 	 * @return string  The color coded string
187
 	 *
188
 	 * @throws \Syscodes\Core\Exceptions\LenevorException
189
 	 */
190
 	public static function color(string $text, string $foreground, string $background = null, string $format = null)
191
 	{
192
 		if (static::$noColor)
193
 		{
194
 			return $text;
195
 		}
196
197
 		if ( ! Arr::exists(static::$foregroundColors, $foreground)) {
198
 			throw new LenevorException(static::error("Invalid CLI foreground color: {$foreground}."));
199
 		}
200
201
 		if ( $background !== null && ! Arr::exists(static::$backgroundColors, $background)) {
202
 			throw new LenevorException(static::error("Invalid CLI background color: {$background}."));
203
 		}
204
205
 		$string = "\033[".static::$foregroundColors[$foreground]."m";
206
207
 		if ($background !== null) {
208
 			$string .= "\033[".static::$backgroundColors[$background]."m";
209
 		}
210
211
 		if ($format === 'underline') {
212
 			$string .= "\033[4m";
213
 		}
214
215
 		$string .= $text."\033[0m";
216
217
 		return $string;
218
 	}
219
220
 	/**
221
 	 * Get the number of characters in a string.
222
 	 *
223
 	 * @param  string  $string
224
 	 *
225
 	 * @return int
226
 	 */
227
 	public static function strlen(?string $string)
228
 	{
229
 		if (is_null($string)) {
230
 			return 0;
231
 		}
232
233
 		foreach (static::$foregroundColors as $color) {
234
 			$string = strtr($string, ["\033[".$color.'m' => '']);
235
 		}
236
237
 		foreach (static::$backgroundColors as $color) {
238
 			$string = strtr($string, ["\033[".$color.'m' => '']);
239
 		}
240
241
 		$string = strtr($string, ["\033[4m" => '', "\033[0m" => '']);
242
243
 		return mb_strlen($string);
244
 	}
245
246
 	/**
247
 	 * Outputs an error to the CLI using STDERR instead of STDOUT.
248
 	 *
249
 	 * @param  string|array  $text  The text to output, or array of errors
250
 	 * @param  string  $foreground  The foreground color
251
 	 * @param  string|null  $background  the background color
252
 	 *
253
 	 * @return string
254
 	 */
255
 	public static function error(string $text = '', string $foreground = 'light_red', string $background = null)
256
 	{
257
		if (is_array($text)) {
0 ignored issues
show
introduced by
The condition is_array($text) is always false.
Loading history...
258
			$text = implode(PHP_EOL, $text);
259
		}
260
		
261
		if ($foreground || $background) {
262
			$text = static::color($text, $foreground, $background);
263
		}
264
		
265
		static::fwrite(static::$stderr, $text.PHP_EOL);
0 ignored issues
show
Bug introduced by
static::stderr of type string is incompatible with the type resource expected by parameter $handle of Syscodes\Console\Cli::fwrite(). ( Ignorable by Annotation )

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

265
		static::fwrite(/** @scrutinizer ignore-type */ static::$stderr, $text.PHP_EOL);
Loading history...
266
	}
267
268
	/**
269
	 * Attempts to determine the width of the viewable CLI window.
270
	 *
271
	 * @param  int  $default
272
	 *
273
	 * @return int
274
	 */
275
	public static function getWidth(int $default = 80)
276
	{
277
		if (static::isWindows() || (int) shell_exec('tput cols') === 0) {
278
			return $default;
279
		}
280
281
		return (int) shell_exec('tput cols');
282
	}
283
284
	/**
285
	 * Attempts to determine the height of the viewable CLI window.
286
	 *
287
	 * @param  int  $default
288
	 *
289
	 * @return int
290
	 */
291
	public static function getHeight(int $default = 32)
292
	{
293
		if (static::isWindows()) {
294
			return $default;
295
		}
296
297
		return (int) shell_exec('tput lines');
298
	}
299
300
	/**
301
	 * Takes a string and writes it to the command line, wrapping to a maximum width. 
302
	 * If no maximum width is specified, will wrap to the window's max.
303
	 *
304
	 * @param  string  $string
305
	 * @param  int  $max
306
	 * @param  int $padLeft
307
	 *
308
	 * @return string
309
	 */
310
	public static function wrap(string $string = null, int $max = 0, int $padLeft = 0)
311
	{
312
		if (empty($string)) {
313
			return '';
314
		}
315
316
		if ($max === 0) {
317
			$max = static::getWidth();
318
		}
319
320
		if (static::getWidth() < $max) {
321
			$max = static::getWidth();
322
		}
323
324
		$max = $max - $padLeft;
325
326
		$lines = wordwrap($string, $max);
327
328
		if ($pad_left > 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pad_left does not exist. Did you maybe mean $padLeft?
Loading history...
329
			$lines = explode(PHP_EOL, $lines);
330
331
			$first = true;
332
333
			array_walk ($lines, function (&$line, $index) use ($pad_left, &$first) {
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed. ( Ignorable by Annotation )

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

333
			array_walk ($lines, function (&$line, /** @scrutinizer ignore-unused */ $index) use ($pad_left, &$first) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
334
				if ( ! $first) {
335
					$line = str_repeat(' ', $pad_left) . $line;
336
				} else {
337
					$first = false;
338
				}
339
			});
340
341
			$lines = implode(PHP_EOL, $lines);
342
		}
343
344
		return $lines;
345
	}
346
347
 	/**
348
 	 * Get input from the shell, using readline or the standard STDIN.
349
 	 *
350
 	 * @param  string|int  $prefix  The name of the option (int if unnamed)
351
 	 *
352
 	 * @return string
353
 	 */
354
 	public static function input($prefix = '')
355
 	{
356
 		if (static::$readlineSupport) {
357
 			return readline($prefix);
358
 		}
359
360
 		echo $prefix;
361
362
 		return fgets(STDIN);
363
 	}
364
365
 	/**
366
 	 * If operating system === windows.
367
 	 * 
368
 	 * @return string
369
 	 */
370
 	public static function isWindows()
371
 	{
372
 		return stripos(PHP_OS, 'WIN') === 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return stripos(Syscodes\...le\PHP_OS, 'WIN') === 0 returns the type boolean which is incompatible with the documented return type string.
Loading history...
373
 	}
374
375
 	/**
376
 	 * Enter a number of empty lines.
377
 	 * 
378
 	 * @param  int  $num  Number of lines to output
379
 	 *
380
 	 * @return void
381
 	 */
382
 	public static function newLine(int $num = 1)
383
 	{
384
 		for ($i = 0; $i < $num; $i++) {			
385
 			static::write();
386
 		}
387
 	}
388
389
 	/**
390
	 * Returns the option with the given name. You can also give the option number.
391
	 *
392
	 * @param  string|int  $name  The name of the option (int if unnamed)
393
	 * @param  mixed  $default  The value to return if the option is not defined
394
	 *
395
	 * @return mixed
396
	 * 
397
	 * @uses   \Syscodes\Contract\Core\Lenevor
398
	 */
399
 	public static function option($name, $default = null)
400
 	{
401
 		if ( ! isset(static::$options[$name])) {
402
 			return Lenevor::value($default);
0 ignored issues
show
Bug introduced by
The type Syscodes\Console\Lenevor 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...
403
 		}
404
405
 		return static::$options[$name];
406
	}
407
408
	/**
409
	 * Parses the command line it was called from and collects all
410
	 * options and valid segments.
411
	 * 
412
	 * @return bool
413
	 */
414
	protected static function parseCommandLine()
415
	{
416
		$options = false;
417
418
		for ($i = 1; $i < $_SERVER['argc']; $i++) {
419
			if ( ! $options && mb_strpos($_SERVER['argv'][$i], '-') === false) {
420
				static::$segments[] = $_SERVER['argv'][$i];
421
422
				continue;
423
			}
424
425
			$options = true;
0 ignored issues
show
Unused Code introduced by
The assignment to $options is dead and can be removed.
Loading history...
426
427
			$args  = str_replace('-', '', $_SERVER['argv'][$i]);
428
			$value = null;
429
430
			if (isset($_SERVER['argv'][$i + 1]) && mb_strpos($_SERVER['argv'][$i + 1], '-') !== 0) {
431
				$value = $_SERVER['argv'][$i + 1];
432
				$i++;
433
			}
434
435
			static::$options[$args] = $value;
436
437
			$options = false;
438
		}
439
	}
440
441
	/**
442
	 * Returns the command line string portions of the arguments, minus
443
	 * any options, as a string.
444
	 *
445
	 * @return string
446
	 */
447
	public static function getURI()
448
	{
449
		return implode('/', static::$segments);
450
	}
451
452
	/**
453
	 * Returns an individual segment.
454
	 *
455
	 * @param  int  $index
456
	 * 
457
	 * @return mixed|null
458
	 */
459
	public static function getSegment(int $index)
460
	{
461
		if ( ! isset(static::$segments[$index - 1])) {
462
			return null;
463
		}
464
465
		return static::$segments[$index - 1];
466
	}
467
468
	/**
469
	 * Returns the raw array of segments found.
470
	 *
471
	 * @return array
472
	 */
473
	public static function getSegments()
474
	{
475
		return static::$segments;
476
	}
477
478
 	/**
479
 	 * Asks the user for input.  This can have either 1 or 2 arguments.
480
	 *
481
	 * Usage:
482
	 *
483
	 * // Waits for any key press
484
	 * Cli::prompt();
485
	 *
486
	 * // Takes any input
487
	 * $color = Cli::prompt('What is your favorite color?');
488
	 *
489
	 * // Takes any input, but offers default
490
	 * $color = Cli::prompt('What is your favourite color?', 'white');
491
	 *
492
	 * // Will only accept the options in the array
493
	 * $ready = Cli::prompt('Are you ready?', array('y','n'));
494
	 *
495
	 * @return string The user input
496
	 */
497
 	public static function prompt()
498
 	{
499
 		$args = func_get_args();
500
501
		$options = [];
502
		$output  = '';
503
		$default = null;
504
505
		// How many we got
506
		$arg_count = count($args);
507
508
		// Is the last argument a boolean? True means required
509
		$required = end($args) === true;
510
511
		// Reduce the argument count if required was passed, we don't care about that anymore
512
		$required === true and --$arg_count;
513
514
		// This method can take a few crazy combinations of arguments, so lets work it out
515
		switch ($arg_count) {
516
			case 2:
517
518
				// E.g: $ready = Cli::prompt('Are you ready?', ['y','n']);
519
				if (is_array($args[1])) {
520
					list($output, $options) = $args;
521
				}
522
				// E.g: $color = Cli::prompt('What is your favourite color?', 'white');
523
				elseif (is_string($args[1])) {
524
					list($output, $default) = $args;
525
				}
526
527
			break;
528
529
			case 1:
530
531
				// No question (probably been asked already) so just show options
532
				// E.g: $ready = Cli::prompt(array('y','n'));
533
				if (is_array($args[0])) {
534
					$options = $args[0];
535
				}
536
				// Question without options
537
				// E.g: $ready = Cli::prompt('What did you do today?');
538
				elseif (is_string($args[0])) {
539
					$output = $args[0];
540
				}
541
542
			break;
543
		}
544
545
		// If a question has been asked with the read
546
		if ($output !== '') {
547
			$extra_output = '';
548
549
			if ($default !== null) {
0 ignored issues
show
introduced by
The condition $default !== null is always false.
Loading history...
550
				$extra_output = ' [ Default: "'.$default.'" ]';
551
			} elseif ($options !== []) {
552
				$extra_output = ' [ '.implode(' | ', $options).' ]';
553
			}
554
555
			static::fwrite(static::$stdout, $output.$extra_output.': ');
556
		}
557
558
		// Read the input from keyboard.
559
		$input = trim(static::input()) ?: $default;
560
561
		// No input provided and we require one (default will stop this being called)
562
		if (empty($input) and $required === true) {
563
			static::write('This is required.');
564
			static::newLine();
565
566
			$input = forward_static_call_array([__CLASS__, 'prompt'], $args);
567
		}
568
569
		// If options are provided and the choice is not in the array, tell them to try again
570
		if ( ! empty($options) and ! in_array($input, $options)) {
571
			static::write('This is not a valid option. Please try again.');
572
			static::newLine();
573
574
			$input = forward_static_call_array([__CLASS__, 'prompt'], $args);
575
		}
576
577
		return $input;
578
 	}
579
580
 	/**
581
 	 * Allows you to set a commandline option from code.
582
 	 *
583
 	 * @param  string|int  $name  The name of the option (int if unnamed)
584
	 * @param  mixed|null  $value  The value to set, or null to delete the option
585
	 *
586
	 * @return mixed
587
	 */
588
 	public static function setOption($name, $value = null)
589
 	{
590
 		if ($value == null) {
591
 			if (isset(static::$options[$name])) {
592
 				unset(static::$options[$name]);
593
 			}
594
 		} else {
595
 			static::$options[$name] = $value;
596
 		}
597
 	}
598
599
 	/**
600
 	 * Waits a certain number of seconds, optionally showing a wait message and
601
	 * waiting for a key press.
602
 	 *
603
 	 * @param  int  $seconds  Number of seconds
604
 	 * @param  bool  $countdown  Show a countdown or not
605
 	 *
606
 	 * @return string
607
 	 */
608
 	public static function wait(int $seconds = 0, bool $countdown = false)
609
 	{
610
 		if ($countdown === true) {
611
			$time = $seconds;
612
613
 			while ($time > 0) {
614
 				fwrite(static::$stdout, $time.'... ');
615
 				sleep(1);
616
 				$time--;
617
 			}
618
619
 			static::write();
620
 		} else {
621
 			if ($seconds = 0) {
622
 				sleep($seconds);
623
 			} else {
624
 				static::write(static::$waitMsg);
625
 				static::input();
626
 			}
627
 		}
628
 	}
629
630
 	/**
631
 	 * Outputs a string to the cli.	If you send an array it will implode them 
632
 	 * with a line break.
633
 	 * 
634
 	 * @param  string|array  $text  The text to output, or array of lines
635
 	 * @param  string|null  $foreground  The foreground color
636
 	 * @param  string|null  $background  The background color
637
 	 *
638
 	 * @return string
639
 	 */
640
 	public static function write(string $text = '', string $foreground = null, string $background = null)
641
 	{
642
 		if (is_array($text)) {
0 ignored issues
show
introduced by
The condition is_array($text) is always false.
Loading history...
643
 			$text = implode(PHP_EOL, $text);
644
 		}
645
646
 		if ($foreground OR $background) {
647
 			$text = static::color($text, $foreground, $background);
0 ignored issues
show
Bug introduced by
It seems like $foreground can also be of type null; however, parameter $foreground of Syscodes\Console\Cli::color() does only seem to accept string, 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

647
 			$text = static::color($text, /** @scrutinizer ignore-type */ $foreground, $background);
Loading history...
648
 		}
649
650
 		static::fwrite(static::$stdout, $text.PHP_EOL);
651
 	}
652
653
 	/**
654
 	 * Returns a well formatted table.
655
 	 *
656
 	 * @param  array  $tbody  List of rows
657
 	 * @param  array  $thead  List of columns
658
 	 *
659
 	 * @return void
660
 	 */
661
 	public static function table(array $tbody, array $thead = [])
662
 	{
663
 		$rows = [];
664
665
 		if ( ! empty($thead)) {
666
 			$rows[] = array_values($thead);
667
 		}
668
669
 		foreach ($tbody as $tr) {
670
 			$rows[] = count($rows);
671
 		}
672
673
 		$totalRows = count($rows);
674
675
 		// Store all columns lengths
676
 		$allColsLengths = [];
677
678
 		// Store maximum lengths by column
679
 		$maxColsLengths = [];
680
681
 		for ($row = 0; $row < $totalRows; $row++) {
682
 			$column = 0;
683
684
 			foreach ($rows[$row] as $col) {
685
 				$allColsLengths[$row][$column] = static::strlen($col);
686
687
 				if ( ! isset($maxColsLengths[$column]) || $allColsLengths[$row][$column] > $maxColsLengths[$column]) {
688
 					$maxColsLengths[$column] = $allColsLengths[$row][$column];
689
 				}
690
691
 				$column++;
692
 			}
693
 		}
694
695
 		for ($row = 0; $row < $totalRows; $row++) {
696
 			$column = 0;
697
698
 			foreach ($rows[$row] as $col)
699
 			{
700
 				$diverse = $maxColsLengths[$column] - static::strlen($col);
701
 				
702
 				if ($diverse) {
703
 					$rows[$row][$column] = $rows[$row][$column].str_repeat(' ', $diverse);
704
 				}
705
706
 				$column++;
707
 			} 			
708
 		}
709
710
 		$table = '';
711
		$cols  = '';
712
713
 		for ($row = 0; $row < $rows; $row++) {
714
 			if (0 === $row) {
715
 				$cols = '+';
716
717
 				foreach ($rows[$row] as $col) {
718
 					$cols .= str_repeat('-', static::strlen($col) + 2).'+';
719
 				}
720
721
 				$table .= $cols.PHP_EOL;
722
 			}
723
724
 			$table .= '| '.implode('-', $rows[$row]).' |'.PHP_EOL;
725
726
 			if (0 === $row && ( ! empty($thead)) || ($row + 1) === $rows) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (0 === $row && ! empty($...) || $row + 1 === $rows, Probably Intended Meaning: 0 === $row && (! empty($... || $row + 1 === $rows)
Loading history...
727
 				$table .= $cols.PHP_EOL;
728
 			}
729
 		}
730
731
 		static::write($table);
732
 	}
733
734
	/**
735
	 * The library is intended for used on Cli commanda, 
736
	 * this commands can be called from controllers and 
737
	 * elsewhere of framework.
738
	 * 
739
	 * @param  resource  $handle
740
	 * @param  string  $text
741
	 * 
742
	 * @return string
743
	 */
744
	protected static function fwrite($handle, string $text)
745
	{
746
		if (isCli()) {
747
			fwrite($handle, $text);
748
			return;
749
		}
750
751
		echo $text;
752
	}
753
}