22
33namespace PhpSchool \PhpWorkshop ;
44
5+ use PhpSchool \PhpWorkshop \Event \EventDispatcher ;
56use PhpSchool \PhpWorkshop \Exception \CliRouteNotExistsException ;
67use PhpSchool \PhpWorkshop \Exception \MissingArgumentException ;
78use Interop \Container \ContainerInterface ;
9+ use PhpSchool \PhpWorkshop \Input \Input ;
810use SebastianBergmann \Environment \Runtime ;
911
1012/**
@@ -28,6 +30,11 @@ class CommandRouter
2830 */
2931 private $ defaultCommand ;
3032
33+ /**
34+ * @var EventDispatcher
35+ */
36+ private $ eventDispatcher ;
37+
3138 /**
3239 * @var ContainerInterface
3340 */
@@ -42,10 +49,15 @@ class CommandRouter
4249 *
4350 * @param CommandDefinition[] $commands An array of command definitions
4451 * @param string $default The default command to use (if the workshop was invoked with no arguments)
52+ * @param EventDispatcher $eventDispatcher
4553 * @param ContainerInterface $container An instance of the container
4654 */
47- public function __construct (array $ commands , $ default , ContainerInterface $ container )
48- {
55+ public function __construct (
56+ array $ commands ,
57+ $ default ,
58+ EventDispatcher $ eventDispatcher ,
59+ ContainerInterface $ container
60+ ) {
4961 foreach ($ commands as $ command ) {
5062 $ this ->addCommand ($ command );
5163 }
@@ -54,6 +66,7 @@ public function __construct(array $commands, $default, ContainerInterface $conta
5466 throw new \InvalidArgumentException (sprintf ('Default command: "%s" is not available ' , $ default ));
5567 }
5668 $ this ->defaultCommand = $ default ;
69+ $ this ->eventDispatcher = $ eventDispatcher ;
5770 $ this ->container = $ container ;
5871 }
5972
@@ -88,40 +101,47 @@ private function addCommand(CommandDefinition $c)
88101 */
89102 public function route (array $ args = null )
90103 {
104+
91105 if (null === $ args ) {
92106 $ args = isset ($ _SERVER ['argv ' ]) ? $ _SERVER ['argv ' ] : [];
93107 }
94108
95109 $ appName = array_shift ($ args );
96110
97111 if (empty ($ args )) {
98- return $ this ->resolveCallable ($ this ->commands [$ this ->defaultCommand ], array_merge ([ $ appName], $ args ));
112+ return $ this ->resolveCallable ($ this ->commands [$ this ->defaultCommand ], new Input ( $ appName ));
99113 }
100114
101115 $ commandName = array_shift ($ args );
102116 if (!isset ($ this ->commands [$ commandName ])) {
103117 $ command = $ this ->findNearestCommand ($ commandName , $ this ->commands );
104-
118+
105119 if (false === $ command ) {
106120 throw new CliRouteNotExistsException ($ commandName );
107121 }
108-
122+
109123 $ commandName = $ command ;
110124 }
111125 $ command = $ this ->commands [$ commandName ];
112126
113- $ this ->checkRequiredArgs ( $ commandName , $ command-> getRequiredArgs (), $ args );
127+ $ this ->eventDispatcher -> dispatch ( new Event \ Event ( ' route.pre.resolve.args ' , [ ' command ' => $ command ]) );
114128
115- return $ this ->resolveCallable ($ command , array_merge ([$ appName ], $ args ));
129+ $ input = $ this ->parseArgs ($ commandName , $ command ->getRequiredArgs (), $ appName , $ args );
130+
131+ return $ this ->resolveCallable ($ command , $ input );
116132 }
117133
118134 /**
119135 * @param string $commandName
120- * @param array $definitionArgs
136+ * @param CommandArgument[] $definitionArgs
137+ * @param string $appName
121138 * @param array $givenArgs
139+ * @return Input
122140 */
123- private function checkRequiredArgs ($ commandName , array $ definitionArgs , array $ givenArgs )
141+ private function parseArgs ($ commandName , array $ definitionArgs, $ appName , array $ givenArgs )
124142 {
143+ $ parsedArgs = [];
144+
125145 while (null !== ($ definitionArg = array_shift ($ definitionArgs ))) {
126146 $ arg = array_shift ($ givenArgs );
127147
@@ -130,7 +150,11 @@ private function checkRequiredArgs($commandName, array $definitionArgs, array $g
130150 return $ argument ->getName ();
131151 }, array_merge ([$ definitionArg ], $ definitionArgs )));
132152 }
153+
154+ $ parsedArgs [$ definitionArg ->getName ()] = $ arg ;
133155 }
156+
157+ return new Input ($ appName , $ parsedArgs );
134158 }
135159
136160 /**
@@ -147,29 +171,29 @@ private function findNearestCommand($commandName, array $commands)
147171 foreach (array_keys ($ commands ) as $ command ) {
148172 $ distances [$ command ] = levenshtein ($ commandName , $ command );
149173 }
150-
174+
151175 $ distances = array_filter (array_unique ($ distances ), function ($ distance ) {
152176 return $ distance <= 3 ;
153177 });
154-
178+
155179 if (empty ($ distances )) {
156180 return false ;
157181 }
158-
182+
159183 return array_search (min ($ distances ), $ distances );
160184 }
161185
162186 /**
163187 * @param CommandDefinition $command
164- * @param array $args
188+ * @param Input $input
165189 * @return int
166190 */
167- private function resolveCallable (CommandDefinition $ command , array $ args )
191+ private function resolveCallable (CommandDefinition $ command , Input $ input )
168192 {
169193 $ commandCallable = $ command ->getCommandCallable ();
170194
171195 if (is_callable ($ commandCallable )) {
172- return $ this ->callCommand ($ commandCallable , $ args );
196+ return $ this ->callCommand ($ command , $ commandCallable , $ input );
173197 }
174198
175199 if (!is_string ($ commandCallable )) {
@@ -186,7 +210,7 @@ private function resolveCallable(CommandDefinition $command, array $args)
186210 throw new \RuntimeException (sprintf ('Container entry: "%s" not callable ' , $ commandCallable ));
187211 }
188212
189- $ return = $ this ->callCommand ($ callable , $ args );
213+ $ return = $ this ->callCommand ($ command , $ callable , $ input );
190214
191215 if (is_int ($ return )) {
192216 return $ return ;
@@ -196,12 +220,16 @@ private function resolveCallable(CommandDefinition $command, array $args)
196220 }
197221
198222 /**
199- * @param callable $command
200- * @param array $arguments
223+ * @param CommandDefinition $command
224+ * @param callable $callable
225+ * @param Input $input
201226 * @return int
202227 */
203- private function callCommand (callable $ command , array $ arguments )
228+ private function callCommand (CommandDefinition $ command , callable $ callable , Input $ input )
204229 {
205- return $ command (...$ arguments );
230+ $ this ->eventDispatcher ->dispatch (new Event \Event ('route.pre.invoke ' ));
231+ $ this ->eventDispatcher ->dispatch (new Event \Event (sprintf ('route.pre.invoke.%s ' , $ command ->getName ())));
232+
233+ return $ callable ($ input );
206234 }
207235}
0 commit comments