Skip to content

Commit f78ce11

Browse files
Merge pull request #1 from InitPHP/2.0
2.0
2 parents 05b956c + 41e37b4 commit f78ce11

9 files changed

+891
-292
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ composer require initphp/console
1616
```php
1717
#!usr/bin/php
1818
require_once __DIR__ . '/../vendor/autoload.php';
19-
use InitPHP\Console\Console;
19+
use \InitPHP\Console\{Application, Input, Output};
2020

21-
$console = new Console();
21+
$console = new Application("My Console Application", '1.0');
2222

2323
// Register commands ...
2424

2525
// hello -name=John
26-
$console->register('hello', function (Console $console) {
27-
if ($console->has_flag('name')) {
28-
$console->message("Hello {name}", [
29-
'name' => $console->flag('name')
26+
$console->register('hello', function (Input $input, Output $output) {
27+
if ($input->hasArgument('name')) {
28+
$output->writeln('Hello {name}', [
29+
'name' => $input->getArgument('name')
3030
]);
31-
}else{
32-
$console->message('Hello World!');
31+
} else {
32+
$output->writeln('Hello World!');
3333
}
3434
}, 'Says hello.');
3535

src/Application.php

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
<?php
2+
/**
3+
* Application.php
4+
*
5+
* This file is part of Console.
6+
*
7+
* @author Muhammet ŞAFAK <[email protected]>
8+
* @copyright Copyright © 2022 Muhammet ŞAFAK
9+
* @license ./LICENSE MIT
10+
* @version 2.0
11+
* @link https://www.muhammetsafak.com.tr
12+
*/
13+
14+
declare(strict_types=1);
15+
16+
namespace InitPHP\Console;
17+
18+
class Application
19+
{
20+
public const VERSION = '2.0';
21+
22+
/** @var string */
23+
protected $application;
24+
25+
/** @var string */
26+
protected $version;
27+
28+
protected $terminal;
29+
30+
/** @var array */
31+
protected $commands = [];
32+
33+
protected $input;
34+
35+
protected $output;
36+
37+
protected $command;
38+
39+
public function __construct(string $application = 'InitPHP Console Application', string $version = '1.1')
40+
{
41+
$this->application = $application;
42+
$this->version = $version;
43+
}
44+
45+
/**
46+
* @param string $command
47+
* @param callable|null $execute
48+
* @param string $definition
49+
* @return $this
50+
* @throws \InvalidArgumentException
51+
*/
52+
public function register(string $command, callable $execute = null, string $definition = ''): self
53+
{
54+
if ($execute === null) {
55+
if (!\class_exists($command)) {
56+
throw new \InvalidArgumentException("The specified executable does not meet the requirements.");
57+
}
58+
$commandObj = new $command();
59+
if (!($commandObj instanceof Command)) {
60+
throw new \InvalidArgumentException("The specified executable does not meet the requirements.");
61+
}
62+
if (!isset($commandObj->command)) {
63+
throw new \Exception('The Command feature of the command class is undefined.');
64+
}
65+
$command = $commandObj->command;
66+
$execute = $commandObj;
67+
$definition = $commandObj->definition();
68+
$help = $commandObj->help();
69+
if (empty($help)) {
70+
$help = $definition;
71+
}
72+
} else {
73+
$help = $definition;
74+
}
75+
if (!\is_callable($execute) && !($execute instanceof Command)) {
76+
throw new \InvalidArgumentException("The specified executable does not meet the requirements.");
77+
}
78+
$this->commands[$command] = [
79+
'command' => $command,
80+
'execute' => $execute,
81+
'definition' => $definition,
82+
'help' => $help,
83+
];
84+
85+
return $this;
86+
}
87+
88+
public function run(): bool
89+
{
90+
global $argv;
91+
92+
$inputs = $argv;
93+
$this->terminal = $inputs[0];
94+
\array_shift($inputs);
95+
if (empty($inputs)) {
96+
return false;
97+
}
98+
99+
$this->command = \current($inputs);
100+
\array_shift($inputs);
101+
102+
$this->input = new Input($inputs);
103+
$this->output = new Output();
104+
105+
if ($this->command === 'help') {
106+
$this->help($this->input, $this->output);
107+
return true;
108+
}
109+
110+
if (isset($this->commands[$this->command])) {
111+
112+
try {
113+
$command = $this->commands[$this->command];
114+
115+
if ($this->input->hasArgument('help')) {
116+
$this->commandHelp($this->input, $this->output, $command);
117+
return true;
118+
}
119+
$execute = $command['execute'];
120+
121+
if (\is_callable($execute)) {
122+
\call_user_func_array($execute, [$this->input, $this->output]);
123+
return true;
124+
}
125+
126+
if ($execute instanceof Command) {
127+
$arguments = $execute->arguments();
128+
if (!empty($arguments)) {
129+
foreach ($arguments as $argument) {
130+
if ($argument instanceof InputArgument) {
131+
if ($argument->run($this->input, $this->output) === FALSE) {
132+
return false;
133+
}
134+
} else {
135+
$this->output->error("One or more arguments are wrong! Please check that you create arguments from the InputArgument object.");
136+
}
137+
}
138+
}
139+
140+
$execute->execute($this->input, $this->output);
141+
return true;
142+
}
143+
144+
145+
$this->output->error("The command is not executable; Please make sure the command is correctly recorded.");
146+
return false;
147+
} catch (\Throwable $e) {
148+
$this->output->error($e->getMessage());
149+
return false;
150+
}
151+
152+
} else {
153+
$this->output->error("The command was not found.");
154+
}
155+
return true;
156+
}
157+
158+
private function help(Input $input, Output $output)
159+
{
160+
$output->writeln('
161+
____ _ __ ____ __ ______ ______ __ ___ ____
162+
/ _/___ (_) /_/ __ \/ / / / __ \ / ____/___ ____ _________ / /__ |__ \ / __ \
163+
/ // __ \/ / __/ /_/ / /_/ / /_/ / / / / __ \/ __ \/ ___/ __ \/ / _ \__/ / / / / /
164+
_/ // / / / / /_/ ____/ __ / ____/ / /___/ /_/ / / / (__ ) /_/ / / __/ __/_/ /_/ /
165+
/___/_/ /_/_/\__/_/ /_/ /_/_/ \____/\____/_/ /_/____/\____/_/\___/____(_)____/
166+
167+
');
168+
$output->writeln($this->application . ' v' . $this->version);
169+
170+
$groups = [];
171+
$ungroup = [];
172+
foreach ($this->commands as $command) {
173+
if (\strpos($command['command'], ':') === FALSE) {
174+
$ungroup[$command['command']] = !empty($command['definition']) ? $command['definition'] : $command['help'];
175+
continue;
176+
}
177+
$split = \explode(':', $command['command'], 2);
178+
if (!isset($groups[$split[0]])) {
179+
$groups[$split[0]] = [];
180+
}
181+
$groups[$split[0]][$command['command']] = !empty($command['definition']) ? $command['definition'] : $command['help'];
182+
}
183+
184+
$output->writeln('');
185+
$output->writeln('[COMMANDS]', [], [Output::COLOR_RED, Output::BOLD]);
186+
foreach ($groups as $group_name => $group) {
187+
$output->writeln('');
188+
$output->writeln($group_name, [], [Output::COLOR_MAGENTA]);
189+
$output->list($group, 1);
190+
}
191+
$output->writeln('');
192+
$output->list($ungroup);
193+
$output->writeln('');
194+
195+
$output->writeln('Copyright © 2022 - ' . date("Y") . ' InitPHP Console ' . self::VERSION);
196+
$output->writeln('http://initphp.org');
197+
}
198+
199+
private function commandHelp(Input $input, Output $output, array $command)
200+
{
201+
$output->writeln(\PHP_EOL . ($command['help'] ?? $command['definition']));
202+
$exe = $command['execute'];
203+
if ($exe instanceof Command) {
204+
$usageArguments = ['optional' => [], 'required' => []];
205+
if ($arguments = $exe->arguments()) {
206+
$rows = [];
207+
foreach ($arguments as $argument) {
208+
if (!($argument instanceof InputArgument)) {
209+
$output->error("One or more arguments are wrong! Please check that you create arguments from the InputArgument object.");
210+
exit;
211+
}
212+
$rows[$argument->getName()] = $argument->getDefinition();
213+
if ($argument->isOptional()) {
214+
$usageArguments['optional'][] = '[' . \trim($argument->getName() . '=(' . $argument->getType() . ')' . $argument->getDefault()) . ']';
215+
} else {
216+
$usageArguments['required'][] = \trim($argument->getName() . '=(' . $argument->getType() . ')'.$argument->getDefault());
217+
}
218+
}
219+
$output->writeln(\PHP_EOL . "[PARAMETERS]");
220+
$output->list($rows, 1);
221+
}
222+
$usage = "[USAGE]" . \PHP_EOL . "\t";
223+
$usage .= 'php '
224+
. $this->terminal
225+
. ' '
226+
. $exe->command
227+
. ' '
228+
. \implode(' ', $usageArguments['required'])
229+
. ' '
230+
. \implode(' ', $usageArguments['optional']);
231+
$output->writeln(\trim($usage));
232+
}
233+
}
234+
235+
}

src/Command.php

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/**
3+
* Command.php
4+
*
5+
* This file is part of Console.
6+
*
7+
* @author Muhammet ŞAFAK <[email protected]>
8+
* @copyright Copyright © 2022 Muhammet ŞAFAK
9+
* @license ./LICENSE MIT
10+
* @version 2.0
11+
* @link https://www.muhammetsafak.com.tr
12+
*/
13+
14+
declare(strict_types=1);
15+
16+
namespace InitPHP\Console;
17+
18+
abstract class Command
19+
{
20+
21+
/** @var string */
22+
public $command;
23+
24+
abstract public function execute(Input $input, Output $output);
25+
26+
public function help(): string
27+
{
28+
return 'No explanation for this command is specified.';
29+
}
30+
31+
public function definition(): string
32+
{
33+
return '';
34+
}
35+
36+
public function arguments(): array
37+
{
38+
return [];
39+
}
40+
41+
}

0 commit comments

Comments
 (0)