@@ -39,6 +39,19 @@ abstract class Controller extends AbstractCommand implements ControllerInterface
3939 /** @var bool */
4040 private $ standAlone = false ;
4141
42+ /**
43+ * @param string $command
44+ * @return int
45+ */
46+ public function run ($ command = '' )
47+ {
48+ if (!$ this ->action = trim ($ command )) {
49+ return $ this ->showHelp ();
50+ }
51+
52+ return parent ::run ($ command );
53+ }
54+
4255 /**
4356 * load command configure
4457 */
@@ -76,7 +89,23 @@ protected function execute($input, $output)
7689 } else {
7790 $ status = -1 ;
7891 $ this ->output ->liteError ("Sorry, the console controller command [ $ action] not exist! " );
79- $ this ->showCommandList ();
92+
93+ // find similar command names by similar_text()
94+ $ similares = [];
95+
96+ foreach ($ this ->getAllCommandMethods () as $ cmd => $ refM ) {
97+ similar_text ($ action , $ cmd , $ percent );
98+
99+ if (45 <= (int )$ percent ) {
100+ $ similares [] = $ cmd ;
101+ }
102+ }
103+
104+ if ($ similares ) {
105+ $ this ->write (sprintf ('Maybe what you mean is: <info>%s</info> ' , implode (', ' , $ similares )));
106+ } else {
107+ $ this ->showCommandList ();
108+ }
80109 }
81110
82111 return $ status ;
@@ -119,6 +148,7 @@ final public function helpCommand()
119148 $ action = Helper::camelCase ($ action );
120149 $ method = $ this ->actionSuffix ? $ action . ucfirst ($ this ->actionSuffix ) : $ action ;
121150
151+ // show help info for a command.
122152 return $ this ->showHelpByMethodAnnotation ($ method , $ action );
123153 }
124154
@@ -134,31 +164,12 @@ final protected function showCommandList()
134164 $ classDes = Annotation::description ($ ref ->getDocComment ()) ?: 'No Description for the console controller ' ;
135165 }
136166
137- $ suffix = $ this ->actionSuffix ;
138- $ suffixLen = Helper::strLen ($ suffix );
139-
140167 $ commands = [];
141- foreach ($ ref -> getMethods ( ) as $ m ) {
142- $ mName = $ m ->getName ( );
168+ foreach ($ this -> getAllCommandMethods ( $ ref ) as $ cmd => $ m ) {
169+ $ desc = Annotation:: firstLine ( $ m ->getDocComment () );
143170
144- if ($ m ->isPublic () && substr ($ mName , -$ suffixLen ) === $ suffix ) {
145- $ desc = Annotation::firstLine ($ m ->getDocComment ());
146- $ length = strlen ($ this ->actionSuffix );
147- $ cmd = '' ;
148-
149- if ($ length ) {
150- if (substr ($ mName , -$ length ) === $ this ->actionSuffix ) {
151- $ cmd = substr ($ mName , 0 , -$ length );
152- }
153-
154- } else {
155- $ cmd = $ mName ;
156- }
157-
158- if ($ cmd ) {
159- //$this->write(" <info>$cmd</info> $desc");
160- $ commands [$ cmd ] = $ desc ;
161- }
171+ if ($ cmd ) {
172+ $ commands [$ cmd ] = $ desc ;
162173 }
163174 }
164175
@@ -198,6 +209,29 @@ final protected function showCommandList()
198209 ));
199210 }
200211
212+ /**
213+ * @param \ReflectionClass|null $ref
214+ * @return \Generator
215+ */
216+ protected function getAllCommandMethods (\ReflectionClass $ ref = null )
217+ {
218+ $ ref = $ ref ?: new \ReflectionObject ($ this );
219+
220+ $ suffix = $ this ->actionSuffix ;
221+ $ suffixLen = Helper::strLen ($ suffix );
222+
223+ foreach ($ ref ->getMethods () as $ m ) {
224+ $ mName = $ m ->getName ();
225+
226+ if ($ m ->isPublic () && substr ($ mName , - $ suffixLen ) === $ suffix ) {
227+ // suffix is empty ?
228+ $ cmd = $ suffix ? substr ($ mName , 0 , -$ suffixLen ) : $ mName ;
229+
230+ yield $ cmd => $ m ;
231+ }
232+ }
233+ }
234+
201235 /**************************************************************************
202236 * getter/setter methods
203237 **************************************************************************/
0 commit comments