@@ -77,24 +77,32 @@ class Application extends StreamAware implements FormatterAware
7777 protected $ commands ;
7878
7979 /**
80- * Name of the default command to be used if none was supplied
80+ * Is this application a Mono-Command Application ?
8181 *
82- * @var string
82+ * @var bool
8383 */
84- protected $ default ;
84+ protected $ mono = false ;
8585
8686 /**
8787 * Application constructor.
8888 *
89- * @param string $name The application name
90- * @param string $version The application version
89+ * @param string $name The application name
90+ * @param string $version The application version
91+ * @param Command|null $main Main command (only for MCA)
9192 */
92- public function __construct ($ name , $ version )
93+ public function __construct ($ name , $ version, Command $ main = null )
9394 {
9495 $ this ->name = $ name ;
9596 $ this ->version = $ version ;
9697 $ this ->formatter = FormatterFactory::create ();
9798
99+ // For Mono-Command Applications, the command can be passed as a 3rd constructor arg
100+ if ($ main instanceof Command) {
101+ $ this
102+ ->add ($ main )
103+ ->mono = true ;
104+ }
105+
98106 $ this ->init ();
99107 }
100108
@@ -153,31 +161,10 @@ public function run($args = [])
153161 }
154162
155163 $ this ->script = array_shift ($ args );
156- $ command = array_shift ($ args );
157-
158- // Invoke the appropriated command for special global options like --help, --version, etc
159- switch ($ command ):
160- case '--version ' :
161- $ command = self ::COMMAND_VERS ;
162- break ;
163-
164- case 'list ' :
165- case '--help ' :
166- case '-h ' :
167- case '--usage ' :
168- $ command = self ::COMMAND_HELP ;
169- break ;
170-
171- case null :
172- $ command = $ this ->getDefault ();
173- break ;
174-
175- default :
176- break ;
177- endswitch ;
178164
179165 try {
180- return $ this ->get ($ command )->run ($ args );
166+ $ info = $ this ->parse ($ args );
167+ return $ this ->get ($ info ['command ' ])->run ($ info ['args ' ]);
181168 } catch (LogicException $ e ) {
182169 $ error = sprintf ('%s, exiting. ' , (string ) $ e );
183170 $ this ->iowrite ($ error );
@@ -283,28 +270,90 @@ public function getUsage($tab = Formatter::TAB, $width = Formatter::PAD)
283270 $ lines [] = sprintf ("$ {tab}%s <command> [<options>] -- [<arguments>] " , $ this ->script );
284271 $ lines [] = "<strong>Commands</strong> " ;
285272
286- foreach ($ this ->commands as $ name => $ command ) {
287- // Don't display help or version commands
288- if (in_array ($ name , [self ::COMMAND_HELP , self ::COMMAND_VERS ])) {
289- continue ;
290- }
291-
273+ foreach ($ this ->getUserCommands () as $ name => $ command ) {
292274 $ lines [] = sprintf ("$ {tab}%- {$ width }s %s " , $ name , $ command ->getHelp ());
293275 }
294276
295277 return implode (Formatter::LF , $ lines );
296278 }
297279
280+ /**
281+ * Find command name and arguments from the command-line invocation
282+ *
283+ * @param array $args The command-line parameters list
284+ *
285+ * @return array An associative array of the form ['command' => '...', 'args' => array(...)]
286+ */
287+ public function parse ($ args )
288+ {
289+ if (in_array ('--version ' , $ args )) {
290+ return [
291+ 'command ' => self ::COMMAND_VERS ,
292+ 'args ' => array_filter ($ args , function ($ a ) { return $ a !== '--version ' ; })
293+ ];
294+ }
295+
296+ if ($ this ->isMono ()) {
297+ return ['command ' => $ this ->getDefault (), 'args ' => $ args ];
298+ }
299+
300+ $ command = array_shift ($ args );
301+
302+ switch ($ command ):
303+ case 'list ' :
304+ case '--help ' :
305+ case '-h ' :
306+ case null :
307+ $ command = self ::COMMAND_HELP ;
308+ break ;
309+
310+ default :
311+ break ;
312+ endswitch ;
313+
314+ return ['command ' => $ command , 'args ' => $ args ];
315+ }
316+
317+ /**
318+ * Setter for the mono-command application flag
319+ *
320+ * @param bool $mono
321+ *
322+ * @return self
323+ */
324+ public function setMono ($ mono )
325+ {
326+ $ this ->mono = $ mono ;
327+
328+ return $ this ;
329+ }
330+
331+ /**
332+ * Getter for the mono-command application flag
333+ *
334+ * @return bool
335+ */
336+ public function isMono ()
337+ {
338+ return $ this ->mono ;
339+ }
340+
341+ /**
342+ * @return Command[]
343+ */
344+ public function getUserCommands ()
345+ {
346+ return array_filter ($ this ->commands , function (Command $ command ) { return (!$ command ->isSystem ()); });
347+ }
348+
298349 /**
299350 * Hook for initialization tasks, called at the end of the constructor:
300351 * - add common commands (help, version)
301- * - set default command name
302352 */
303353 protected function init ()
304354 {
305355 $ this
306- ->addBaseCommands ()
307- ->setDefault (self ::COMMAND_HELP );
356+ ->addBaseCommands ();
308357 }
309358
310359 /**
@@ -326,32 +375,16 @@ public function addBaseCommands()
326375 * Getter for the default command name
327376 *
328377 * @return string
378+ * @throws LogicException If the application has no user-defined command
329379 */
330380 public function getDefault ()
331381 {
332- return $ this ->default ;
333- }
382+ $ commands = $ this ->getUserCommands ();
334383
335- /**
336- * Setter for the default command name
337- * Allow easy configuration in user-defined applications
338- *
339- * @param string|Command $command Name of the default command
340- * A command object may also be passed, thanks to force to-string type-casting
341- *
342- * @return self
343- * @throws UnknownCommandException
344- */
345- public function setDefault ($ command )
346- {
347- $ command = (string ) $ command ;
348-
349- if (!$ this ->has ($ command )) {
350- throw new UnknownCommandException ($ command );
384+ if (0 === count ($ commands )) {
385+ throw new LogicException ('Mono-command applications need at least 1 command defined ' );
351386 }
352387
353- $ this ->default = $ command ;
354-
355- return $ this ;
388+ return $ commands [0 ]->getName ();
356389 }
357390}
0 commit comments