Skip to content

Commit 4b89dd2

Browse files
committed
Refactoring ShellDispatcher::dispatch
Updating dispatch method to use is_a fixes #5318 Adding _getShell method to ease testing Updating status code handling in the constructor Adding and updating tests
1 parent 0ee8889 commit 4b89dd2

File tree

2 files changed

+471
-108
lines changed

2 files changed

+471
-108
lines changed

cake/console/cake.php

Lines changed: 131 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,21 @@ function ShellDispatcher($args = array()) {
120120
/**
121121
* Constructor
122122
*
123-
* @param array $args the argv.
123+
* The execution of the script is stopped after dispatching the request with
124+
* a status code of either 0 or 1 according to the result of the dispatch.
125+
*
126+
* @param array $args the argv
127+
* @return void
128+
* @access public
124129
*/
125130
function __construct($args = array()) {
126131
set_time_limit(0);
132+
127133
$this->__initConstants();
128134
$this->parseParams($args);
129135
$this->_initEnvironment();
130136
$this->__buildPaths();
131-
$this->_stop($this->dispatch());
137+
$this->_stop($this->dispatch() === false ? 1 : 0);
132138
}
133139
/**
134140
* Defines core configuration.
@@ -269,118 +275,145 @@ function __bootstrap() {
269275
/**
270276
* Dispatches a CLI request
271277
*
278+
* @return boolean
272279
* @access public
273280
*/
274281
function dispatch() {
275-
if (isset($this->args[0])) {
282+
if (!$arg = array_shift($this->args)) {
283+
$this->help();
284+
return false;
285+
}
286+
if ($arg == 'help') {
287+
$this->help();
288+
return true;
289+
}
290+
291+
if (strpos($arg, '.') !== false) {
292+
list($plugin, $shell) = explode('.', $arg);
293+
} else {
276294
$plugin = null;
277-
$shell = $this->args[0];
278-
if (strpos($shell, '.') !== false) {
279-
list($plugin, $shell) = explode('.', $this->args[0]);
295+
$shell = $arg;
296+
}
297+
$this->shell = $shell;
298+
$this->shellName = Inflector::camelize($shell);
299+
$this->shellClass = $this->shellName . 'Shell';
300+
301+
if ($arg = array_shift($this->args)) {
302+
$this->shellCommand = Inflector::variable($arg);
303+
}
304+
305+
$Shell = $this->_getShell($plugin);
306+
307+
if (!$Shell) {
308+
$message = sprintf(__('Class `%s` could not be loaded', true), $this->shellClass);
309+
$this->stderr($message . "\n");
310+
return false;
311+
}
312+
313+
if (is_a($Shell, 'Shell')) {
314+
$Shell->initialize();
315+
$Shell->loadTasks();
316+
317+
foreach ($Shell->taskNames as $task) {
318+
if (is_a($Shell->{$task}, 'Shell')) {
319+
$Shell->{$task}->initialize();
320+
$Shell->{$task}->loadTasks();
321+
}
280322
}
281323

282-
$this->shell = $shell;
283-
$this->shiftArgs();
284-
$this->shellName = Inflector::camelize($this->shell);
285-
$this->shellClass = $this->shellName . 'Shell';
324+
$task = Inflector::camelize($this->shellCommand);
286325

287-
if ($this->shell === 'help') {
288-
$this->help();
289-
} else {
290-
$loaded = false;
291-
foreach ($this->shellPaths as $path) {
292-
$this->shellPath = $path . $this->shell . '.php';
293-
294-
$isPlugin = ($plugin && strpos($path, DS . $plugin . DS . 'vendors' . DS . 'shells' . DS) !== false);
295-
if (($isPlugin && file_exists($this->shellPath)) || (!$plugin && file_exists($this->shellPath))) {
296-
$loaded = true;
297-
break;
326+
if (in_array($task, $Shell->taskNames)) {
327+
$this->shiftArgs();
328+
$Shell->{$task}->startup();
329+
330+
if (isset($this->args[0]) && $this->args[0] == 'help') {
331+
if (method_exists($Shell->{$task}, 'help')) {
332+
$Shell->{$task}->help();
333+
} else {
334+
$this->help();
298335
}
336+
return true;
299337
}
338+
return $Shell->{$task}->execute();
339+
}
300340

301-
if ($loaded) {
302-
if (!class_exists('Shell')) {
303-
require CONSOLE_LIBS . 'shell.php';
304-
}
305-
require $this->shellPath;
306-
if (class_exists($this->shellClass)) {
307-
$command = null;
308-
if (isset($this->args[0])) {
309-
$command = $this->args[0];
310-
}
311-
$this->shellCommand = Inflector::variable($command);
312-
$shell = new $this->shellClass($this);
313-
314-
if (strtolower(get_parent_class($shell)) == 'shell') {
315-
$shell->initialize();
316-
$shell->loadTasks();
317-
318-
foreach ($shell->taskNames as $task) {
319-
if (strtolower(get_parent_class($shell)) == 'shell') {
320-
$shell->{$task}->initialize();
321-
$shell->{$task}->loadTasks();
322-
}
323-
}
324-
325-
$task = Inflector::camelize($command);
326-
if (in_array($task, $shell->taskNames)) {
327-
$this->shiftArgs();
328-
$shell->{$task}->startup();
329-
if (isset($this->args[0]) && $this->args[0] == 'help') {
330-
if (method_exists($shell->{$task}, 'help')) {
331-
$shell->{$task}->help();
332-
$this->_stop();
333-
} else {
334-
$this->help();
335-
}
336-
}
337-
return $shell->{$task}->execute();
338-
}
339-
}
341+
}
340342

341-
$classMethods = get_class_methods($shell);
343+
$classMethods = get_class_methods($Shell);
342344

343-
$privateMethod = $missingCommand = false;
344-
if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
345-
$privateMethod = true;
346-
}
345+
$privateMethod = $missingCommand = false;
346+
if ((in_array($arg, $classMethods) || in_array(strtolower($arg), $classMethods))
347+
&& $arg[0] == '_') {
348+
$privateMethod = true;
349+
}
347350

348-
if (!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) {
349-
$missingCommand = true;
350-
}
351+
if (!in_array($arg, $classMethods) && !in_array(strtolower($arg), $classMethods)) {
352+
$missingCommand = true;
353+
}
351354

352-
$protectedCommands = array(
353-
'initialize','in','out','err','hr',
354-
'createfile', 'isdir','copydir','object','tostring',
355-
'requestaction','log','cakeerror', 'shelldispatcher',
356-
'__initconstants','__initenvironment','__construct',
357-
'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
358-
);
355+
$protectedCommands = array(
356+
'initialize','in','out','err','hr',
357+
'createfile', 'isdir','copydir','object','tostring',
358+
'requestaction','log','cakeerror', 'shelldispatcher',
359+
'__initconstants','__initenvironment','__construct',
360+
'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
361+
);
359362

360-
if (in_array(strtolower($command), $protectedCommands)) {
361-
$missingCommand = true;
362-
}
363+
if (in_array(strtolower($arg), $protectedCommands)) {
364+
$missingCommand = true;
365+
}
363366

364-
if ($missingCommand && method_exists($shell, 'main')) {
365-
$shell->startup();
366-
return $shell->main();
367-
} elseif (!$privateMethod && method_exists($shell, $command)) {
368-
$this->shiftArgs();
369-
$shell->startup();
370-
return $shell->{$command}();
371-
} else {
372-
$this->stderr("Unknown {$this->shellName} command '$command'.\nFor usage, try 'cake {$this->shell} help'.\n\n");
373-
}
374-
} else {
375-
$this->stderr('Class '.$this->shellClass.' could not be loaded');
376-
}
377-
} else {
378-
$this->help();
379-
}
367+
if ($missingCommand && method_exists($Shell, 'main')) {
368+
$Shell->startup();
369+
return $Shell->main();
370+
} elseif (!$privateMethod && method_exists($Shell, $arg)) {
371+
$this->shiftArgs();
372+
$Shell->startup();
373+
return $Shell->{$arg}();
374+
}
375+
376+
$message = sprintf(__('Unknown %1$s command `%2$s`. For usage try `cake %3$s help`.', true),
377+
$this->shellName, $this->shellCommand, $this->shell);
378+
$this->stderr($message . "\n");
379+
return false;
380+
}
381+
/**
382+
* Get shell to use, either plugin shell or application shell
383+
*
384+
* All paths in the shellPaths property are searched.
385+
* shell, shellPath and shellClass properties are taken into account.
386+
*
387+
* @param string $plugin Optionally the name of a plugin
388+
* @return mixed False if no shell could be found or an object on success
389+
* @access protected
390+
*/
391+
function _getShell($plugin = null) {
392+
foreach ($this->shellPaths as $path) {
393+
$this->shellPath = $path . $this->shell . '.php';
394+
$pluginShellPath = DS . $plugin . DS . 'vendors' . DS . 'shells' . DS;
395+
396+
if ((strpos($path, $pluginShellPath) !== false || !$plugin) && file_exists($this->shellPath)) {
397+
$loaded = true;
398+
break;
380399
}
381-
} else {
382-
$this->help();
383400
}
401+
if (!isset($loaded)) {
402+
return false;
403+
}
404+
405+
if (!class_exists('Shell')) {
406+
require CONSOLE_LIBS . 'shell.php';
407+
}
408+
409+
if (!class_exists($this->shellClass)) {
410+
require $this->shellPath;
411+
}
412+
if (!class_exists($this->shellClass)) {
413+
return false;
414+
}
415+
$Shell = new $this->shellClass($this);
416+
return $Shell;
384417
}
385418
/**
386419
* Prompts the user for input, and returns it.
@@ -480,7 +513,7 @@ function parseParams($params) {
480513
$this->params = array_merge($this->params, $params);
481514
}
482515
/**
483-
* Helper for recursively paraing params
516+
* Helper for recursively parsing params
484517
*
485518
* @return array params
486519
* @access private
@@ -559,6 +592,7 @@ function help() {
559592
} else {
560593
sort($shells);
561594
foreach ($shells as $shell) {
595+
562596
if ($shell !== 'shell.php') {
563597
$this->stdout("\t " . str_replace('.php', '', $shell));
564598
}
@@ -568,7 +602,6 @@ function help() {
568602
}
569603
$this->stdout("\nTo run a command, type 'cake shell_name [args]'");
570604
$this->stdout("To get help on a specific command, type 'cake shell_name help'");
571-
$this->_stop();
572605
}
573606
/**
574607
* Stop execution of the current script

0 commit comments

Comments
 (0)