Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mariuswilms committed Apr 30, 2009
1 parent 0ee8889 commit 4b89dd2
Show file tree
Hide file tree
Showing 2 changed files with 471 additions and 108 deletions.
229 changes: 131 additions & 98 deletions cake/console/cake.php
Expand Up @@ -120,15 +120,21 @@ function ShellDispatcher($args = array()) {
/**
* Constructor
*
* @param array $args the argv.
* The execution of the script is stopped after dispatching the request with
* a status code of either 0 or 1 according to the result of the dispatch.
*
* @param array $args the argv
* @return void
* @access public
*/
function __construct($args = array()) {
set_time_limit(0);

$this->__initConstants();
$this->parseParams($args);
$this->_initEnvironment();
$this->__buildPaths();
$this->_stop($this->dispatch());
$this->_stop($this->dispatch() === false ? 1 : 0);
}
/**
* Defines core configuration.
Expand Down Expand Up @@ -269,118 +275,145 @@ function __bootstrap() {
/**
* Dispatches a CLI request
*
* @return boolean
* @access public
*/
function dispatch() {
if (isset($this->args[0])) {
if (!$arg = array_shift($this->args)) {
$this->help();
return false;
}
if ($arg == 'help') {
$this->help();
return true;
}

if (strpos($arg, '.') !== false) {
list($plugin, $shell) = explode('.', $arg);
} else {
$plugin = null;
$shell = $this->args[0];
if (strpos($shell, '.') !== false) {
list($plugin, $shell) = explode('.', $this->args[0]);
$shell = $arg;
}
$this->shell = $shell;
$this->shellName = Inflector::camelize($shell);
$this->shellClass = $this->shellName . 'Shell';

if ($arg = array_shift($this->args)) {
$this->shellCommand = Inflector::variable($arg);
}

$Shell = $this->_getShell($plugin);

if (!$Shell) {
$message = sprintf(__('Class `%s` could not be loaded', true), $this->shellClass);
$this->stderr($message . "\n");
return false;
}

if (is_a($Shell, 'Shell')) {
$Shell->initialize();
$Shell->loadTasks();

foreach ($Shell->taskNames as $task) {
if (is_a($Shell->{$task}, 'Shell')) {
$Shell->{$task}->initialize();
$Shell->{$task}->loadTasks();
}
}

$this->shell = $shell;
$this->shiftArgs();
$this->shellName = Inflector::camelize($this->shell);
$this->shellClass = $this->shellName . 'Shell';
$task = Inflector::camelize($this->shellCommand);

if ($this->shell === 'help') {
$this->help();
} else {
$loaded = false;
foreach ($this->shellPaths as $path) {
$this->shellPath = $path . $this->shell . '.php';

$isPlugin = ($plugin && strpos($path, DS . $plugin . DS . 'vendors' . DS . 'shells' . DS) !== false);
if (($isPlugin && file_exists($this->shellPath)) || (!$plugin && file_exists($this->shellPath))) {
$loaded = true;
break;
if (in_array($task, $Shell->taskNames)) {
$this->shiftArgs();
$Shell->{$task}->startup();

if (isset($this->args[0]) && $this->args[0] == 'help') {
if (method_exists($Shell->{$task}, 'help')) {
$Shell->{$task}->help();
} else {
$this->help();
}
return true;
}
return $Shell->{$task}->execute();
}

if ($loaded) {
if (!class_exists('Shell')) {
require CONSOLE_LIBS . 'shell.php';
}
require $this->shellPath;
if (class_exists($this->shellClass)) {
$command = null;
if (isset($this->args[0])) {
$command = $this->args[0];
}
$this->shellCommand = Inflector::variable($command);
$shell = new $this->shellClass($this);

if (strtolower(get_parent_class($shell)) == 'shell') {
$shell->initialize();
$shell->loadTasks();

foreach ($shell->taskNames as $task) {
if (strtolower(get_parent_class($shell)) == 'shell') {
$shell->{$task}->initialize();
$shell->{$task}->loadTasks();
}
}

$task = Inflector::camelize($command);
if (in_array($task, $shell->taskNames)) {
$this->shiftArgs();
$shell->{$task}->startup();
if (isset($this->args[0]) && $this->args[0] == 'help') {
if (method_exists($shell->{$task}, 'help')) {
$shell->{$task}->help();
$this->_stop();
} else {
$this->help();
}
}
return $shell->{$task}->execute();
}
}
}

$classMethods = get_class_methods($shell);
$classMethods = get_class_methods($Shell);

$privateMethod = $missingCommand = false;
if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
$privateMethod = true;
}
$privateMethod = $missingCommand = false;
if ((in_array($arg, $classMethods) || in_array(strtolower($arg), $classMethods))
&& $arg[0] == '_') {
$privateMethod = true;
}

if (!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) {
$missingCommand = true;
}
if (!in_array($arg, $classMethods) && !in_array(strtolower($arg), $classMethods)) {
$missingCommand = true;
}

$protectedCommands = array(
'initialize','in','out','err','hr',
'createfile', 'isdir','copydir','object','tostring',
'requestaction','log','cakeerror', 'shelldispatcher',
'__initconstants','__initenvironment','__construct',
'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
);
$protectedCommands = array(
'initialize','in','out','err','hr',
'createfile', 'isdir','copydir','object','tostring',
'requestaction','log','cakeerror', 'shelldispatcher',
'__initconstants','__initenvironment','__construct',
'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
);

if (in_array(strtolower($command), $protectedCommands)) {
$missingCommand = true;
}
if (in_array(strtolower($arg), $protectedCommands)) {
$missingCommand = true;
}

if ($missingCommand && method_exists($shell, 'main')) {
$shell->startup();
return $shell->main();
} elseif (!$privateMethod && method_exists($shell, $command)) {
$this->shiftArgs();
$shell->startup();
return $shell->{$command}();
} else {
$this->stderr("Unknown {$this->shellName} command '$command'.\nFor usage, try 'cake {$this->shell} help'.\n\n");
}
} else {
$this->stderr('Class '.$this->shellClass.' could not be loaded');
}
} else {
$this->help();
}
if ($missingCommand && method_exists($Shell, 'main')) {
$Shell->startup();
return $Shell->main();
} elseif (!$privateMethod && method_exists($Shell, $arg)) {
$this->shiftArgs();
$Shell->startup();
return $Shell->{$arg}();
}

$message = sprintf(__('Unknown %1$s command `%2$s`. For usage try `cake %3$s help`.', true),
$this->shellName, $this->shellCommand, $this->shell);
$this->stderr($message . "\n");
return false;
}
/**
* Get shell to use, either plugin shell or application shell
*
* All paths in the shellPaths property are searched.
* shell, shellPath and shellClass properties are taken into account.
*
* @param string $plugin Optionally the name of a plugin
* @return mixed False if no shell could be found or an object on success
* @access protected
*/
function _getShell($plugin = null) {
foreach ($this->shellPaths as $path) {
$this->shellPath = $path . $this->shell . '.php';
$pluginShellPath = DS . $plugin . DS . 'vendors' . DS . 'shells' . DS;

if ((strpos($path, $pluginShellPath) !== false || !$plugin) && file_exists($this->shellPath)) {
$loaded = true;
break;
}
} else {
$this->help();
}
if (!isset($loaded)) {
return false;
}

if (!class_exists('Shell')) {
require CONSOLE_LIBS . 'shell.php';
}

if (!class_exists($this->shellClass)) {
require $this->shellPath;
}
if (!class_exists($this->shellClass)) {
return false;
}
$Shell = new $this->shellClass($this);
return $Shell;
}
/**
* Prompts the user for input, and returns it.
Expand Down Expand Up @@ -480,7 +513,7 @@ function parseParams($params) {
$this->params = array_merge($this->params, $params);
}
/**
* Helper for recursively paraing params
* Helper for recursively parsing params
*
* @return array params
* @access private
Expand Down Expand Up @@ -559,6 +592,7 @@ function help() {
} else {
sort($shells);
foreach ($shells as $shell) {

if ($shell !== 'shell.php') {
$this->stdout("\t " . str_replace('.php', '', $shell));
}
Expand All @@ -568,7 +602,6 @@ function help() {
}
$this->stdout("\nTo run a command, type 'cake shell_name [args]'");
$this->stdout("To get help on a specific command, type 'cake shell_name help'");
$this->_stop();
}
/**
* Stop execution of the current script
Expand Down

0 comments on commit 4b89dd2

Please sign in to comment.