1111 */
1212namespace Hyperf \Command ;
1313
14- use Hyperf \Contract \Arrayable ;
1514use Hyperf \Coroutine \Coroutine ;
16- use Hyperf \Stringable \Str ;
1715use Psr \EventDispatcher \EventDispatcherInterface ;
1816use Swoole \ExitException ;
1917use Symfony \Component \Console \Command \Command as SymfonyCommand ;
20- use Symfony \Component \Console \Formatter \OutputFormatterStyle ;
21- use Symfony \Component \Console \Helper \Table ;
22- use Symfony \Component \Console \Helper \TableStyle ;
2318use Symfony \Component \Console \Input \ArrayInput ;
2419use Symfony \Component \Console \Input \InputInterface ;
2520use Symfony \Component \Console \Output \OutputInterface ;
26- use Symfony \Component \Console \Question \ChoiceQuestion ;
27- use Symfony \Component \Console \Question \Question ;
2821use Symfony \Component \Console \Style \SymfonyStyle ;
2922use Throwable ;
3023
3629abstract class Command extends SymfonyCommand
3730{
3831 use DisableEventDispatcher;
32+ use Concerns \InteractsWithIO;
33+ use Concerns \HasParameters;
3934
4035 /**
4136 * The name of the command.
4237 */
4338 protected ?string $ name = null ;
4439
45- protected string $ description = '' ;
46-
47- protected ?InputInterface $ input = null ;
48-
4940 /**
50- * @var null|SymfonyStyle
41+ * The description of the command.
5142 */
52- protected ?OutputInterface $ output = null ;
53-
54- /**
55- * The default verbosity of output commands.
56- */
57- protected int $ verbosity = OutputInterface::VERBOSITY_NORMAL ;
43+ protected string $ description = '' ;
5844
5945 /**
6046 * Execution in a coroutine environment.
6147 */
6248 protected bool $ coroutine = true ;
6349
50+ /**
51+ * The eventDispatcher.
52+ */
6453 protected ?EventDispatcherInterface $ eventDispatcher = null ;
6554
55+ /**
56+ * The hookFlags of the command.
57+ */
6658 protected int $ hookFlags = -1 ;
6759
6860 /**
6961 * The name and signature of the command.
7062 */
7163 protected ?string $ signature = null ;
7264
73- /**
74- * The mapping between human-readable verbosity levels and Symfony's OutputInterface.
75- */
76- protected array $ verbosityMap
77- = [
78- 'v ' => OutputInterface::VERBOSITY_VERBOSE ,
79- 'vv ' => OutputInterface::VERBOSITY_VERY_VERBOSE ,
80- 'vvv ' => OutputInterface::VERBOSITY_DEBUG ,
81- 'quiet ' => OutputInterface::VERBOSITY_QUIET ,
82- 'normal ' => OutputInterface::VERBOSITY_NORMAL ,
83- ];
84-
8565 /**
8666 * The exit code of the command.
8767 */
@@ -101,208 +81,25 @@ public function __construct(string $name = null)
10181 parent ::__construct ($ this ->name );
10282 }
10383
104- ! empty ($ this ->description ) && $ this ->setDescription ($ this ->description );
105-
10684 $ this ->addDisableDispatcherOption ();
107- }
108-
109- /**
110- * Run the console command.
111- */
112- public function run (InputInterface $ input , OutputInterface $ output ): int
113- {
114- $ this ->output = new SymfonyStyle ($ input , $ output );
115-
116- return parent ::run ($ this ->input = $ input , $ this ->output );
117- }
118-
119- /**
120- * Confirm a question with the user.
121- */
122- public function confirm (string $ question , bool $ default = false ): bool
123- {
124- return $ this ->output ->confirm ($ question , $ default );
125- }
126-
127- /**
128- * Prompt the user for input.
129- */
130- public function ask (string $ question , string $ default = null )
131- {
132- return $ this ->output ->ask ($ question , $ default );
133- }
134-
135- /**
136- * Prompt the user for input with auto-completion.
137- *
138- * @param null|bool|float|int|string $default
139- */
140- public function anticipate (string $ question , array $ choices , $ default = null )
141- {
142- return $ this ->askWithCompletion ($ question , $ choices , $ default );
143- }
144-
145- /**
146- * Prompt the user for input with auto-completion.
147- *
148- * @param null|bool|float|int|string $default
149- */
150- public function askWithCompletion (string $ question , array $ choices , $ default = null )
151- {
152- $ question = new Question ($ question , $ default );
153-
154- $ question ->setAutocompleterValues ($ choices );
155-
156- return $ this ->output ->askQuestion ($ question );
157- }
158-
159- /**
160- * Prompt the user for input but hide the answer from the console.
161- */
162- public function secret (string $ question , bool $ fallback = true )
163- {
164- $ question = new Question ($ question );
165-
166- $ question ->setHidden (true )->setHiddenFallback ($ fallback );
167-
168- return $ this ->output ->askQuestion ($ question );
169- }
170-
171- /**
172- * Give the user a multiple choice from an array of answers.
173- * @param mixed $default
174- */
175- public function choiceMultiple (
176- string $ question ,
177- array $ choices ,
178- $ default = null ,
179- ?int $ attempts = null
180- ): array {
181- $ question = new ChoiceQuestion ($ question , $ choices , $ default );
182-
183- $ question ->setMaxAttempts ($ attempts )->setMultiselect (true );
184-
185- return $ this ->output ->askQuestion ($ question );
186- }
187-
188- /**
189- * Give the user a single choice from an array of answers.
190- *
191- * @param mixed $default
192- */
193- public function choice (
194- string $ question ,
195- array $ choices ,
196- $ default = null ,
197- ?int $ attempts = null
198- ): mixed {
199- return $ this ->choiceMultiple ($ question , $ choices , $ default , $ attempts )[0 ];
200- }
201-
202- /**
203- * Format input to textual table.
204- */
205- public function table (array $ headers , array |Arrayable $ rows , TableStyle |string $ tableStyle = 'default ' , array $ columnStyles = []): void
206- {
207- $ table = new Table ($ this ->output );
20885
209- if ($ rows instanceof Arrayable ) {
210- $ rows = $ rows -> toArray ( );
86+ if (! empty ( $ this -> description ) ) {
87+ $ this -> setDescription ( $ this -> description );
21188 }
21289
213- $ table ->setHeaders ($ headers )->setRows ($ rows )->setStyle ($ tableStyle );
214-
215- foreach ($ columnStyles as $ columnIndex => $ columnStyle ) {
216- $ table ->setColumnStyle ($ columnIndex , $ columnStyle );
90+ if (! isset ($ this ->signature )) {
91+ $ this ->specifyParameters ();
21792 }
218-
219- $ table ->render ();
220- }
221-
222- /**
223- * Write a string as standard output.
224- *
225- * @param mixed $string
226- * @param null|mixed $style
227- * @param null|mixed $verbosity
228- */
229- public function line ($ string , $ style = null , $ verbosity = null )
230- {
231- $ styled = $ style ? "< {$ style }> {$ string }</ {$ style }> " : $ string ;
232- $ this ->output ->writeln ($ styled , $ this ->parseVerbosity ($ verbosity ));
233- }
234-
235- /**
236- * Write a string as information output.
237- *
238- * @param mixed $string
239- * @param null|mixed $verbosity
240- */
241- public function info ($ string , $ verbosity = null )
242- {
243- $ this ->line ($ string , 'info ' , $ verbosity );
244- }
245-
246- /**
247- * Write a string as comment output.
248- *
249- * @param mixed $string
250- * @param null|mixed $verbosity
251- */
252- public function comment ($ string , $ verbosity = null )
253- {
254- $ this ->line ($ string , 'comment ' , $ verbosity );
255- }
256-
257- /**
258- * Write a string as question output.
259- *
260- * @param mixed $string
261- * @param null|mixed $verbosity
262- */
263- public function question ($ string , $ verbosity = null )
264- {
265- $ this ->line ($ string , 'question ' , $ verbosity );
26693 }
26794
26895 /**
269- * Write a string as error output.
270- *
271- * @param mixed $string
272- * @param null|mixed $verbosity
273- */
274- public function error ($ string , $ verbosity = null )
275- {
276- $ this ->line ($ string , 'error ' , $ verbosity );
277- }
278-
279- /**
280- * Write a string as warning output.
281- *
282- * @param mixed $string
283- * @param null|mixed $verbosity
96+ * Run the console command.
28497 */
285- public function warn ( $ string , $ verbosity = null )
98+ public function run ( InputInterface $ input , OutputInterface $ output ): int
28699 {
287- if (! $ this ->output ->getFormatter ()->hasStyle ('warning ' )) {
288- $ style = new OutputFormatterStyle ('yellow ' );
289- $ this ->output ->getFormatter ()->setStyle ('warning ' , $ style );
290- }
291- $ this ->line ($ string , 'warning ' , $ verbosity );
292- }
100+ $ this ->output = new SymfonyStyle ($ input , $ output );
293101
294- /**
295- * Write a string in an alert box.
296- *
297- * @param mixed $string
298- */
299- public function alert ($ string )
300- {
301- $ length = Str::length (strip_tags ($ string )) + 12 ;
302- $ this ->comment (str_repeat ('* ' , $ length ));
303- $ this ->comment ('* ' . $ string . ' * ' );
304- $ this ->comment (str_repeat ('* ' , $ length ));
305- $ this ->output ->newLine ();
102+ return parent ::run ($ this ->input = $ input , $ this ->output );
306103 }
307104
308105 /**
@@ -315,36 +112,6 @@ public function call(string $command, array $arguments = []): int
315112 return $ this ->getApplication ()->find ($ command )->run ($ this ->createInputFromArguments ($ arguments ), $ this ->output );
316113 }
317114
318- /**
319- * Handle the current command.
320- */
321- abstract public function handle ();
322-
323- /**
324- * Set the verbosity level.
325- *
326- * @param mixed $level
327- */
328- protected function setVerbosity ($ level )
329- {
330- $ this ->verbosity = $ this ->parseVerbosity ($ level );
331- }
332-
333- /**
334- * Get the verbosity level in terms of Symfony's OutputInterface level.
335- *
336- * @param null|mixed $level
337- */
338- protected function parseVerbosity ($ level = null ): int
339- {
340- if (isset ($ this ->verbosityMap [$ level ])) {
341- $ level = $ this ->verbosityMap [$ level ];
342- } elseif (! is_int ($ level )) {
343- $ level = $ this ->verbosity ;
344- }
345- return $ level ;
346- }
347-
348115 /**
349116 * Create an input instance from the given arguments.
350117 */
@@ -373,27 +140,6 @@ protected function context(): array
373140 })->all ();
374141 }
375142
376- /**
377- * Specify the arguments and options on the command.
378- */
379- protected function specifyParameters (): void
380- {
381- // We will loop through all the arguments and options for the command and
382- // set them all on the base command instance. This specifies what can get
383- // past into these commands as "parameters" to control the execution.
384- if (method_exists ($ this , 'getArguments ' )) {
385- foreach ($ this ->getArguments () ?? [] as $ arguments ) {
386- call_user_func_array ([$ this , 'addArgument ' ], $ arguments );
387- }
388- }
389-
390- if (method_exists ($ this , 'getOptions ' )) {
391- foreach ($ this ->getOptions () ?? [] as $ options ) {
392- call_user_func_array ([$ this , 'addOption ' ], $ options );
393- }
394- }
395- }
396-
397143 /**
398144 * Configure the console command using a fluent definition.
399145 */
@@ -413,19 +159,17 @@ protected function configureUsingFluentDefinition()
413159 protected function configure ()
414160 {
415161 parent ::configure ();
416- if (! isset ($ this ->signature )) {
417- $ this ->specifyParameters ();
418- }
419162 }
420163
421164 protected function execute (InputInterface $ input , OutputInterface $ output )
422165 {
423166 $ this ->disableDispatcher ($ input );
167+ $ method = method_exists ($ this , 'handle ' ) ? 'handle ' : '__invoke ' ;
424168
425- $ callback = function () {
169+ $ callback = function () use ( $ method ) {
426170 try {
427171 $ this ->eventDispatcher ?->dispatch(new Event \BeforeHandle ($ this ));
428- $ this ->handle ();
172+ $ this ->{ $ method } ();
429173 $ this ->eventDispatcher ?->dispatch(new Event \AfterHandle ($ this ));
430174 } catch (Throwable $ exception ) {
431175 if (class_exists (ExitException::class) && $ exception instanceof ExitException) {
0 commit comments