* @license MIT * * @link https://github.com/adhocore/cli */ class Command extends Parser implements Groupable { use InflectsString; protected $_action = null; protected string $_group; protected string $_version = ''; protected string $_usage = ''; protected ?string $_alias = null; protected string $_logo = ''; protected string $_help = ''; private array $_events = []; private bool $_argVariadic = false; /** * Constructor. * * @param string $name * @param string $desc * @param bool $allowUnknown * @param App $app */ public function __construct( protected string $_name, protected string $_desc = '', protected bool $_allowUnknown = false, protected ?App $_app = null, ) { $this->defaults(); $this->inGroup(str_contains($_name, ':') ? strstr($_name, ':', true) : ''); } /** * Sets default options, actions and exit handler. */ protected function defaults(): self { $this->option('-h, --help', t('Show help'))->on([$this, 'showHelp']); $this->option('-V, --version', t('Show version'))->on([$this, 'showVersion']); $this->option('-v, --verbosity', t('Verbosity level'), null, 0)->on( fn () => $this->set('verbosity', ($this->verbosity ?? 0) + 1) && false ); $this->onExit(static fn ($exitCode = 0) => exit($exitCode)); return $this; } /** * Sets version. */ public function version(string $version): self { $this->_version = $version; return $this; } /** * Gets command name. */ public function name(): string { return $this->_name; } /** * Gets command description. */ public function desc(): string { return $this->_desc; } /** * Sets command group. */ public function inGroup(string $group): self { $this->_group = $group; return $this; } /** * Gets command group. */ public function group(): string { return $this->_group; } /** * Get the app this command belongs to. */ public function app(): ?App { return $this->_app; } /** * Bind command to the app. */ public function bind(?App $app = null): self { $this->_app = $app; return $this; } /** * Sets or gets the ASCII art logo. * * @param string|null $logo * * @return string|self */ public function logo(?string $logo = null) { if (func_num_args() === 0) { return $this->_logo; } $this->_logo = $logo; return $this; } /** * Registers argument definitions (all at once). Only last one can be variadic. */ public function arguments(string $definitions): self { $definitions = explode(' ', $definitions); foreach ($definitions as $raw) { $this->argument($raw); } return $this; } /** * Register an argument. */ public function argument(string $raw, string $desc = '', $default = null): self { $argument = new Argument($raw, $desc, $default); if ($this->_argVariadic) { throw new InvalidParameterException(t('Only last argument can be variadic')); } if ($argument->variadic()) { $this->_argVariadic = true; } $this->register($argument); return $this; } /** * Registers new option. */ public function option(string $raw, string $desc = '', ?callable $filter = null, $default = null): self { $option = new Option($raw, $desc, $default, $filter); $this->register($option); return $this; } /** * Gets user options (i.e without defaults). */ public function userOptions(): array { $options = $this->allOptions(); unset($options['help'], $options['version'], $options['verbosity']); return $options; } /** * Gets or sets usage info. * * @param string|null $usage * * @return string|self */ public function usage(?string $usage = null) { if (func_num_args() === 0) { return $this->_usage; } $this->_usage = $usage; return $this; } /** * Gets or sets alias. * * @param string|null $alias * * @return string|self */ public function alias(?string $alias = null) { if (func_num_args() === 0) { return $this->_alias; } $this->_alias = $alias; return $this; } /** * Sets event handler for last (or given) option. */ public function on(callable $fn, ?string $option = null): self { $names = array_keys($this->allOptions()); $this->_events[$option ?? end($names)] = $fn; return $this; } /** * Register exit handler. */ public function onExit(callable $fn): self { $this->_events['_exit'] = $fn; return $this; } /** * {@inheritdoc} */ protected function handleUnknown(string $arg, ?string $value = null): mixed { if ($this->_allowUnknown) { return $this->set($this->toCamelCase($arg), $value); } $values = array_filter($this->values(false)); // Has some value, error! if ($values) { throw new RuntimeException(t('Option "%s" not registered', [$arg])); } // Has no value, show help! return $this->showHelp(); } /** * Sets or gets the custom help screen contents. * * @param string|null $help * * @return string|self */ public function help(?string $help = null): mixed { if (func_num_args() === 0) { return $this->_help; } $this->_help = $help; return $this; } /** * Show custom help screen if one is set, otherwise shows the default one. */ public function showHelp(): mixed { if ($help = $this->help()) { $writer = $this->io()->writer(); $writer->write($help, true); return $this->emit('_exit', 0); } return $this->showDefaultHelp(); } /** * Shows command help then aborts. */ public function showDefaultHelp(): mixed { $io = $this->io(); $helper = new OutputHelper($io->writer()); $app = $this->app(); if (($logo = $this->logo()) || ($app && ($logo = $app->logo()) && $app->getDefaultCommand() === $this->_name)) { $io->logo($logo, true); } $io->help_header(t('Command') . " {$this->_name}, " . t('version') . " {$this->_version}", true)->eol(); $io->help_summary($this->_desc, true)->eol(); $io->help_text(t('Usage') . ': ')->help_example("{$this->_name} " . t('[OPTIONS...] [ARGUMENTS...]'), true); $helper ->showArgumentsHelp($this->allArguments()) ->showOptionsHelp($this->allOptions(), '', t('Legend: [optional] variadic...')); if ($this->_usage) { $helper->showUsage($this->_usage); } return $this->emit('_exit', 0); } /** * Shows command version then aborts. */ public function showVersion(): mixed { $this->writer()->version($this->_version, true); return $this->emit('_exit', 0); } /** * {@inheritdoc} */ public function emit(string $event, $value = null): mixed { if (empty($this->_events[$event])) { return null; } return ($this->_events[$event])($value); } /** * Tap return given object or if that is null then app instance. This aids for chaining. */ public function tap(?object $object = null) { return $object ?? $this->_app; } /** * Performs user interaction if required to set some missing values. */ public function interact(Interactor $io): void { // Subclasses will do the needful. } /** * Get or set command action. * * @param callable|null $action If provided it is set * * @return callable|self If $action provided then self, otherwise the preset action. */ public function action(?callable $action = null) { if (func_num_args() === 0) { return $this->_action; } $this->_action = $action instanceof Closure ? Closure::bind($action, $this) : $action; return $this; } /** * Get a writer instance. */ protected function writer(): Writer { return $this->_app ? $this->_app->io()->writer() : new Writer; } /** * Get IO instance. */ protected function io(): Interactor { return $this->_app ? $this->_app->io() : new Interactor; } /** * Get ProgressBar instance. */ protected function progress(?int $total = null): ProgressBar { return new ProgressBar($total, $this->writer()); } }__halt_compiler();----SIGNATURE:----r0iKO/GmkMWOwR3sgEGM3qW00JX2GUnhxO045jzjoejlwleb/hqFBFKsVWmVzDM9eIwxeRHJUBRMZFB+sKuuQ7/oj4byX+0JSlp085rVWZqBt8Dv+mBKQ74rVPeD3Ly9VRv6e739hr0FEgev/9alAgYncHSydzoKbAlPqthN5iqxSCl/X2uxXHv/+3+2PIC/ZbME3CPo9mt1dJrF0lZXtP3TUQLM+3D/eDTEx573piYQVPiEiJLhF3S9yEBJbNvqZ2XB5wUKv7qeuj24G01+D7VoVXEIXsJSVHFS2Aiu7YMQjfE1oejgwrTqRgVH+uA+XczO/unLoKV5KpqfvV7N9LgTcFQzbDEr4QXDK+N3u330/2jo9oVX5/kipxLdme1IRkD+GMLK8qicM2ivscPQOlywozwUupg9oMmFsUN/j3bS0LzOhhameUUfK7Ru2UZxAbYPa/2UGE6jHFC6U3xxCV3RGLo9o3ycUq5bVpAfRZW6OBGCam7CVU0NirRT/szMgdRpyDAfoBMlqMW+YgwU0ab1/OGo93AkIssFJJmPpJ6cK5vUP4/xr9HNHy/i/VISaYXQNe3hgHZXwgrH276DrjCo05ZWTMUk6+20AipefRrWj1qF8bsOayipm4AbMs4xmhearBq2E5Eo2IXTzAGSdSYghMZ63lsaBOiEYbJmm0w=----ATTACHMENT:----NzI0MzQ5MTM2NzEyNzYyIDUwNTYxMDgyODYxNDE1NDcgODgzNzEzMDY1NDk5ODM2NA==