'command', 'shellPaths'); foreach ($vars as $key => $var) { if (is_string($key)) { $this->{$var} =& $dispatch->{$key}; } else { $this->{$var} =& $dispatch->{$var}; } } if ($this->name == null) { $this->name = get_class($this); } if ($this->alias == null) { $this->alias = $this->name; } $this->Dispatch =& $dispatch; $this->Tasks = new TaskCollection($this); $this->stdout = $stdout; $this->stderr = $stderr; $this->stdin = $stdin; if ($this->stdout == null) { $this->stdout = new ConsoleOutput('php://stdout'); } if ($this->stderr == null) { $this->stderr = new ConsoleOutput('php://stderr'); } if ($this->stdin == null) { $this->stdin = new ConsoleInput('php://stdin'); } } /** * Initializes the Shell * acts as constructor for subclasses * allows configuration of tasks prior to shell execution * */ public function initialize() { $this->_loadModels(); } /** * Starts up the Shell * allows for checking and configuring prior to command or main execution * can be overriden in subclasses * */ public function startup() { $this->_welcome(); } /** * Displays a header for the shell * */ protected function _welcome() { $this->clear(); $this->out(); $this->out('Welcome to CakePHP v' . Configure::version() . ' Console'); $this->hr(); $this->out('App : '. $this->params['app']); $this->out('Path: '. $this->params['working']); $this->hr(); } /** * if public $uses = true * Loads AppModel file and constructs AppModel class * makes $this->AppModel available to subclasses * if public $uses is an array of models will load those models * * @return bool */ protected function _loadModels() { if ($this->uses === null || $this->uses === false) { return; } if ($this->uses === true && App::import('Model', 'AppModel')) { $this->AppModel =& new AppModel(false, false, false); return true; } if ($this->uses !== true && !empty($this->uses)) { $uses = is_array($this->uses) ? $this->uses : array($this->uses); $modelClassName = $uses[0]; if (strpos($uses[0], '.') !== false) { list($plugin, $modelClassName) = explode('.', $uses[0]); } $this->modelClass = $modelClassName; foreach ($uses as $modelClass) { list($plugin, $modelClass) = pluginSplit($modelClass, true); $this->{$modelClass} = ClassRegistry::init($plugin . $modelClass); } return true; } return false; } /** * Loads tasks defined in public $tasks * * @return bool */ public function loadTasks() { if ($this->tasks === true || empty($this->tasks) || empty($this->Tasks)) { return true; } $tasks = TaskCollection::normalizeObjectArray((array)$this->tasks); foreach ($tasks as $task => $properties) { $this->{$task} = $this->Tasks->load($properties['class'], $properties['settings']); $this->taskNames[] = $task; } return true; } /** * Prompts the user for input, and returns it. * * @param string $prompt Prompt text. * @param mixed $options Array or string of options. * @param string $default Default input value. * @return Either the default value, or the user-provided input. */ public function in($prompt, $options = null, $default = null) { if (!$this->interactive) { return $default; } $in = $this->_getInput($prompt, $options, $default); if ($options && is_string($options)) { if (strpos($options, ',')) { $options = explode(',', $options); } elseif (strpos($options, '/')) { $options = explode('/', $options); } else { $options = array($options); } } if (is_array($options)) { while ($in == '' || ($in && (!in_array(strtolower($in), $options) && !in_array(strtoupper($in), $options)) && !in_array($in, $options))) { $in = $this->_getInput($prompt, $options, $default); } } if ($in) { return $in; } } /** * Prompts the user for input, and returns it. * * @param string $prompt Prompt text. * @param mixed $options Array or string of options. * @param string $default Default input value. * @return Either the default value, or the user-provided input. */ protected function _getInput($prompt, $options, $default) { if (!is_array($options)) { $printOptions = ''; } else { $printOptions = '(' . implode('/', $options) . ')'; } if ($default === null) { $this->stdout->write($prompt . " $printOptions \n" . '> ', 0); } else { $this->stdout->write($prompt . " $printOptions \n" . "[$default] > ", 0); } $result = $this->stdin->read(); if ($result === false) { $this->_stop(1); } $result = trim($result); if ($default != null && empty($result)) { return $default; } return $result; } /** * Outputs a single or multiple messages to stdout. If no parameters * are passed outputs just a newline. * * @param mixed $message A string or a an array of strings to output * @param integer $newlines Number of newlines to append * @return integer Returns the number of bytes returned from writing to stdout. */ public function out($message = null, $newlines = 1) { return $this->stdout->write($message, $newlines); } /** * Outputs a single or multiple error messages to stderr. If no parameters * are passed outputs just a newline. * * @param mixed $message A string or a an array of strings to output * @param integer $newlines Number of newlines to append */ public function err($message = null, $newlines = 1) { $this->stderr->write($message, $newlines); } /** * Returns a single or multiple linefeeds sequences. * * @param integer $multiplier Number of times the linefeed sequence should be repeated * @access public * @return string */ function nl($multiplier = 1) { return str_repeat(ConsoleOutput::LF, $multiplier); } /** * Outputs a series of minus characters to the standard output, acts as a visual separator. * * @param integer $newlines Number of newlines to pre- and append * @param integer $width Width of the line, defaults to 63 */ public function hr($newlines = 0, $width = 63) { $this->out(null, $newlines); $this->out(str_repeat('-', $width)); $this->out(null, $newlines); } /** * Displays a formatted error message * and exits the application with status code 1 * * @param string $title Title of the error * @param string $message An optional error message */ public function error($title, $message = null) { $this->err(sprintf(__('Error: %s'), $title)); if (!empty($message)) { $this->err($message); } $this->_stop(1); } /** * Clear the console * * @return void */ public function clear() { if (empty($this->params['noclear'])) { if ( DS === '/') { passthru('clear'); } else { passthru('cls'); } } } /** * Will check the number args matches otherwise throw an error * * @param integer $expectedNum Expected number of paramters * @param string $command Command */ protected function _checkArgs($expectedNum, $command = null) { if (!$command) { $command = $this->command; } if (count($this->args) < $expectedNum) { $message[] = "Got: " . count($this->args); $message[] = "Expected: {$expectedNum}"; $message[] = "Please type `cake {$this->shell} help` for help"; $message[] = "on usage of the {$this->name} {$command}."; $this->error('Wrong number of parameters', $message); } } /** * Creates a file at given path * * @param string $path Where to put the file. * @param string $contents Content to put in the file. * @return boolean Success */ public function createFile($path, $contents) { $path = str_replace(DS . DS, DS, $path); $this->out(); $this->out(sprintf(__('Creating file %s'), $path)); if (is_file($path) && $this->interactive === true) { $prompt = sprintf(__('File `%s` exists, overwrite?'), $path); $key = $this->in($prompt, array('y', 'n', 'q'), 'n'); if (strtolower($key) == 'q') { $this->out(__('Quitting.'), 2); $this->_stop(); } elseif (strtolower($key) != 'y') { $this->out(sprintf(__('Skip `%s`'), $path), 2); return false; } } if (!class_exists('File')) { require LIBS . 'file.php'; } if ($File = new File($path, true)) { $data = $File->prepare($contents); $File->write($data); $this->out(sprintf(__('Wrote `%s`'), $path)); return true; } else { $this->err(sprintf(__('Could not write to `%s`.'), $path), 2); return false; } } /** * Outputs usage text on the standard output. Implement it in subclasses. * */ public function help() { if ($this->command != null) { $this->err("Unknown {$this->name} command `{$this->command}`."); $this->err("For usage, try `cake {$this->shell} help`.", 2); } else { $this->Dispatch->help(); } } /** * Action to create a Unit Test * * @return boolean Success */ protected function _checkUnitTest() { if (App::import('vendor', 'simpletest' . DS . 'simpletest')) { return true; } $prompt = 'SimpleTest is not installed. Do you want to bake unit test files anyway?'; $unitTest = $this->in($prompt, array('y','n'), 'y'); $result = strtolower($unitTest) == 'y' || strtolower($unitTest) == 'yes'; if ($result) { $this->out(); $this->out('You can download SimpleTest from http://simpletest.org'); } return $result; } /** * Makes absolute file path easier to read * * @param string $file Absolute file path * @return sting short path */ public function shortPath($file) { $shortPath = str_replace(ROOT, null, $file); $shortPath = str_replace('..' . DS, '', $shortPath); return str_replace(DS . DS, DS, $shortPath); } /** * Creates the proper controller path for the specified controller class name * * @param string $name Controller class name * @return string Path to controller */ protected function _controllerPath($name) { return strtolower(Inflector::underscore($name)); } /** * Creates the proper controller plural name for the specified controller class name * * @param string $name Controller class name * @return string Controller plural name */ protected function _controllerName($name) { return Inflector::pluralize(Inflector::camelize($name)); } /** * Creates the proper controller camelized name (singularized) for the specified name * * @param string $name Name * @return string Camelized and singularized controller name */ protected function _modelName($name) { return Inflector::camelize(Inflector::singularize($name)); } /** * Creates the proper underscored model key for associations * * @param string $name Model class name * @return string Singular model key */ protected function _modelKey($name) { return Inflector::underscore($name) . '_id'; } /** * Creates the proper model name from a foreign key * * @param string $key Foreign key * @return string Model name */ protected function _modelNameFromKey($key) { return Inflector::camelize(str_replace('_id', '', $key)); } /** * creates the singular name for use in views. * * @param string $name * @return string $name */ protected function _singularName($name) { return Inflector::variable(Inflector::singularize($name)); } /** * Creates the plural name for views * * @param string $name Name to use * @return string Plural name for views */ protected function _pluralName($name) { return Inflector::variable(Inflector::pluralize($name)); } /** * Creates the singular human name used in views * * @param string $name Controller name * @return string Singular human name */ protected function _singularHumanName($name) { return Inflector::humanize(Inflector::underscore(Inflector::singularize($name))); } /** * Creates the plural human name used in views * * @param string $name Controller name * @return string Plural human name */ protected function _pluralHumanName($name) { return Inflector::humanize(Inflector::underscore($name)); } /** * Find the correct path for a plugin. Scans $pluginPaths for the plugin you want. * * @param string $pluginName Name of the plugin you want ie. DebugKit * @return string $path path to the correct plugin. */ function _pluginPath($pluginName) { return App::pluginPath($pluginName); } }