diff --git a/app/config/bootstrap.php b/app/config/bootstrap.php
index 924147237..2c9b9f45d 100644
--- a/app/config/bootstrap.php
+++ b/app/config/bootstrap.php
@@ -20,22 +20,27 @@
* @since CakePHP(tm) v 0.10.8.2117
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
+
/**
* The settings below can be used to set additional paths to models, views and controllers.
* This is related to Ticket #470 (https://trac.cakephp.org/ticket/470)
*
- * $modelPaths = array('/full/path/to/models/', '/next/full/path/to/models/');
- * $viewPaths = array('/full/path/to/views/', '/next/full/path/to/views/');
- * $controllerPaths = array(/full/path/to/controllers/', '/next/full/path/to/controllers/');
- * $pluginPaths = array('/full/path/to/plugins/', '/next/full/path/to/plugins/');
- * $behaviorPaths = array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/');
- * $componentPaths = array('/full/path/to/components/', '/next/full/path/to/components/');
- * $helperPaths = array('/full/path/to/helpers/', '/next/full/path/to/helpers/');
- * $vendorPaths = array('/full/path/to/vendors/', '/next/full/path/to/vendors/');
- * $shellPaths = array('/full/path/to/shells/', '/next/full/path/to/shells/');
- * $localePaths = array('/full/path/to/locale/', '/next/full/path/to/locale/';
+ * App::build(array(
+ * 'plugins' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
+ * 'models' => array('/full/path/to/models/', '/next/full/path/to/models/'),
+ * 'views' => array('/full/path/to/views/', '/next/full/path/to/views/'),
+ * 'controllers' => array(/full/path/to/controllers/', '/next/full/path/to/controllers/'),
+ * 'datasources' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'),
+ * 'behaviors' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'),
+ * 'components' => array('/full/path/to/components/', '/next/full/path/to/components/'),
+ * 'helpers' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
+ * 'vendors' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
+ * 'shells' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
+ * 'locales' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
+ * ));
*
*/
+
/**
* As of 1.3, additional rules for the inflector are added below
*
diff --git a/app/webroot/test.php b/app/webroot/test.php
index 725469d93..4cdbd8c28 100644
--- a/app/webroot/test.php
+++ b/app/webroot/test.php
@@ -93,7 +93,7 @@ if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) {
trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR);
}
-$corePath = Configure::corePaths('cake');
+$corePath = App::core('cake');
if (isset($corePath[0])) {
define('TEST_CAKE_CORE_INCLUDE_PATH', rtrim($corePath[0], DS) . DS);
} else {
diff --git a/cake/basics.php b/cake/basics.php
index cae6e65bd..b6b07c761 100644
--- a/cake/basics.php
+++ b/cake/basics.php
@@ -1,5 +1,6 @@
tags around
* the output of given array. Similar to debug().
@@ -314,6 +331,7 @@ if (!function_exists('array_combine')) {
echo '';
}
}
+
/**
* Display parameters.
*
@@ -329,6 +347,7 @@ if (!function_exists('array_combine')) {
}
return $p;
}
+
/**
* Merge a group of arrays
*
@@ -350,6 +369,7 @@ if (!function_exists('array_combine')) {
}
return $r;
}
+
/**
* Gets an environment variable from available sources, and provides emulation
* for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
@@ -362,8 +382,8 @@ if (!function_exists('array_combine')) {
*/
function env($key) {
if ($key == 'HTTPS') {
- if (isset($_SERVER) && !empty($_SERVER)) {
- return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on');
+ if (isset($_SERVER['HTTPS'])) {
+ return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
}
return (strpos(env('SCRIPT_URI'), 'https://') === 0);
}
@@ -426,6 +446,7 @@ if (!function_exists('array_combine')) {
return null;
}
if (!function_exists('file_put_contents')) {
+
/**
* Writes data into file.
*
@@ -453,6 +474,7 @@ if (!function_exists('file_put_contents')) {
return false;
}
}
+
/**
* Reads/writes temporary data to cache files or session.
*
@@ -504,6 +526,7 @@ if (!function_exists('file_put_contents')) {
}
return $data;
}
+
/**
* Used to delete files in the cache directories, or clear contents of cache directories
*
@@ -566,6 +589,7 @@ if (!function_exists('file_put_contents')) {
}
return false;
}
+
/**
* Recursively strips slashes from all values in an array
*
@@ -583,6 +607,7 @@ if (!function_exists('file_put_contents')) {
}
return $values;
}
+
/**
* Returns a translated string if one is found; Otherwise, the submitted message.
*
@@ -605,6 +630,7 @@ if (!function_exists('file_put_contents')) {
return I18n::translate($singular);
}
}
+
/**
* Returns correct plural form of message identified by $singular and $plural for count $count.
* Some languages have more than one form for plural messages dependent on the count.
@@ -624,11 +650,12 @@ if (!function_exists('file_put_contents')) {
}
if ($return === false) {
- echo I18n::translate($singular, $plural, null, 5, $count);
+ echo I18n::translate($singular, $plural, null, 6, $count);
} else {
- return I18n::translate($singular, $plural, null, 5, $count);
+ return I18n::translate($singular, $plural, null, 6, $count);
}
}
+
/**
* Allows you to override the current domain for a single message lookup.
*
@@ -651,6 +678,7 @@ if (!function_exists('file_put_contents')) {
return I18n::translate($msg, null, $domain);
}
}
+
/**
* Allows you to override the current domain for a single plural message lookup.
* Returns correct plural form of message identified by $singular and $plural for count $count
@@ -672,11 +700,12 @@ if (!function_exists('file_put_contents')) {
}
if ($return === false) {
- echo I18n::translate($singular, $plural, $domain, 5, $count);
+ echo I18n::translate($singular, $plural, $domain, 6, $count);
} else {
- return I18n::translate($singular, $plural, $domain, 5, $count);
+ return I18n::translate($singular, $plural, $domain, 6, $count);
}
}
+
/**
* Allows you to override the current domain for a single message lookup.
* It also allows you to specify a category.
@@ -713,6 +742,7 @@ if (!function_exists('file_put_contents')) {
return I18n::translate($msg, null, $domain, $category);
}
}
+
/**
* Allows you to override the current domain for a single plural message lookup.
* It also allows you to specify a category.
@@ -723,13 +753,13 @@ if (!function_exists('file_put_contents')) {
* Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
*
* Note that the category must be specified with a numeric value, instead of the constant name. The values are:
- * LC_CTYPE 0
- * LC_NUMERIC 1
- * LC_TIME 2
- * LC_COLLATE 3
- * LC_MONETARY 4
- * LC_MESSAGES 5
- * LC_ALL 6
+ * LC_ALL 0
+ * LC_COLLATE 1
+ * LC_CTYPE 2
+ * LC_MONETARY 3
+ * LC_NUMERIC 4
+ * LC_TIME 5
+ * LC_MESSAGES 6
*
* @param string $domain Domain
* @param string $singular Singular string to translate
@@ -753,6 +783,7 @@ if (!function_exists('file_put_contents')) {
return I18n::translate($singular, $plural, $domain, $category, $count);
}
}
+
/**
* The category argument allows a specific category of the locale settings to be used for fetching a message.
* Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL.
@@ -785,6 +816,7 @@ if (!function_exists('file_put_contents')) {
return I18n::translate($msg, null, null, $category);
}
}
+
/**
* Computes the difference of arrays using keys for comparison.
*
@@ -819,6 +851,7 @@ if (!function_exists('file_put_contents')) {
return $valuesDiff;
}
}
+
/**
* Computes the intersection of arrays using keys for comparison
*
@@ -837,6 +870,7 @@ if (!function_exists('file_put_contents')) {
return $res;
}
}
+
/**
* Shortcut to Log::write.
*
@@ -850,6 +884,7 @@ if (!function_exists('file_put_contents')) {
$good = ' ';
CakeLog::write('error', str_replace($bad, $good, $message));
}
+
/**
* Searches include path for files.
*
@@ -870,6 +905,7 @@ if (!function_exists('file_put_contents')) {
}
return false;
}
+
/**
* Convert forward slashes to underscores and removes first and last underscores in a string
*
@@ -883,6 +919,7 @@ if (!function_exists('file_put_contents')) {
$string = str_replace('/', '_', $string);
return $string;
}
+
/**
* Implements http_build_query for PHP4.
*
@@ -922,6 +959,7 @@ if (!function_exists('file_put_contents')) {
return implode($argSep, $out);
}
}
+
/**
* Wraps ternary operations. If $condition is a non-empty value, $val1 is returned, otherwise $val2.
* Don't use for isset() conditions, or wrap your variable with @ operator:
diff --git a/cake/config/paths.php b/cake/config/paths.php
index 6a6449f0e..4a29fadab 100644
--- a/cake/config/paths.php
+++ b/cake/config/paths.php
@@ -1,5 +1,6 @@
__construct($args);
}
+
/**
* 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.
*
@@ -154,6 +176,7 @@ class ShellDispatcher {
}
require_once(CORE_PATH . 'cake' . DS . 'basics.php');
}
+
/**
* Defines current working environment.
*
@@ -190,6 +213,7 @@ class ShellDispatcher {
$this->shiftArgs();
}
+
/**
* Builds the shell paths.
*
@@ -224,6 +248,7 @@ class ShellDispatcher {
$this->shellPaths = array_values(array_unique(array_merge($paths, App::path('shells'))));
}
+
/**
* Initializes the environment and loads the Cake core.
*
@@ -259,129 +284,163 @@ class ShellDispatcher {
Configure::getInstance(file_exists(CONFIGS . 'bootstrap.php'));
if (!file_exists(APP_PATH . 'config' . DS . 'core.php')) {
- include_once CORE_PATH . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
- Configure::buildPaths(array());
+ include_once CORE_PATH . 'cake' . DS . 'console' . DS . 'libs' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
+ App::build();
}
Configure::write('debug', 1);
return true;
}
+
+/**
+ * Clear the console
+ *
+ * @return void
+ * @access public
+ */
+ function clear() {
+ if (empty($this->params['noclear'])) {
+ if ( DS === '/') {
+ passthru('clear');
+ } else {
+ passthru('cls');
+ }
+ }
+ }
+
/**
* Dispatches a CLI request
*
+ * @return boolean
* @access public
*/
function dispatch() {
- if (isset($this->args[0])) {
- $plugin = null;
- $shell = $this->args[0];
- if (strpos($shell, '.') !== false) {
- list($plugin, $shell) = explode('.', $this->args[0]);
- }
+ $arg = $this->shiftArgs();
- $this->shell = $shell;
- $this->shiftArgs();
- $this->shellName = Inflector::camelize($this->shell);
- $this->shellClass = $this->shellName . 'Shell';
-
- 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 ($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);
-
- $privateMethod = $missingCommand = false;
- if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
- $privateMethod = true;
- }
-
- if (!in_array($command, $classMethods) && !in_array(strtolower($command), $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'
- );
-
- if (in_array(strtolower($command), $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();
- }
- }
- } else {
+ if (!$arg) {
$this->help();
+ return false;
}
+ if ($arg == 'help') {
+ $this->help();
+ return true;
+ }
+
+ if (strpos($arg, '.') !== false) {
+ list($plugin, $shell) = explode('.', $arg);
+ } else {
+ $plugin = null;
+ $shell = $arg;
+ }
+ $this->shell = $shell;
+ $this->shellName = Inflector::camelize($shell);
+ $this->shellClass = $this->shellName . 'Shell';
+
+ $arg = null;
+
+ if (isset($this->args[0])) {
+ $arg = $this->args[0];
+ $this->shellCommand = Inflector::variable($arg);
+ }
+
+ $Shell = $this->_getShell($plugin);
+
+ if (!$Shell) {
+ $title = sprintf(__('Error: Class %s could not be loaded.', true), $this->shellClass);
+ $this->stderr($title . "\n");
+ return false;
+ }
+
+ $methods = array();
+
+ 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();
+ }
+ }
+
+ $task = Inflector::camelize($arg);
+
+ 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();
+ }
+ $methods = array_diff(get_class_methods('Shell'), array('help'));
+ }
+ $methods = array_diff(get_class_methods($Shell), $methods);
+ $added = in_array(strtolower($arg), array_map('strtolower', $methods));
+ $private = $arg[0] == '_' && method_exists($Shell, $arg);
+
+ if (!$private) {
+ if ($added) {
+ $this->shiftArgs();
+ $Shell->startup();
+ return $Shell->{$arg}();
+ }
+ if (method_exists($Shell, 'main')) {
+ $Shell->startup();
+ return $Shell->main();
+ }
+ }
+
+ $title = sprintf(__('Error: Unknown %1$s command %2$s.', true), $this->shellName, $arg);
+ $message = sprintf(__('For usage try `cake %s help`', true), $this->shell);
+ $this->stderr($title . "\n" . $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;
+ }
+ }
+ 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.
*
@@ -415,6 +474,7 @@ class ShellDispatcher {
}
return $result;
}
+
/**
* Outputs to the stdout filehandle.
*
@@ -429,6 +489,7 @@ class ShellDispatcher {
fwrite($this->stdout, $string);
}
}
+
/**
* Outputs to the stderr filehandle.
*
@@ -436,8 +497,9 @@ class ShellDispatcher {
* @access public
*/
function stderr($string) {
- fwrite($this->stderr, 'Error: '. $string);
+ fwrite($this->stderr, $string);
}
+
/**
* Parses command line options
*
@@ -446,13 +508,15 @@ class ShellDispatcher {
*/
function parseParams($params) {
$this->__parseParams($params);
-
$defaults = array('app' => 'app', 'root' => dirname(dirname(dirname(__FILE__))), 'working' => null, 'webroot' => 'webroot');
-
$params = array_merge($defaults, array_intersect_key($this->params, $defaults));
-
- $isWin = array_filter(array_map('strpos', $params, array('\\')));
-
+ $isWin = false;
+ foreach ($defaults as $default => $value) {
+ if (strpos($params[$default], '\\') !== false) {
+ $isWin = true;
+ break;
+ }
+ }
$params = str_replace('\\', '/', $params);
if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
@@ -464,7 +528,7 @@ class ShellDispatcher {
}
}
- if ($params['app'][0] == '/' || preg_match('/([a-zA-Z])(:)/i', $params['app'], $matches)) {
+ if ($params['app'][0] == '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
$params['root'] = dirname($params['app']);
} elseif (strpos($params['app'], '/')) {
$params['root'] .= '/' . dirname($params['app']);
@@ -479,8 +543,9 @@ class ShellDispatcher {
$this->params = array_merge($this->params, $params);
}
+
/**
- * Helper for recursively paraing params
+ * Helper for recursively parsing params
*
* @return array params
* @access private
@@ -510,26 +575,24 @@ class ShellDispatcher {
}
}
}
+
/**
* Removes first argument and shifts other arguments up
*
- * @return boolean False if there are no arguments
+ * @return mixed Null if there are no arguments otherwise the shifted argument
* @access public
*/
function shiftArgs() {
- if (empty($this->args)) {
- return false;
- }
- unset($this->args[0]);
- $this->args = array_values($this->args);
- return true;
+ return array_shift($this->args);
}
+
/**
* Shows console help
*
* @access public
*/
function help() {
+ $this->clear();
$this->stdout("\nWelcome to CakePHP v" . Configure::version() . " Console");
$this->stdout("---------------------------------------------------------------");
$this->stdout("Current Paths:");
@@ -559,6 +622,7 @@ class ShellDispatcher {
} else {
sort($shells);
foreach ($shells as $shell) {
+
if ($shell !== 'shell.php') {
$this->stdout("\t " . str_replace('.php', '', $shell));
}
@@ -568,8 +632,8 @@ class ShellDispatcher {
}
$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
*
diff --git a/cake/console/error.php b/cake/console/error.php
index 9c88a40b8..4d9a9f7a5 100644
--- a/cake/console/error.php
+++ b/cake/console/error.php
@@ -1,5 +1,6 @@
stderr($code . $name . $message."\n");
$this->_stop();
}
+
/**
* Convenience method to display a 404 page.
*
@@ -84,6 +91,7 @@ class ErrorHandler extends Object {
'message' => sprintf(__("The requested address %s was not found on this server.", true), $url, $message)));
$this->_stop();
}
+
/**
* Renders the Missing Controller web page.
*
@@ -96,6 +104,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Controller '%s'", true), $controllerName));
$this->_stop();
}
+
/**
* Renders the Missing Action web page.
*
@@ -107,6 +116,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Method '%s' in '%s'", true), $action, $className));
$this->_stop();
}
+
/**
* Renders the Private Action web page.
*
@@ -118,6 +128,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Trying to access private method '%s' in '%s'", true), $action, $className));
$this->_stop();
}
+
/**
* Renders the Missing Table web page.
*
@@ -129,6 +140,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing database table '%s' for model '%s'", true), $table, $className));
$this->_stop();
}
+
/**
* Renders the Missing Database web page.
*
@@ -139,6 +151,7 @@ class ErrorHandler extends Object {
$this->stderr(__("Missing Database", true));
$this->_stop();
}
+
/**
* Renders the Missing View web page.
*
@@ -150,6 +163,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing View '%s' for '%s' in '%s'", true), $file, $action, $className));
$this->_stop();
}
+
/**
* Renders the Missing Layout web page.
*
@@ -161,6 +175,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Layout '%s'", true), $file));
$this->_stop();
}
+
/**
* Renders the Database Connection web page.
*
@@ -172,6 +187,7 @@ class ErrorHandler extends Object {
$this->stderr(__("Missing Database Connection. Try 'cake bake'", true));
$this->_stop();
}
+
/**
* Renders the Missing Helper file web page.
*
@@ -183,6 +199,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Helper file '%s' for '%s'", true), $file, Inflector::camelize($helper)));
$this->_stop();
}
+
/**
* Renders the Missing Helper class web page.
*
@@ -194,6 +211,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Helper class '%s' in '%s'", true), Inflector::camelize($helper), $file));
$this->_stop();
}
+
/**
* Renders the Missing Component file web page.
*
@@ -205,6 +223,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Component file '%s' for '%s'", true), $file, Inflector::camelize($component)));
$this->_stop();
}
+
/**
* Renders the Missing Component class web page.
*
@@ -216,6 +235,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing Component class '%s' in '%s'", true), Inflector::camelize($component), $file));
$this->_stop();
}
+
/**
* Renders the Missing Model class web page.
*
@@ -227,6 +247,7 @@ class ErrorHandler extends Object {
$this->stderr(sprintf(__("Missing model '%s'", true), $className));
$this->_stop();
}
+
/**
* Outputs to the stdout filehandle.
*
@@ -241,6 +262,7 @@ class ErrorHandler extends Object {
fwrite($this->stdout, $string);
}
}
+
/**
* Outputs to the stderr filehandle.
*
diff --git a/cake/console/libs/acl.php b/cake/console/libs/acl.php
index 5a7873da8..c62f91ba3 100644
--- a/cake/console/libs/acl.php
+++ b/cake/console/libs/acl.php
@@ -1,5 +1,6 @@
'", true);
$this->out($out);
}
+
/**
* Creates an ARO/ACO node
*
@@ -179,6 +188,7 @@ class AclShell extends Shell {
$this->err(sprintf(__("There was a problem creating a new %s '%s'.", true), $class, $this->args[2]));
}
}
+
/**
* Delete an ARO/ACO node.
*
@@ -216,6 +226,7 @@ class AclShell extends Shell {
$this->out(sprintf(__("Node parent set to %s", true), $this->args[2]) . "\n", true);
}
}
+
/**
* Get path to specified ARO/ACO node.
*
@@ -234,6 +245,7 @@ class AclShell extends Shell {
$this->out(str_repeat(' ', $i) . "[" . $nodes[$i][$class]['id'] . "]" . $nodes[$i][$class]['alias'] . "\n");
}
}
+
/**
* Check permission for a given ARO to a given ACO.
*
@@ -249,6 +261,7 @@ class AclShell extends Shell {
$this->out(sprintf(__("%s is not allowed.", true), $aro), true);
}
}
+
/**
* Grant permission for a given ARO to a given ACO.
*
@@ -264,6 +277,7 @@ class AclShell extends Shell {
$this->out(__("Permission was not granted.", true), true);
}
}
+
/**
* Deny access for an ARO to an ACO.
*
@@ -279,6 +293,7 @@ class AclShell extends Shell {
$this->out(__("Permission was not denied.", true), true);
}
}
+
/**
* Set an ARO to inhermit permission to an ACO.
*
@@ -294,6 +309,7 @@ class AclShell extends Shell {
$this->out(__("Permission was not inherited.", true), true);
}
}
+
/**
* Show a specific ARO/ACO node.
*
@@ -345,6 +361,7 @@ class AclShell extends Shell {
}
$this->hr();
}
+
/**
* Initialize ACL database.
*
@@ -354,6 +371,7 @@ class AclShell extends Shell {
$this->Dispatch->args = array('schema', 'run', 'create', 'DbAcl');
$this->Dispatch->dispatch();
}
+
/**
* Show help screen.
*
@@ -431,6 +449,7 @@ class AclShell extends Shell {
$this->out(sprintf(__("Command '%s' not found", true), $this->args[0]));
}
}
+
/**
* Check that first argument specifies a valid Node type (ARO/ACO)
*
@@ -444,6 +463,7 @@ class AclShell extends Shell {
$this->error(sprintf(__("Missing/Unknown node type: '%s'", true), $this->args[1]), __('Please specify which ACL object type you wish to create.', true));
}
}
+
/**
* Checks that given node exists
*
@@ -465,6 +485,7 @@ class AclShell extends Shell {
}
return $possibility;
}
+
/**
* get params for standard Acl methods
*
diff --git a/cake/console/libs/api.php b/cake/console/libs/api.php
index 7ff0d73e0..8da6f9092 100644
--- a/cake/console/libs/api.php
+++ b/cake/console/libs/api.php
@@ -1,5 +1,6 @@
LIBS
));
}
+
/**
* Override main() to handle action
*
@@ -66,7 +70,7 @@ class ApiShell extends Shell {
return $this->help();
}
- $type = low($this->args[0]);
+ $type = strtolower($this->args[0]);
if (isset($this->paths[$type])) {
$path = $this->paths[$type];
@@ -202,7 +206,7 @@ class ApiShell extends Shell {
if (strpos($method, '__') === false && $method[0] != '_') {
$parsed[$method] = array(
- 'comment' => r(array('/*', '*/', '*'), '', trim($result[1][$key])),
+ 'comment' => str_replace(array('/*', '*/', '*'), '', trim($result[1][$key])),
'method' => $method,
'parameters' => trim($result[3][$key])
);
diff --git a/cake/console/libs/bake.php b/cake/console/libs/bake.php
index f891ca2a4..bc15e6360 100644
--- a/cake/console/libs/bake.php
+++ b/cake/console/libs/bake.php
@@ -1,5 +1,4 @@
command);
if (isset($this->{$task}) && !in_array($task, array('Project', 'DbConfig'))) {
- $path = Inflector::underscore(Inflector::pluralize($this->command));
- $this->{$task}->path = $this->params['working'] . DS . $path . DS;
+ if (empty($this->{$task}->path)) {
+ $path = Inflector::underscore(Inflector::pluralize($this->command));
+ $this->{$task}->path = $this->params['working'] . DS . $path . DS;
+ }
+ if (isset($this->params['connection'])) {
+ $this->{$task}->connection = $this->params['connection'];
+ }
+ if (isset($this->params['plugin'])) {
+ $this->{$task}->plugin = $this->params['plugin'];
+ }
if (!is_dir($this->{$task}->path)) {
$this->err(sprintf(__("%s directory could not be found.\nBe sure you have created %s", true), $task, $this->{$task}->path));
$this->_stop();
}
}
}
+
/**
* Override main() to handle action
*
@@ -82,6 +90,7 @@ class BakeShell extends Shell {
$this->out('[V]iew');
$this->out('[C]ontroller');
$this->out('[P]roject');
+ $this->out('[F]ixture');
$this->out('[Q]uit');
$classToBake = strtoupper($this->in(__('What would you like to Bake?', true), array('D', 'M', 'V', 'C', 'P', 'Q')));
@@ -101,6 +110,9 @@ class BakeShell extends Shell {
case 'P':
$this->Project->execute();
break;
+ case 'F':
+ $this->Fixture->execute();
+ break;
case 'Q':
exit(0);
break;
@@ -110,28 +122,33 @@ class BakeShell extends Shell {
$this->hr();
$this->main();
}
+
/**
* Quickly bake the MVC
*
* @access public
*/
function all() {
- $ds = 'default';
$this->hr();
$this->out('Bake All');
$this->hr();
- if (isset($this->params['connection'])) {
- $ds = $this->params['connection'];
+ if (!isset($this->params['connection']) && empty($this->connection)) {
+ $this->connection = $this->DbConfig->getConfig();
}
if (empty($this->args)) {
- $name = $this->Model->getName($ds);
+ $this->Model->interactive = true;
+ $name = $this->Model->getName($this->connection);
+ }
+
+ foreach (array('Model', 'Controller', 'View') as $task) {
+ $this->{$task}->connection = $this->connection;
+ $this->{$task}->interactive = false;
}
if (!empty($this->args[0])) {
$name = $this->args[0];
- $this->Model->listAll($ds, false);
}
$modelExists = false;
@@ -140,8 +157,8 @@ class BakeShell extends Shell {
$object = new $model();
$modelExists = true;
} else {
- App::import('Model');
- $object = new Model(array('name' => $name, 'ds' => $ds));
+ App::import('Model', 'Model', false);
+ $object = new Model(array('name' => $name, 'ds' => $this->connection));
}
$modelBaked = $this->Model->bake($object, false);
@@ -149,6 +166,7 @@ class BakeShell extends Shell {
if ($modelBaked && $modelExists === false) {
$this->out(sprintf(__('%s Model was baked.', true), $model));
if ($this->_checkUnitTest()) {
+ $this->Model->bakeFixture($model);
$this->Model->bakeTest($model);
}
$modelExists = true;
@@ -165,16 +183,13 @@ class BakeShell extends Shell {
if (App::import('Controller', $controller)) {
$this->View->args = array($controller);
$this->View->execute();
+ $this->out(sprintf(__('%s Views were baked.', true), $name));
}
- $this->out(__('Bake All complete'));
+ $this->out(__('Bake All complete', true));
array_shift($this->args);
} else {
$this->err(__('Bake All could not continue without a valid model', true));
}
-
- if (empty($this->args)) {
- $this->all();
- }
$this->_stop();
}
diff --git a/cake/console/libs/console.php b/cake/console/libs/console.php
index b9f2e6e96..82427d9b4 100644
--- a/cake/console/libs/console.php
+++ b/cake/console/libs/console.php
@@ -1,5 +1,6 @@
_loadRoutes();
}
+
/**
* Prints the help message
*
@@ -136,6 +143,7 @@ class ConsoleShell extends Shell {
$out .= "\tRoutes show";
$this->out($out);
}
+
/**
* Override main() to handle action
*
@@ -269,8 +277,7 @@ class ConsoleShell extends Shell {
if ($this->_isValidModel($modelToSave)) {
// Extract the array of data we are trying to build
list($foo, $data) = explode("->save", $command);
- $badChars = array("(", ")");
- $data = str_replace($badChars, "", $data);
+ $data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
$saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
@eval($saveCommand);
$this->out('Saved record for ' . $modelToSave);
@@ -321,6 +328,7 @@ class ConsoleShell extends Shell {
$command = '';
}
}
+
/**
* Tells if the specified model is included in the list of available models
*
@@ -331,6 +339,7 @@ class ConsoleShell extends Shell {
function _isValidModel($modelToCheck) {
return in_array($modelToCheck, $this->models);
}
+
/**
* Reloads the routes configuration from config/routes.php, and compiles
* all routes found
diff --git a/cake/console/libs/i18n.php b/cake/console/libs/i18n.php
index aa5fe8b8a..5e8d547ed 100644
--- a/cake/console/libs/i18n.php
+++ b/cake/console/libs/i18n.php
@@ -1,5 +1,6 @@
hr();
$this->main();
}
+
/**
* Initialize I18N database.
*
@@ -105,6 +112,7 @@ class I18nShell extends Shell {
$this->Dispatch->args = array('schema', 'run', 'create', 'i18n');
$this->Dispatch->dispatch();
}
+
/**
* Show help screen.
*
diff --git a/cake/console/libs/schema.php b/cake/console/libs/schema.php
index 445ad1579..60d959721 100644
--- a/cake/console/libs/schema.php
+++ b/cake/console/libs/schema.php
@@ -1,5 +1,6 @@
out('Cake Schema Shell');
$this->hr();
}
+
/**
* Override startup
*
@@ -85,6 +90,7 @@ class SchemaShell extends Shell {
$this->Schema =& new CakeSchema(compact('name', 'path', 'file', 'connection'));
}
+
/**
* Override main
*
@@ -93,6 +99,7 @@ class SchemaShell extends Shell {
function main() {
$this->help();
}
+
/**
* Read and output contents of schema object
* path to read as second arg
@@ -109,6 +116,7 @@ class SchemaShell extends Shell {
$this->_stop();
}
}
+
/**
* Read database and Write schema object
* accepts a connection as first arg or path to save as second arg
@@ -177,6 +185,7 @@ class SchemaShell extends Shell {
$this->_stop();
}
}
+
/**
* Dump Schema object to sql file
* if first arg == write, file will be written to sql file
@@ -199,7 +208,7 @@ class SchemaShell extends Shell {
}
}
$db =& ConnectionManager::getDataSource($this->Schema->connection);
- $contents = "#". $Schema->name ." sql generated on: " . date('Y-m-d H:m:s') . " : ". time()."\n\n";
+ $contents = "#" . $Schema->name . " sql generated on: " . date('Y-m-d H:i:s') . " : " . time() . "\n\n";
$contents .= $db->dropSchema($Schema) . "\n\n". $db->createSchema($Schema);
if ($write) {
if (strpos($write, '.sql') === false) {
@@ -217,6 +226,7 @@ class SchemaShell extends Shell {
$this->out($contents);
return $contents;
}
+
/**
* Run database commands: create, update
*
@@ -275,6 +285,7 @@ class SchemaShell extends Shell {
$this->_stop();
}
}
+
/**
* Create database from Schema object
* Should be called via the run method
@@ -318,6 +329,7 @@ class SchemaShell extends Shell {
$this->out(__('End create.', true));
}
+
/**
* Update database with Schema object
* Should be called via the run method
@@ -356,6 +368,7 @@ class SchemaShell extends Shell {
$this->out(__('End update.', true));
}
+
/**
* Runs sql from __create() or __update()
*
@@ -397,6 +410,7 @@ class SchemaShell extends Shell {
}
}
}
+
/**
* Displays help contents
*
@@ -426,4 +440,4 @@ class SchemaShell extends Shell {
$this->_stop();
}
}
-?>
+?>
\ No newline at end of file
diff --git a/cake/console/libs/shell.php b/cake/console/libs/shell.php
index bac6c347b..503a63111 100644
--- a/cake/console/libs/shell.php
+++ b/cake/console/libs/shell.php
@@ -1,5 +1,6 @@
name, $this->alias);
if (!PHP5 && isset($this->args[0])) {
- if (strpos($this->name, low(Inflector::camelize($this->args[0]))) !== false) {
+ if (strpos($this->name, strtolower(Inflector::camelize($this->args[0]))) !== false) {
$dispatch->shiftArgs();
}
- if (low($this->command) == low(Inflector::variable($this->args[0])) && method_exists($this, $this->command)) {
+ if (strtolower($this->command) == strtolower(Inflector::variable($this->args[0])) && method_exists($this, $this->command)) {
$dispatch->shiftArgs();
}
}
$this->Dispatch =& $dispatch;
}
+
/**
* Initializes the Shell
* acts as constructor for subclasses
@@ -169,6 +186,7 @@ class Shell extends Object {
function initialize() {
$this->_loadModels();
}
+
/**
* Starts up the the Shell
* allows for checking and configuring prior to command or main execution
@@ -179,18 +197,21 @@ class Shell extends Object {
function startup() {
$this->_welcome();
}
+
/**
* Displays a header for the shell
*
* @access protected
*/
function _welcome() {
+ $this->Dispatch->clear();
$this->out("\nWelcome to CakePHP v" . Configure::version() . " Console");
$this->out("---------------------------------------------------------------");
$this->out('App : '. $this->params['app']);
$this->out('Path: '. $this->params['working']);
$this->hr();
}
+
/**
* Loads database file and constructs DATABASE_CONFIG class
* makes $this->DbConfig available to subclasses
@@ -207,6 +228,7 @@ class Shell extends Object {
$this->out('Run \'bake\' to create the database configuration');
return false;
}
+
/**
* if var $uses = true
* Loads AppModel file and constructs AppModel class
@@ -251,6 +273,7 @@ class Shell extends Object {
}
return false;
}
+
/**
* Loads tasks defined in var $tasks
*
@@ -297,13 +320,14 @@ class Shell extends Object {
}
if (!isset($this->{$taskName})) {
- $this->err("Task '".$taskName."' could not be loaded");
+ $this->err("Task '" . $taskName . "' could not be loaded");
$this->_stop();
}
}
return true;
}
+
/**
* Prompts the user for input, and returns it.
*
@@ -329,7 +353,7 @@ class Shell extends Object {
}
}
if (is_array($options)) {
- while ($in == '' || ($in && (!in_array(low($in), $options) && !in_array(up($in), $options)) && !in_array($in, $options))) {
+ while ($in == '' || ($in && (!in_array(strtolower($in), $options) && !in_array(strtoupper($in), $options)) && !in_array($in, $options))) {
$in = $this->Dispatch->getInput($prompt, $options, $default);
}
}
@@ -337,68 +361,82 @@ class Shell extends Object {
return $in;
}
}
+
/**
- * Outputs to the stdout filehandle.
+ * Outputs a single or multiple messages to stdout.
*
- * @param string $string String to output.
- * @param boolean $newline If true, the outputs gets an added newline.
+ * @param mixed $message A string or a an array of strings to output
+ * @param mixed $after Appended to message, if true a newline is used
* @access public
*/
- function out($string, $newline = true) {
- if (is_array($string)) {
- $str = '';
- foreach ($string as $message) {
- $str .= $message ."\n";
- }
- $string = $str;
+ function out($message, $after = true) {
+ if (is_array($message)) {
+ $message = implode($this->nl(), $message);
}
- return $this->Dispatch->stdout($string, $newline);
+ $this->Dispatch->stdout($message . $this->nl($after), false);
}
+
/**
- * Outputs to the stderr filehandle.
+ * Outputs a single or multiple error messages to stderr.
*
- * @param string $string Error text to output.
+ * @param mixed $message A string or a an array of strings to output
+ * @param mixed $after Appended to message, if true a newline is used
* @access public
*/
- function err($string) {
- if (is_array($string)) {
- $str = '';
- foreach ($string as $message) {
- $str .= $message ."\n";
- }
- $string = $str;
+ function err($message, $after = true) {
+ if (is_array($message)) {
+ $message = implode($this->nl(), $message);
}
- return $this->Dispatch->stderr($string."\n");
+ $this->Dispatch->stderr($message . $this->nl($after));
}
+
+/**
+ * Returns a single or multiple linefeeds sequences.
+ *
+ * @param mixed $format If true returns a linefeed sequence, if false null,
+ * if a string is given that is returned,
+ * if an integer is given it is used as a multiplier to return multiple linefeed sequences
+ * @access public
+ * @return string
+ */
+ function nl($format = true) {
+ if (is_string($format)) {
+ return $format . "\n";
+ }
+ if (is_int($format)) {
+ return str_repeat("\n", $format);
+ }
+ return $format ? "\n" : null;
+ }
+
/**
* Outputs a series of minus characters to the standard output, acts as a visual separator.
*
- * @param boolean $newline If true, the outputs gets an added newline.
+ * @param mixed $surround If true, the outputs gets surrounded by newlines.
* @access public
*/
- function hr($newline = false) {
- if ($newline) {
- $this->out("\n");
- }
+ function hr($surround = false) {
+ $this->out(null, $surround);
$this->out('---------------------------------------------------------------');
- if ($newline) {
- $this->out("\n");
- }
+ $this->out(null, $surround);
}
/**
- * Displays a formatted error message and exits the application
+ * Displays a formatted error message
+ * and exits the application with status code 1
*
- * @param string $title Title of the error message
- * @param string $msg Error message
+ * @param string $title Title of the error
+ * @param string $message An optional error message
* @access public
*/
- function error($title, $msg) {
- $out = "$title\n";
- $out .= "$msg\n";
- $out .= "\n";
- $this->err($out);
- $this->_stop();
+ function error($title, $message = null) {
+ $this->err(sprintf(__('Error: %s', true), $title));
+
+ if (!empty($message)) {
+ $this->err($message);
+ }
+ $this->_stop(1);
}
+
/**
* Will check the number args matches otherwise throw an error
*
@@ -414,6 +452,7 @@ class Shell extends Object {
$this->error("Wrong number of parameters: ".count($this->args), "Expected: {$expectedNum}\nPlease type 'cake {$this->shell} help' for help on usage of the {$this->name} {$command}");
}
}
+
/**
* Creates a file at given path
*
@@ -427,10 +466,10 @@ class Shell extends Object {
$this->out("\n" . sprintf(__("Creating file %s", true), $path));
if (is_file($path) && $this->interactive === true) {
$key = $this->in(__("File exists, overwrite?", true). " {$path}", array('y', 'n', 'q'), 'n');
- if (low($key) == 'q') {
+ if (strtolower($key) == 'q') {
$this->out(__("Quitting.", true) ."\n");
exit;
- } elseif (low($key) != 'y') {
+ } elseif (strtolower($key) != 'y') {
$this->out(__("Skip", true) ." {$path}\n");
return false;
}
@@ -449,6 +488,7 @@ class Shell extends Object {
return false;
}
}
+
/**
* Outputs usage text on the standard output. Implement it in subclasses.
*
@@ -461,6 +501,7 @@ class Shell extends Object {
$this->Dispatch->help();
}
}
+
/**
* Action to create a Unit Test
*
@@ -472,13 +513,14 @@ class Shell extends Object {
return true;
}
$unitTest = $this->in('SimpleTest is not installed. Do you want to bake unit test files anyway?', array('y','n'), 'y');
- $result = low($unitTest) == 'y' || low($unitTest) == 'yes';
+ $result = strtolower($unitTest) == 'y' || strtolower($unitTest) == 'yes';
if ($result) {
$this->out("\nYou can download SimpleTest from http://simpletest.org", true);
}
return $result;
}
+
/**
* Makes absolute file path easier to read
*
@@ -488,38 +530,10 @@ class Shell extends Object {
*/
function shortPath($file) {
$shortPath = str_replace(ROOT, null, $file);
- $shortPath = str_replace('..'.DS, '', $shortPath);
- return r(DS.DS, DS, $shortPath);
- }
-/**
- * Checks for Configure::read('Routing.admin') and forces user to input it if not enabled
- *
- * @return string Admin route to use
- * @access public
- */
- function getAdmin() {
- $admin = '';
- $cakeAdmin = null;
- $adminRoute = Configure::read('Routing.admin');
- if (!empty($adminRoute)) {
- $cakeAdmin = $adminRoute . '_';
- } else {
- $this->out('You need to enable Configure::write(\'Routing.admin\',\'admin\') in /app/config/core.php to use admin routing.');
- $this->out('What would you like the admin route to be?');
- $this->out('Example: www.example.com/admin/controller');
- while ($admin == '') {
- $admin = $this->in("What would you like the admin route to be?", null, 'admin');
- }
- if ($this->Project->cakeAdmin($admin) !== true) {
- $this->out('Unable to write to /app/config/core.php.');
- $this->out('You need to enable Configure::write(\'Routing.admin\',\'admin\') in /app/config/core.php to use admin routing.');
- $this->_stop();
- } else {
- $cakeAdmin = $admin . '_';
- }
- }
- return $cakeAdmin;
+ $shortPath = str_replace('..' . DS, '', $shortPath);
+ return str_replace(DS . DS, DS, $shortPath);
}
+
/**
* Creates the proper controller path for the specified controller class name
*
@@ -528,8 +542,9 @@ class Shell extends Object {
* @access protected
*/
function _controllerPath($name) {
- return low(Inflector::underscore($name));
+ return strtolower(Inflector::underscore($name));
}
+
/**
* Creates the proper controller plural name for the specified controller class name
*
@@ -540,6 +555,7 @@ class Shell extends Object {
function _controllerName($name) {
return Inflector::pluralize(Inflector::camelize($name));
}
+
/**
* Creates the proper controller camelized name (singularized) for the specified name
*
@@ -550,6 +566,7 @@ class Shell extends Object {
function _modelName($name) {
return Inflector::camelize(Inflector::singularize($name));
}
+
/**
* Creates the proper singular model key for associations
*
@@ -560,6 +577,7 @@ class Shell extends Object {
function _modelKey($name) {
return Inflector::underscore(Inflector::singularize($name)).'_id';
}
+
/**
* Creates the proper model name from a foreign key
*
@@ -571,6 +589,7 @@ class Shell extends Object {
$name = str_replace('_id', '',$key);
return Inflector::camelize($name);
}
+
/**
* creates the singular name for use in views.
*
@@ -581,6 +600,7 @@ class Shell extends Object {
function _singularName($name) {
return Inflector::variable(Inflector::singularize($name));
}
+
/**
* Creates the plural name for views
*
@@ -591,6 +611,7 @@ class Shell extends Object {
function _pluralName($name) {
return Inflector::variable(Inflector::pluralize($name));
}
+
/**
* Creates the singular human name used in views
*
@@ -601,6 +622,7 @@ class Shell extends Object {
function _singularHumanName($name) {
return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
}
+
/**
* Creates the plural human name used in views
*
@@ -611,5 +633,22 @@ class Shell extends Object {
function _pluralHumanName($name) {
return Inflector::humanize(Inflector::underscore(Inflector::pluralize($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) {
+ $pluginPaths = App::path('plugins');
+ $pluginDirName = Inflector::underscore($pluginName);
+ foreach ($pluginPaths as $path) {
+ if (is_dir($path . $pluginDirName)) {
+ return $path . $pluginDirName . DS ;
+ }
+ }
+ return $pluginPaths[0] . $pluginDirName . DS;
+ }
}
?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/controller.php b/cake/console/libs/tasks/controller.php
index 81f4fafbe..25e63e404 100644
--- a/cake/console/libs/tasks/controller.php
+++ b/cake/console/libs/tasks/controller.php
@@ -1,5 +1,4 @@
args[0])) {
+ if (!isset($this->connection)) {
+ $this->connection = 'default';
+ }
+ if (strtolower($this->args[0]) == 'all') {
+ return $this->all();
+ }
$controller = Inflector::camelize($this->args[0]);
$actions = null;
if (isset($this->args[1]) && $this->args[1] == 'scaffold') {
- $this->out('Baking scaffold for ' . $controller);
+ $this->out(__('Baking scaffold for ', true) . $controller);
$actions = $this->bakeActions($controller);
} else {
$actions = 'scaffold';
}
if ((isset($this->args[1]) && $this->args[1] == 'admin') || (isset($this->args[2]) && $this->args[2] == 'admin')) {
- if ($admin = $this->getAdmin()) {
+ if ($admin = $this->Project->getAdmin()) {
$this->out('Adding ' . Configure::read('Routing.admin') .' methods');
if ($actions == 'scaffold') {
$actions = $this->bakeActions($controller, $admin);
@@ -95,144 +103,169 @@ class ControllerTask extends Shell {
}
}
}
+
+/**
+ * Bake All the controllers at once. Will only bake controllers for models that exist.
+ *
+ * @access public
+ * @return void
+ **/
+ function all() {
+ $this->interactive = false;
+ $this->listAll($this->connection, false);
+ ClassRegistry::config('Model', array('ds' => $this->connection));
+ $unitTestExists = $this->_checkUnitTest();
+ foreach ($this->__tables as $table) {
+ $model = $this->_modelName($table);
+ $controller = $this->_controllerName($model);
+ if (App::import('Model', $model)) {
+ $actions = $this->bakeActions($controller);
+ if ($this->bake($controller, $actions) && $unitTestExists) {
+ $this->bakeTest($controller);
+ }
+ }
+ }
+ }
+
/**
* Interactive
*
* @access private
*/
- function __interactive($controllerName = false) {
- if (!$controllerName) {
- $this->interactive = true;
- $this->hr();
- $this->out(sprintf("Bake Controller\nPath: %s", $this->path));
- $this->hr();
- $actions = '';
- $uses = array();
- $helpers = array();
- $components = array();
- $wannaUseSession = 'y';
- $wannaDoAdmin = 'n';
- $wannaUseScaffold = 'n';
- $wannaDoScaffolding = 'y';
- $controllerName = $this->getName();
- }
+ function __interactive() {
+ $this->interactive = true;
$this->hr();
- $this->out("Baking {$controllerName}Controller");
+ $this->out(sprintf(__("Bake Controller\nPath: %s", true), $this->path));
$this->hr();
- $controllerFile = low(Inflector::underscore($controllerName));
+ if (empty($this->connection)) {
+ $this->connection = $this->DbConfig->getConfig();
+ }
+
+ $controllerName = $this->getName();
+ $this->hr();
+ $this->out(sprintf(__('Baking %sController', true), $controllerName));
+ $this->hr();
+
+ $helpers = $components = array();
+ $actions = '';
+ $wannaUseSession = 'y';
+ $wannaBakeAdminCrud = 'n';
+ $useDynamicScaffold = 'n';
+ $wannaBakeCrud = 'y';
+
+ $controllerFile = strtolower(Inflector::underscore($controllerName));
$question[] = __("Would you like to build your controller interactively?", true);
if (file_exists($this->path . $controllerFile .'_controller.php')) {
$question[] = sprintf(__("Warning: Choosing no will overwrite the %sController.", true), $controllerName);
}
- $doItInteractive = $this->in(join("\n", $question), array('y','n'), 'y');
+ $doItInteractive = $this->in(join("\n", $question), array('y', 'n'), 'y');
- if (low($doItInteractive) == 'y' || low($doItInteractive) == 'yes') {
+ if (strtolower($doItInteractive) == 'y') {
$this->interactive = true;
+ $useDynamicScaffold = $this->in(
+ __("Would you like to use dynamic scaffolding?", true), array('y','n'), 'n'
+ );
- $wannaUseScaffold = $this->in(__("Would you like to use scaffolding?", true), array('y','n'), 'n');
-
- if (low($wannaUseScaffold) == 'n' || low($wannaUseScaffold) == 'no') {
-
- $wannaDoScaffolding = $this->in(__("Would you like to include some basic class methods (index(), add(), view(), edit())?", true), array('y','n'), 'n');
-
- if (low($wannaDoScaffolding) == 'y' || low($wannaDoScaffolding) == 'yes') {
- $wannaDoAdmin = $this->in(__("Would you like to create the methods for admin routing?", true), array('y','n'), 'n');
- }
-
- $wannaDoHelpers = $this->in(__("Would you like this controller to use other helpers besides HtmlHelper and FormHelper?", true), array('y','n'), 'n');
-
- if (low($wannaDoHelpers) == 'y' || low($wannaDoHelpers) == 'yes') {
- $helpersList = $this->in(__("Please provide a comma separated list of the other helper names you'd like to use.\nExample: 'Ajax, Javascript, Time'", true));
- $helpersListTrimmed = str_replace(' ', '', $helpersList);
- $helpers = explode(',', $helpersListTrimmed);
- }
- $wannaDoComponents = $this->in(__("Would you like this controller to use any components?", true), array('y','n'), 'n');
-
- if (low($wannaDoComponents) == 'y' || low($wannaDoComponents) == 'yes') {
- $componentsList = $this->in(__("Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'", true));
- $componentsListTrimmed = str_replace(' ', '', $componentsList);
- $components = explode(',', $componentsListTrimmed);
- }
-
- $wannaUseSession = $this->in(__("Would you like to use Sessions?", true), array('y','n'), 'y');
+ if (strtolower($useDynamicScaffold) == 'y') {
+ $wannaBakeCrud = 'n';
+ $actions = 'scaffold';
} else {
- $wannaDoScaffolding = 'n';
+ list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
+
+ $helpers = $this->doHelpers();
+ $components = $this->doComponents();
+
+ $wannaUseSession = $this->in(
+ __("Would you like to use Session flash messages?", true), array('y','n'), 'y'
+ );
}
} else {
- $wannaDoScaffolding = $this->in(__("Would you like to include some basic class methods (index(), add(), view(), edit())?", true), array('y','n'), 'y');
-
- if (low($wannaDoScaffolding) == 'y' || low($wannaDoScaffolding) == 'yes') {
- $wannaDoAdmin = $this->in(__("Would you like to create the methods for admin routing?", true), array('y','n'), 'y');
- }
- }
- $admin = false;
-
- if ((low($wannaDoAdmin) == 'y' || low($wannaDoAdmin) == 'yes')) {
- $admin = $this->getAdmin();
+ list($wannaBakeCrud, $wannaBakeCrud) = $this->_askAboutMethods();
}
- if (low($wannaDoScaffolding) == 'y' || low($wannaDoScaffolding) == 'yes') {
- $actions = $this->bakeActions($controllerName, null, in_array(low($wannaUseSession), array('y', 'yes')));
- if ($admin) {
- $actions .= $this->bakeActions($controllerName, $admin, in_array(low($wannaUseSession), array('y', 'yes')));
- }
+ if (strtolower($wannaBakeCrud) == 'y') {
+ $actions = $this->bakeActions($controllerName, null, strtolower($wannaUseSession) == 'y');
+ }
+ if (strtolower($wannaBakeAdminCrud) == 'y') {
+ $admin = $this->Project->getAdmin();
+ $actions .= $this->bakeActions($controllerName, $admin, strtolower($wannaUseSession) == 'y');
}
if ($this->interactive === true) {
- $this->out('');
- $this->hr();
- $this->out('The following controller will be created:');
- $this->hr();
- $this->out("Controller Name: $controllerName");
-
- if (low($wannaUseScaffold) == 'y' || low($wannaUseScaffold) == 'yes') {
- $this->out(" var \$scaffold;");
- $actions = 'scaffold';
- }
-
- if (count($helpers)) {
- $this->out("Helpers: ", false);
-
- foreach ($helpers as $help) {
- if ($help != $helpers[count($helpers) - 1]) {
- $this->out(ucfirst($help) . ", ", false);
- } else {
- $this->out(ucfirst($help));
- }
- }
- }
-
- if (count($components)) {
- $this->out("Components: ", false);
-
- foreach ($components as $comp) {
- if ($comp != $components[count($components) - 1]) {
- $this->out(ucfirst($comp) . ", ", false);
- } else {
- $this->out(ucfirst($comp));
- }
- }
- }
- $this->hr();
+ $this->confirmController($controllerName, $useDynamicScaffold, $helpers, $components);
$looksGood = $this->in(__('Look okay?', true), array('y','n'), 'y');
- if (low($looksGood) == 'y' || low($looksGood) == 'yes') {
- $baked = $this->bake($controllerName, $actions, $helpers, $components, $uses);
+ if (strtolower($looksGood) == 'y') {
+ $baked = $this->bake($controllerName, $actions, $helpers, $components);
if ($baked && $this->_checkUnitTest()) {
$this->bakeTest($controllerName);
}
- } else {
- $this->__interactive($controllerName);
}
} else {
- $baked = $this->bake($controllerName, $actions, $helpers, $components, $uses);
+ $baked = $this->bake($controllerName, $actions, $helpers, $components);
if ($baked && $this->_checkUnitTest()) {
$this->bakeTest($controllerName);
}
}
}
+
+/**
+ * Confirm a to be baked controller with the user
+ *
+ * @return void
+ **/
+ function confirmController($controllerName, $useDynamicScaffold, $helpers, $components) {
+ $this->out('');
+ $this->hr();
+ $this->out(__('The following controller will be created:', true));
+ $this->hr();
+ $this->out(sprintf(__("Controller Name:\n\t%s", true), $controllerName));
+
+ if (strtolower($useDynamicScaffold) == 'y') {
+ $this->out("var \$scaffold;");
+ }
+
+ $properties = array(
+ 'helpers' => __("Helpers:", true),
+ 'components' => __('Components:', true),
+ );
+
+ foreach ($properties as $var => $title) {
+ if (count($$var)) {
+ $output = '';
+ $length = count($$var);
+ foreach ($$var as $i => $propElement) {
+ if ($i != $length -1) {
+ $output .= ucfirst($propElement) . ', ';
+ } else {
+ $output .= ucfirst($propElement);
+ }
+ }
+ $this->out($title . "\n\t" . $output);
+ }
+ }
+ $this->hr();
+ }
+
+/**
+ * Interact with the user and ask about which methods (admin or regular they want to bake)
+ *
+ * @return array Array containing (bakeRegular, bakeAdmin) answers
+ **/
+ function _askAboutMethods() {
+ $wannaBakeCrud = $this->in(
+ __("Would you like to create some basic class methods \n(index(), add(), view(), edit())?", true),
+ array('y','n'), 'n'
+ );
+ $wannaBakeAdminCrud = $this->in(
+ __("Would you like to create the basic class methods for admin routing?", true),
+ array('y','n'), 'n'
+ );
+ return array($wannaBakeCrud, $wannaBakeAdminCrud);
+ }
+
/**
* Bake scaffold actions
*
@@ -247,151 +280,24 @@ class ControllerTask extends Shell {
if ($this->plugin) {
$modelImport = $this->plugin . '.' . $modelImport;
}
- if (!App::import('Model', $modelImport)) {
- $this->err(__('You must have a model for this class to build scaffold methods. Please try again.', true));
- exit;
+ if (!App::import('Model', $currentModelName)) {
+ $this->err(__('You must have a model for this class to build basic methods. Please try again.', true));
+ $this->_stop();
}
- $actions = null;
- $modelObj =& new $currentModelName();
+
+ $modelObj =& ClassRegistry::init($currentModelName);
$controllerPath = $this->_controllerPath($controllerName);
$pluralName = $this->_pluralName($currentModelName);
$singularName = Inflector::variable($currentModelName);
$singularHumanName = Inflector::humanize($currentModelName);
$pluralHumanName = Inflector::humanize($controllerName);
- $actions .= "\n";
- $actions .= "\tfunction {$admin}index() {\n";
- $actions .= "\t\t\$this->{$currentModelName}->recursive = 0;\n";
- $actions .= "\t\t\$this->set('{$pluralName}', \$this->paginate());\n";
- $actions .= "\t}\n";
- $actions .= "\n";
- $actions .= "\tfunction {$admin}view(\$id = null) {\n";
- $actions .= "\t\tif (!\$id) {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\$this->Session->setFlash(__('Invalid {$singularHumanName}.', true));\n";
- $actions .= "\t\t\t\$this->redirect(array('action'=>'index'));\n";
- } else {
- $actions .= "\t\t\t\$this->flash(__('Invalid {$singularHumanName}', true), array('action'=>'index'));\n";
- }
- $actions .= "\t\t}\n";
- $actions .= "\t\t\$this->set('".$singularName."', \$this->{$currentModelName}->read(null, \$id));\n";
- $actions .= "\t}\n";
- $actions .= "\n";
- /* ADD ACTION */
- $compact = array();
- $actions .= "\tfunction {$admin}add() {\n";
- $actions .= "\t\tif (!empty(\$this->data)) {\n";
- $actions .= "\t\t\t\$this->{$currentModelName}->create();\n";
- $actions .= "\t\t\tif (\$this->{$currentModelName}->save(\$this->data)) {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\t\$this->Session->setFlash(__('The ".$singularHumanName." has been saved', true));\n";
- $actions .= "\t\t\t\t\$this->redirect(array('action'=>'index'));\n";
- } else {
- $actions .= "\t\t\t\t\$this->flash(__('{$currentModelName} saved.', true), array('action'=>'index'));\n";
- }
- $actions .= "\t\t\t} else {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\t\$this->Session->setFlash(__('The {$singularHumanName} could not be saved. Please, try again.', true));\n";
- }
- $actions .= "\t\t\t}\n";
- $actions .= "\t\t}\n";
- foreach ($modelObj->hasAndBelongsToMany as $associationName => $relation) {
- if (!empty($associationName)) {
- $habtmModelName = $this->_modelName($associationName);
- $habtmSingularName = $this->_singularName($associationName);
- $habtmPluralName = $this->_pluralName($associationName);
- $actions .= "\t\t\${$habtmPluralName} = \$this->{$currentModelName}->{$habtmModelName}->find('list');\n";
- $compact[] = "'{$habtmPluralName}'";
- }
- }
- foreach ($modelObj->belongsTo as $associationName => $relation) {
- if (!empty($associationName)) {
- $belongsToModelName = $this->_modelName($associationName);
- $belongsToPluralName = $this->_pluralName($associationName);
- $actions .= "\t\t\${$belongsToPluralName} = \$this->{$currentModelName}->{$belongsToModelName}->find('list');\n";
- $compact[] = "'{$belongsToPluralName}'";
- }
- }
- if (!empty($compact)) {
- $actions .= "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
- }
- $actions .= "\t}\n";
- $actions .= "\n";
-
- /* EDIT ACTION */
- $compact = array();
- $actions .= "\tfunction {$admin}edit(\$id = null) {\n";
- $actions .= "\t\tif (!\$id && empty(\$this->data)) {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\$this->Session->setFlash(__('Invalid {$singularHumanName}', true));\n";
- $actions .= "\t\t\t\$this->redirect(array('action'=>'index'));\n";
- } else {
- $actions .= "\t\t\t\$this->flash(__('Invalid {$singularHumanName}', true), array('action'=>'index'));\n";
- }
- $actions .= "\t\t}\n";
- $actions .= "\t\tif (!empty(\$this->data)) {\n";
- $actions .= "\t\t\tif (\$this->{$currentModelName}->save(\$this->data)) {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\t\$this->Session->setFlash(__('The ".$singularHumanName." has been saved', true));\n";
- $actions .= "\t\t\t\t\$this->redirect(array('action'=>'index'));\n";
- } else {
- $actions .= "\t\t\t\t\$this->flash(__('The ".$singularHumanName." has been saved.', true), array('action'=>'index'));\n";
- }
- $actions .= "\t\t\t} else {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\t\$this->Session->setFlash(__('The {$singularHumanName} could not be saved. Please, try again.', true));\n";
- }
- $actions .= "\t\t\t}\n";
- $actions .= "\t\t}\n";
- $actions .= "\t\tif (empty(\$this->data)) {\n";
- $actions .= "\t\t\t\$this->data = \$this->{$currentModelName}->read(null, \$id);\n";
- $actions .= "\t\t}\n";
-
- foreach ($modelObj->hasAndBelongsToMany as $associationName => $relation) {
- if (!empty($associationName)) {
- $habtmModelName = $this->_modelName($associationName);
- $habtmSingularName = $this->_singularName($associationName);
- $habtmPluralName = $this->_pluralName($associationName);
- $actions .= "\t\t\${$habtmPluralName} = \$this->{$currentModelName}->{$habtmModelName}->find('list');\n";
- $compact[] = "'{$habtmPluralName}'";
- }
- }
- foreach ($modelObj->belongsTo as $associationName => $relation) {
- if (!empty($associationName)) {
- $belongsToModelName = $this->_modelName($associationName);
- $belongsToPluralName = $this->_pluralName($associationName);
- $actions .= "\t\t\${$belongsToPluralName} = \$this->{$currentModelName}->{$belongsToModelName}->find('list');\n";
- $compact[] = "'{$belongsToPluralName}'";
- }
- }
- if (!empty($compact)) {
- $actions .= "\t\t\$this->set(compact(".join(',', $compact)."));\n";
- }
- $actions .= "\t}\n";
- $actions .= "\n";
- $actions .= "\tfunction {$admin}delete(\$id = null) {\n";
- $actions .= "\t\tif (!\$id) {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\$this->Session->setFlash(__('Invalid id for {$singularHumanName}', true));\n";
- $actions .= "\t\t\t\$this->redirect(array('action'=>'index'));\n";
- } else {
- $actions .= "\t\t\t\$this->flash(__('Invalid {$singularHumanName}', true), array('action'=>'index'));\n";
- }
- $actions .= "\t\t}\n";
- $actions .= "\t\tif (\$this->{$currentModelName}->delete(\$id)) {\n";
- if ($wannaUseSession) {
- $actions .= "\t\t\t\$this->Session->setFlash(__('{$singularHumanName} deleted', true));\n";
- $actions .= "\t\t\t\$this->redirect(array('action'=>'index'));\n";
- } else {
- $actions .= "\t\t\t\$this->flash(__('{$singularHumanName} deleted', true), array('action'=>'index'));\n";
- }
- $actions .= "\t\t}\n";
- $actions .= "\t}\n";
- $actions .= "\n";
+ $this->Template->set(compact('admin', 'controllerPath', 'pluralName', 'singularName', 'singularHumanName',
+ 'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName'));
+ $actions = $this->Template->generate('actions', 'controller_actions');
return $actions;
}
-
/**
* Assembles and writes a Controller file
*
@@ -403,54 +309,24 @@ class ControllerTask extends Shell {
* @return string Baked controller
* @access private
*/
- function bake($controllerName, $actions = '', $helpers = null, $components = null, $uses = null) {
- $out = "plugin}AppController {\n\n";
- $out .= "\tvar \$name = '$controllerName';\n";
+ function bake($controllerName, $actions = '', $helpers = null, $components = null) {
+ $isScaffold = ($actions === 'scaffold') ? true : false;
- if (low($actions) == 'scaffold') {
- $out .= "\tvar \$scaffold;\n";
- } else {
- if (count($uses)) {
- $out .= "\tvar \$uses = array('" . $this->_modelName($controllerName) . "', ";
+ $this->Template->set('plugin', Inflector::camelize($this->plugin));
+ $this->Template->set(compact('controllerName', 'actions', 'helpers', 'components', 'isScaffold'));
+ $contents = $this->Template->generate('classes', 'controller');
- foreach ($uses as $use) {
- if ($use != $uses[count($uses) - 1]) {
- $out .= "'" . $this->_modelName($use) . "', ";
- } else {
- $out .= "'" . $this->_modelName($use) . "'";
- }
- }
- $out .= ");\n";
- }
-
- $out .= "\tvar \$helpers = array('Html', 'Form'";
- if (count($helpers)) {
- foreach ($helpers as $help) {
- $out .= ", '" . Inflector::camelize($help) . "'";
- }
- }
- $out .= ");\n";
-
- if (count($components)) {
- $out .= "\tvar \$components = array(";
-
- foreach ($components as $comp) {
- if ($comp != $components[count($components) - 1]) {
- $out .= "'" . Inflector::camelize($comp) . "', ";
- } else {
- $out .= "'" . Inflector::camelize($comp) . "'";
- }
- }
- $out .= ");\n";
- }
- $out .= $actions;
+ $path = $this->path;
+ if (isset($this->plugin)) {
+ $path = $this->_pluginPath($this->plugin) . 'controllers' . DS;
}
- $out .= "}\n";
- $out .= "?>";
- $filename = $this->path . $this->_controllerPath($controllerName) . '_controller.php';
- return $this->createFile($filename, $out);
+ $filename = $path . $this->_controllerPath($controllerName) . '_controller.php';
+ if ($this->createFile($filename, $contents)) {
+ return $contents;
+ }
+ return false;
}
+
/**
* Assembles and writes a unit test file
*
@@ -459,84 +335,93 @@ class ControllerTask extends Shell {
* @access private
*/
function bakeTest($className) {
- $import = $className;
- if ($this->plugin) {
- $import = $this->plugin . '.' . $className;
- }
- $out = "App::import('Controller', '$import');\n\n";
- $out .= "class Test{$className} extends {$className}Controller {\n";
- $out .= "\tvar \$autoRender = false;\n}\n\n";
- $out .= "class {$className}ControllerTest extends CakeTestCase {\n";
- $out .= "\tvar \${$className} = null;\n\n";
- $out .= "\tfunction startTest() {\n\t\t\$this->{$className} = new Test{$className}();";
- $out .= "\n\t\t\$this->{$className}->constructClasses();\n\t}\n\n";
- $out .= "\tfunction test{$className}ControllerInstance() {\n";
- $out .= "\t\t\$this->assertTrue(is_a(\$this->{$className}, '{$className}Controller'));\n\t}\n\n";
- $out .= "\tfunction endTest() {\n\t\tunset(\$this->{$className});\n\t}\n}\n";
-
- $path = CONTROLLER_TESTS;
- if (isset($this->plugin)) {
- $pluginPath = 'plugins' . DS . Inflector::underscore($this->plugin) . DS;
- $path = APP . $pluginPath . 'tests' . DS . 'cases' . DS . 'controllers' . DS;
- }
-
- $filename = Inflector::underscore($className).'_controller.test.php';
- $this->out("\nBaking unit test for $className...");
-
- $header = '$Id';
- $content = "";
- return $this->createFile($path . $filename, $content);
+ $this->Test->plugin = $this->plugin;
+ $this->Test->connection = $this->connection;
+ return $this->Test->bake('Controller', $className);
}
+
/**
- * Outputs and gets the list of possible models or controllers from database
+ * Interact with the user and get a list of additional helpers
+ *
+ * @return array Helpers that the user wants to use.
+ **/
+ function doHelpers() {
+ return $this->_doPropertyChoices(
+ __("Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?", true),
+ __("Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Ajax, Javascript, Time'", true)
+ );
+ }
+
+/**
+ * Interact with the user and get a list of additional components
+ *
+ * @return array Components the user wants to use.
+ **/
+ function doComponents() {
+ return $this->_doPropertyChoices(
+ __("Would you like this controller to use any components?", true),
+ __("Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'", true)
+ );
+ }
+
+/**
+ * Common code for property choice handling.
+ *
+ * @param string $prompt A yes/no question to precede the list
+ * @param sting $example A question for a comma separated list, with examples.
+ * @return array Array of values for property.
+ **/
+ function _doPropertyChoices($prompt, $example) {
+ $proceed = $this->in($prompt, array('y','n'), 'n');
+ $property = array();
+ if (strtolower($proceed) == 'y') {
+ $propertyList = $this->in($example);
+ $propertyListTrimmed = str_replace(' ', '', $propertyList);
+ $property = explode(',', $propertyListTrimmed);
+ }
+ return array_filter($property);
+ }
+
+/**
+ * Outputs and gets the list of possible controllers from database
*
* @param string $useDbConfig Database configuration name
+ * @param boolean $interactive Whether you are using listAll interactively and want options output.
* @return array Set of controllers
* @access public
*/
- function listAll($useDbConfig = 'default') {
- $db =& ConnectionManager::getDataSource($useDbConfig);
- $usePrefix = empty($db->config['prefix']) ? '' : $db->config['prefix'];
- if ($usePrefix) {
- $tables = array();
- foreach ($db->listSources() as $table) {
- if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
- $tables[] = substr($table, strlen($usePrefix));
- }
+ function listAll($useDbConfig = null) {
+ if (is_null($useDbConfig)) {
+ $useDbConfig = $this->connection;
+ }
+ $this->__tables = $this->Model->getAllTables($useDbConfig);
+
+ if ($this->interactive == true) {
+ $this->out(__('Possible Controllers based on your current database:', true));
+ $this->_controllerNames = array();
+ $count = count($this->__tables);
+ for ($i = 0; $i < $count; $i++) {
+ $this->_controllerNames[] = $this->_controllerName($this->_modelName($this->__tables[$i]));
+ $this->out($i + 1 . ". " . $this->_controllerNames[$i]);
}
- } else {
- $tables = $db->listSources();
+ return $this->_controllerNames;
}
-
- if (empty($tables)) {
- $this->err(__('Your database does not have any tables.', true));
- $this->_stop();
- }
-
- $this->__tables = $tables;
- $this->out('Possible Controllers based on your current database:');
- $this->_controllerNames = array();
- $count = count($tables);
- for ($i = 0; $i < $count; $i++) {
- $this->_controllerNames[] = $this->_controllerName($this->_modelName($tables[$i]));
- $this->out($i + 1 . ". " . $this->_controllerNames[$i]);
- }
- return $this->_controllerNames;
+ return $this->__tables;
}
/**
* Forces the user to specify the controller he wants to bake, and returns the selected controller name.
*
+ * @param string $useDbConfig Connection name to get a controller name for.
* @return string Controller name
* @access public
*/
- function getName() {
- $useDbConfig = 'default';
- $controllers = $this->listAll($useDbConfig, 'Controllers');
+ function getName($useDbConfig = null) {
+ $controllers = $this->listAll($useDbConfig);
$enteredController = '';
while ($enteredController == '') {
- $enteredController = $this->in(__("Enter a number from the list above, type in the name of another controller, or 'q' to exit", true), null, 'q');
+ $enteredController = $this->in(__("Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit", true), null, 'q');
if ($enteredController === 'q') {
$this->out(__("Exit", true));
@@ -544,8 +429,7 @@ class ControllerTask extends Shell {
}
if ($enteredController == '' || intval($enteredController) > count($controllers)) {
- $this->out(__('Error:', true));
- $this->out(__("The Controller name you supplied was empty, or the number \nyou selected was not an option. Please try again.", true));
+ $this->err(__("The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again.", true));
$enteredController = '';
}
}
@@ -555,9 +439,9 @@ class ControllerTask extends Shell {
} else {
$controllerName = Inflector::camelize($enteredController);
}
-
return $controllerName;
}
+
/**
* Displays help contents
*
@@ -568,12 +452,26 @@ class ControllerTask extends Shell {
$this->out("Usage: cake bake controller ...");
$this->hr();
$this->out('Commands:');
- $this->out("\n\tcontroller \n\t\tbakes controller with var \$scaffold");
- $this->out("\n\tcontroller scaffold\n\t\tbakes controller with scaffold actions.\n\t\t(index, view, add, edit, delete)");
- $this->out("\n\tcontroller scaffold admin\n\t\tbakes a controller with scaffold actions for both public and Configure::read('Routing.admin')");
- $this->out("\n\tcontroller admin\n\t\tbakes a controller with scaffold actions only for Configure::read('Routing.admin')");
+ $this->out('');
+ $this->out("controller ");
+ $this->out("\tbakes controller with var \$scaffold");
+ $this->out('');
+ $this->out("controller scaffold");
+ $this->out("\tbakes controller with scaffold actions.");
+ $this->out("\t(index, view, add, edit, delete)");
+ $this->out('');
+ $this->out("controller scaffold admin");
+ $this->out("\tbakes a controller with scaffold actions for both public");
+ $this->out("\tand Configure::read('Routing.admin')");
+ $this->out('');
+ $this->out("controller admin");
+ $this->out("\tbakes a controller with scaffold actions only for");
+ $this->out("\tConfigure::read('Routing.admin')");
+ $this->out('');
+ $this->out("controller all");
+ $this->out("\tbakes all controllers with CRUD methods.");
$this->out("");
$this->_stop();
}
}
-?>
+?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/db_config.php b/cake/console/libs/tasks/db_config.php
index fcd71052e..befedb4c1 100644
--- a/cake/console/libs/tasks/db_config.php
+++ b/cake/console/libs/tasks/db_config.php
@@ -1,5 +1,4 @@
'root', 'password'=> 'password', 'database'=> 'project_name',
'schema'=> null, 'prefix'=> null, 'encoding' => null, 'port' => null
);
+
+/**
+ * String name of the database config class name.
+ * Used for testing.
+ *
+ * @var string
+ **/
+ var $databaseClassName = 'DATABASE_CONFIG';
+
/**
* initialization callback
*
@@ -61,6 +66,7 @@ class DbConfigTask extends Shell {
function initialize() {
$this->path = $this->params['working'] . DS . 'config' . DS;
}
+
/**
* Execution method always used for tasks
*
@@ -72,6 +78,7 @@ class DbConfigTask extends Shell {
$this->_stop();
}
}
+
/**
* Interactive interface
*
@@ -92,35 +99,27 @@ class DbConfigTask extends Shell {
if (preg_match('/[^a-z0-9_]/i', $name)) {
$name = '';
$this->out('The name may only contain unaccented latin characters, numbers or underscores');
- }
- else if (preg_match('/^[^a-z_]/i', $name)) {
+ } else if (preg_match('/^[^a-z_]/i', $name)) {
$name = '';
$this->out('The name must start with an unaccented latin character or an underscore');
}
}
- $driver = '';
- while ($driver == '') {
- $driver = $this->in('Driver:', array('db2', 'firebird', 'mssql', 'mysql', 'mysqli', 'odbc', 'oracle', 'postgres', 'sqlite', 'sybase'), 'mysql');
- }
- $persistent = '';
-
- while ($persistent == '') {
- $persistent = $this->in('Persistent Connection?', array('y', 'n'), 'n');
- }
+ $driver = $this->in('Driver:', array('db2', 'firebird', 'mssql', 'mysql', 'mysqli', 'odbc', 'oracle', 'postgres', 'sqlite', 'sybase'), 'mysql');
+ $persistent = $this->in('Persistent Connection?', array('y', 'n'), 'n');
if (low($persistent) == 'n') {
$persistent = 'false';
} else {
$persistent = 'true';
}
- $host = '';
+ $host = '';
while ($host == '') {
$host = $this->in('Database Host:', null, 'localhost');
}
- $port = '';
+ $port = '';
while ($port == '') {
$port = $this->in('Port?', null, 'n');
}
@@ -128,8 +127,8 @@ class DbConfigTask extends Shell {
if (low($port) == 'n') {
$port = null;
}
- $login = '';
+ $login = '';
while ($login == '') {
$login = $this->in('User:', null, 'root');
}
@@ -141,43 +140,39 @@ class DbConfigTask extends Shell {
if ($password == '') {
$blank = $this->in('The password you supplied was empty. Use an empty password?', array('y', 'n'), 'n');
- if ($blank == 'y')
- {
+ if ($blank == 'y') {
$blankPassword = true;
}
}
}
- $database = '';
+ $database = '';
while ($database == '') {
$database = $this->in('Database Name:', null, 'cake');
}
- $prefix = '';
+ $prefix = '';
while ($prefix == '') {
$prefix = $this->in('Table Prefix?', null, 'n');
}
-
if (low($prefix) == 'n') {
$prefix = null;
}
- $encoding = '';
+ $encoding = '';
while ($encoding == '') {
$encoding = $this->in('Table encoding?', null, 'n');
}
-
if (low($encoding) == 'n') {
$encoding = null;
}
- $schema = '';
+ $schema = '';
if ($driver == 'postgres') {
while ($schema == '') {
$schema = $this->in('Table schema?', null, 'n');
}
}
-
if (low($schema) == 'n') {
$schema = null;
}
@@ -199,6 +194,7 @@ class DbConfigTask extends Shell {
config('database');
return true;
}
+
/**
* Output verification message and bake if it looks good
*
@@ -240,11 +236,12 @@ class DbConfigTask extends Shell {
$this->hr();
$looksGood = $this->in('Look okay?', array('y', 'n'), 'y');
- if (low($looksGood) == 'y' || low($looksGood) == 'yes') {
+ if (strtolower($looksGood) == 'y') {
return $config;
}
return false;
}
+
/**
* Assembles and writes database.php
*
@@ -262,7 +259,7 @@ class DbConfigTask extends Shell {
$oldConfigs = array();
if (file_exists($filename)) {
- $db = new DATABASE_CONFIG;
+ $db = new $this->databaseClassName;
$temp = get_class_vars(get_class($db));
foreach ($temp as $configName => $info) {
@@ -346,8 +343,28 @@ class DbConfigTask extends Shell {
$out .= "}\n";
$out .= "?>";
- $filename = $this->path.'database.php';
+ $filename = $this->path . 'database.php';
return $this->createFile($filename, $out);
}
+
+/**
+ * Get a user specified Connection name
+ *
+ * @return void
+ **/
+ function getConfig() {
+ $useDbConfig = 'default';
+ $configs = get_class_vars($this->databaseClassName);
+
+ if (!is_array($configs)) {
+ return $this->execute();
+ }
+
+ $connections = array_keys($configs);
+ if (count($connections) > 1) {
+ $useDbConfig = $this->in(__('Use Database Config', true) .':', $connections, 'default');
+ }
+ return $useDbConfig;
+ }
}
?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/extract.php b/cake/console/libs/tasks/extract.php
index 7918e8cd7..eda49614b 100644
--- a/cake/console/libs/tasks/extract.php
+++ b/cake/console/libs/tasks/extract.php
@@ -1,5 +1,4 @@
__extract();
}
+
/**
* Extract text
*
@@ -212,6 +221,7 @@ class ExtractTask extends Shell{
}
$this->__extractTokens();
}
+
/**
* Show help options
*
@@ -237,6 +247,7 @@ class ExtractTask extends Shell{
$this->out(__(' -debug: Perform self test.', true));
$this->out('');
}
+
/**
* Extract tokens out of all files to be processed
*
@@ -281,6 +292,7 @@ class ExtractTask extends Shell{
$this->__writeFiles();
$this->out('Done.');
}
+
/**
* Will parse __(), __c() functions
*
@@ -316,6 +328,7 @@ class ExtractTask extends Shell{
$count++;
}
}
+
/**
* Will parse __d(), __dc(), __n(), __dn(), __dcn()
*
@@ -402,6 +415,7 @@ class ExtractTask extends Shell{
$count++;
}
}
+
/**
* Build the translate template file contents out of obtained strings
*
@@ -464,6 +478,7 @@ class ExtractTask extends Shell{
$this->__store($filename, $output, $fileList);
}
}
+
/**
* Prepare a file to be stored
*
@@ -491,6 +506,7 @@ class ExtractTask extends Shell{
return $storage;
}
}
+
/**
* Write the files that need to be stored
*
@@ -539,6 +555,7 @@ class ExtractTask extends Shell{
fclose($fp);
}
}
+
/**
* Merge output files
*
@@ -565,6 +582,7 @@ class ExtractTask extends Shell{
}
return $output;
}
+
/**
* Build the translation template header
*
@@ -590,6 +608,7 @@ class ExtractTask extends Shell{
$output .= "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n";
return $output;
}
+
/**
* Find the version number of a file looking for SVN commands
*
@@ -604,6 +623,7 @@ class ExtractTask extends Shell{
$this->__fileVersions[$file] = $version;
}
}
+
/**
* Format a string to be added as a translateable string
*
@@ -622,6 +642,7 @@ class ExtractTask extends Shell{
$string = str_replace("\r\n", "\n", $string);
return addcslashes($string, "\0..\37\\\"");
}
+
/**
* Indicate an invalid marker on a processed file
*
@@ -654,6 +675,7 @@ class ExtractTask extends Shell{
}
$this->out("\n", true);
}
+
/**
* Search the specified path for files that may contain translateable strings
*
diff --git a/cake/console/libs/tasks/fixture.php b/cake/console/libs/tasks/fixture.php
new file mode 100644
index 000000000..58a5455d0
--- /dev/null
+++ b/cake/console/libs/tasks/fixture.php
@@ -0,0 +1,427 @@
+path = $this->params['working'] . DS . 'tests' . DS . 'fixtures' . DS;
+ if (!class_exists('CakeSchema')) {
+ App::import('Model', 'CakeSchema', false);
+ }
+ }
+
+/**
+ * Execution method always used for tasks
+ * Handles dispatching to interactive, named, or all processess.
+ *
+ * @access public
+ */
+ function execute() {
+ if (empty($this->args)) {
+ $this->__interactive();
+ }
+
+ if (isset($this->args[0])) {
+ if (!isset($this->connection)) {
+ $this->connection = 'default';
+ }
+ if (strtolower($this->args[0]) == 'all') {
+ return $this->all();
+ }
+ $model = Inflector::camelize($this->args[0]);
+ $this->bake($model);
+ }
+ }
+
+/**
+ * Bake All the Fixtures at once. Will only bake fixtures for models that exist.
+ *
+ * @access public
+ * @return void
+ **/
+ function all() {
+ $this->interactive = false;
+ $tables = $this->Model->listAll($this->connection, false);
+ foreach ($tables as $table) {
+ $model = $this->_modelName($table);
+ $this->bake($model);
+ }
+ }
+
+/**
+ * Interactive baking function
+ *
+ * @access private
+ */
+ function __interactive() {
+ $this->interactive = true;
+ $this->hr();
+ $this->out(sprintf("Bake Fixture\nPath: %s", $this->path));
+ $this->hr();
+
+ $useDbConfig = $this->connection;
+ if (!isset($this->connection)) {
+ $this->connection = $this->DbConfig->getConfig();
+ }
+ $modelName = $this->Model->getName($this->connection);
+ $useTable = $this->Model->getTable($modelName, $this->connection);
+ $importOptions = $this->importOptions($modelName);
+ $this->bake($modelName, $useTable, $importOptions);
+ }
+
+/**
+ * Interacts with the User to setup an array of import options. For a fixture.
+ *
+ * @param string $modelName Name of model you are dealing with.
+ * @return array Array of import options.
+ **/
+ function importOptions($modelName) {
+ $options = array();
+ $doSchema = $this->in(__('Would you like to import schema for this fixture?', true), array('y', 'n'), 'n');
+ if ($doSchema == 'y') {
+ $options['schema'] = $modelName;
+ }
+ $doRecords = $this->in(__('Would you like to use record importing for this fixture?', true), array('y', 'n'), 'n');
+ if ($doRecords == 'y') {
+ $options['records'] = true;
+ }
+ if ($doRecords == 'n') {
+ $prompt = sprintf(__("Would you like to build this fixture with data from %s's table?", true), $modelName);
+ $fromTable = $this->in($prompt, array('y', 'n'), 'n');
+ if (strtolower($fromTable) == 'y') {
+ $options['fromTable'] = true;
+ }
+ }
+ return $options;
+ }
+
+/**
+ * Assembles and writes a Fixture file
+ *
+ * @param string $model Name of model to bake.
+ * @param string $useTable Name of table to use.
+ * @param array $importOptions Options for var $import
+ * @return string Baked fixture
+ * @access private
+ */
+ function bake($model, $useTable = false, $importOptions = array()) {
+ $table = $schema = $records = $import = $modelImport = $recordImport = null;
+ if (!$useTable) {
+ $useTable = Inflector::tableize($model);
+ } elseif ($useTable != Inflector::tableize($model)) {
+ $table = $useTable;
+ }
+
+ if (!empty($importOptions)) {
+ if (isset($importOptions['schema'])) {
+ $modelImport = "'model' => '{$importOptions['schema']}'";
+ }
+ if (isset($importOptions['records'])) {
+ $recordImport = "'records' => true";
+ }
+ if ($modelImport && $recordImport) {
+ $modelImport .= ', ';
+ }
+ if (!empty($modelImport) || !empty($recordImport)) {
+ $import = sprintf("array(%s%s)", $modelImport, $recordImport);
+ }
+ }
+
+ $this->_Schema = new CakeSchema();
+ $data = $this->_Schema->read(array('models' => false, 'connection' => $this->connection));
+
+ if (!isset($data['tables'][$useTable])) {
+ $this->err('Could not find your selected table ' . $useTable);
+ return false;
+ }
+
+ $tableInfo = $data['tables'][$useTable];
+ if (is_null($modelImport)) {
+ $schema = $this->_generateSchema($tableInfo);
+ }
+
+ if (!isset($importOptions['records']) && !isset($importOptions['fromTable'])) {
+ $recordCount = 1;
+ if (isset($this->params['count'])) {
+ $recordCount = $this->params['count'];
+ }
+ $records = $this->_makeRecordString($this->_generateRecords($tableInfo, $recordCount));
+ }
+ if (isset($importOptions['fromTable'])) {
+ $records = $this->_makeRecordString($this->_getRecordsFromTable($model, $useTable));
+ }
+ $out = $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import', 'fields'));
+ return $out;
+ }
+
+/**
+ * Generate the fixture file, and write to disk
+ *
+ * @param string $model name of the model being generated
+ * @param string $fixture Contents of the fixture file.
+ * @access public
+ * @return void
+ **/
+ function generateFixtureFile($model, $otherVars) {
+ $defaults = array('table' => null, 'schema' => null, 'records' => null, 'import' => null, 'fields' => null);
+ $vars = array_merge($defaults, $otherVars);
+
+ $path = $this->path;
+ if (isset($this->plugin)) {
+ $path = $this->_pluginPath($this->plugin) . 'tests' . DS . 'fixtures' . DS;
+ }
+ $filename = Inflector::underscore($model) . '_fixture.php';
+
+ $this->Template->set('model', $model);
+ $this->Template->set($vars);
+ $content = $this->Template->generate('classes', 'fixture');
+
+ $this->out("\nBaking test fixture for $model...");
+ $this->createFile($path . $filename, $content);
+ return $content;
+ }
+
+/**
+ * Generates a string representation of a schema.
+ *
+ * @param array $table Table schema array
+ * @return string fields definitions
+ **/
+ function _generateSchema($tableInfo) {
+ $cols = array();
+ $out = "array(\n";
+ foreach ($tableInfo as $field => $fieldInfo) {
+ if (is_array($fieldInfo)) {
+ if ($field != 'indexes') {
+ $col = "\t\t'{$field}' => array('type'=>'" . $fieldInfo['type'] . "', ";
+ $col .= join(', ', $this->_Schema->__values($fieldInfo));
+ } else {
+ $col = "\t\t'indexes' => array(";
+ $props = array();
+ foreach ((array)$fieldInfo as $key => $index) {
+ $props[] = "'{$key}' => array(".join(', ', $this->_Schema->__values($index)).")";
+ }
+ $col .= join(', ', $props);
+ }
+ $col .= ")";
+ $cols[] = $col;
+ }
+ }
+ $out .= join(",\n", $cols);
+ $out .= "\n\t)";
+ return $out;
+ }
+
+/**
+ * Generate String representation of Records
+ *
+ * @param array $table Table schema array
+ * @return array Array of records to use in the fixture.
+ **/
+ function _generateRecords($tableInfo, $recordCount = 1) {
+ $records = array();
+ for ($i = 0; $i < $recordCount; $i++) {
+ $record = array();
+ foreach ($tableInfo as $field => $fieldInfo) {
+ if (empty($fieldInfo['type'])) {
+ continue;
+ }
+ switch ($fieldInfo['type']) {
+ case 'integer':
+ $insert = $i + 1;
+ break;
+ case 'string';
+ $isPrimaryUuid = (
+ isset($fieldInfo['key']) && strtolower($fieldInfo['key']) == 'primary' &&
+ isset($fieldInfo['length']) && $fieldInfo['length'] == 36
+ );
+ if ($isPrimaryUuid) {
+ $insert = String::uuid();
+ } else {
+ $insert = "Lorem ipsum dolor sit amet";
+ if (!empty($fieldInfo['length'])) {
+ $insert = substr($insert, 0, (int)$fieldInfo['length'] - 2);
+ }
+ }
+ $insert = "'$insert'";
+ break;
+ case 'timestamp':
+ $ts = time();
+ $insert = "'$ts'";
+ break;
+ case 'datetime':
+ $ts = date('Y-m-d H:i:s');
+ $insert = "'$ts'";
+ break;
+ case 'date':
+ $ts = date('Y-m-d');
+ $insert = "'$ts'";
+ break;
+ case 'time':
+ $ts = date('H:i:s');
+ $insert = "'$ts'";
+ break;
+ case 'boolean':
+ $insert = 1;
+ break;
+ case 'text':
+ $insert = "'Lorem ipsum dolor sit amet, aliquet feugiat.";
+ $insert .= " Convallis morbi fringilla gravida,";
+ $insert .= " phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin";
+ $insert .= " venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla";
+ $insert .= " vestibulum massa neque ut et, id hendrerit sit,";
+ $insert .= " feugiat in taciti enim proin nibh, tempor dignissim, rhoncus";
+ $insert .= " duis vestibulum nunc mattis convallis.'";
+ break;
+ }
+ $record[$field] = $insert;
+ }
+ $records[] = $record;
+ }
+ return $records;
+ }
+
+/**
+ * Convert a $records array into a a string.
+ *
+ * @param array $records Array of records to be converted to string
+ * @return string A string value of the $records array.
+ **/
+ function _makeRecordString($records) {
+ $out = "array(\n";
+ foreach ($records as $record) {
+ $values = array();
+ foreach ($record as $field => $value) {
+ $values[] = "\t\t\t'$field' => $value";
+ }
+ $out .= "\t\tarray(\n";
+ $out .= implode(",\n", $values);
+ $out .= "\n\t\t),\n";
+ }
+ $out .= "\t)";
+ return $out;
+ }
+
+/**
+ * Interact with the user to get a custom SQL condition and use that to extract data
+ * to build a fixture.
+ *
+ * @param string $modelName name of the model to take records from.
+ * @param string $useTable Name of table to use.
+ * @return array Array of records.
+ **/
+ function _getRecordsFromTable($modelName, $useTable = null) {
+ $condition = null;
+ $prompt = __("Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1 LIMIT 10", true);
+ while (!$condition) {
+ $condition = $this->in($prompt, null, 'WHERE 1=1 LIMIT 10');
+ }
+ App::import('Model', 'Model', false);
+ $modelObject =& new Model(array('name' => $modelName, 'table' => $useTable, 'ds' => $this->connection));
+ $records = $modelObject->find('all', array(
+ 'conditions' => $condition,
+ 'recursive' => -1
+ ));
+ $db =& $modelObject->getDataSource();
+ $schema = $modelObject->schema();
+ $out = array();
+ foreach ($records as $record) {
+ $row = array();
+ foreach ($record[$modelObject->alias] as $field => $value) {
+ $row[$field] = $db->value($value, $schema[$field]['type']);
+ }
+ $out[] = $row;
+ }
+ return $out;
+ }
+
+/**
+ * Displays help contents
+ *
+ * @access public
+ */
+ function help() {
+ $this->hr();
+ $this->out("Usage: cake bake fixture ");
+ $this->hr();
+ $this->out('Commands:');
+ $this->out("\nfixture \n\tbakes fixture with specified name.");
+ $this->out("\nfixture all\n\tbakes all fixtures.");
+ $this->out("");
+ $this->out('Parameters:');
+ $this->out("\t-count When using generated data, the number of records to include in the fixture(s).");
+ $this->out("\t-connection Which database configuration to use for baking.");
+ $this->out("\t-plugin lowercased_underscored name of plugin to bake fixtures for.");
+ $this->out("");
+ $this->_stop();
+ }
+}
+?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/model.php b/cake/console/libs/tasks/model.php
index b4ae6feed..f9d7937b2 100644
--- a/cake/console/libs/tasks/model.php
+++ b/cake/console/libs/tasks/model.php
@@ -1,5 +1,4 @@
args[0])) {
+ $this->interactive = false;
+ if (!isset($this->connection)) {
+ $this->connection = 'default';
+ }
+ if (strtolower($this->args[0]) == 'all') {
+ return $this->all();
+ }
$model = Inflector::camelize($this->args[0]);
- if ($this->bake($model)) {
+ $object = $this->_getModelObject($model);
+ if ($this->bake($object, false)) {
if ($this->_checkUnitTest()) {
+ $this->bakeFixture($model);
$this->bakeTest($model);
}
}
}
}
+
+/**
+ * Bake all models at once.
+ *
+ * @return void
+ **/
+ function all() {
+ $this->listAll($this->connection, false);
+ $unitTestExists = $this->_checkUnitTest();
+ foreach ($this->__tables as $table) {
+ $modelClass = Inflector::classify($table);
+ $this->out(sprintf(__('Baking %s', true), $modelClass));
+ $object = $this->_getModelObject($modelClass);
+ if ($this->bake($object, false) && $unitTestExists) {
+ $this->bakeFixture($modelClass);
+ $this->bakeTest($modelClass);
+ }
+ }
+ }
+
+/**
+ * Get a model object for a class name.
+ *
+ * @param string $className Name of class you want model to be.
+ * @return object Model instance
+ **/
+ function &_getModelObject($className) {
+ $object = new Model(array('name' => $className, 'ds' => $this->connection));
+ return $object;
+ }
+
+/**
+ * Generate a key value list of options and a prompt.
+ *
+ * @param array $options Array of options to use for the selections. indexes must start at 0
+ * @param string $prompt Prompt to use for options list.
+ * @param integer $default The default option for the given prompt.
+ * @return result of user choice.
+ **/
+ function inOptions($options, $prompt = null, $default = null) {
+ $valid = false;
+ $max = count($options);
+ while (!$valid) {
+ foreach ($options as $i => $option) {
+ $this->out($i + 1 .'. ' . $option);
+ }
+ if (empty($prompt)) {
+ $prompt = __('Make a selection from the choices above', true);
+ }
+ $choice = $this->in($prompt, null, $default);
+ if (intval($choice) > 0 && intval($choice) <= $max) {
+ $valid = true;
+ }
+ }
+ return $choice - 1;
+ }
+
/**
* Handles interactive baking
*
@@ -83,73 +181,42 @@ class ModelTask extends Shell {
$this->hr();
$this->interactive = true;
- $useTable = null;
$primaryKey = 'id';
- $validate = array();
- $associations = array('belongsTo'=> array(), 'hasOne'=> array(), 'hasMany' => array(), 'hasAndBelongsToMany'=> array());
+ $validate = $associations = array();
- $useDbConfig = 'default';
- $configs = get_class_vars('DATABASE_CONFIG');
-
- if (!is_array($configs)) {
- return $this->DbConfig->execute();
+ if (empty($this->connection)) {
+ $this->connection = $this->DbConfig->getConfig();
}
-
- $connections = array_keys($configs);
- if (count($connections) > 1) {
- $useDbConfig = $this->in(__('Use Database Config', true) .':', $connections, 'default');
- }
-
- $currentModelName = $this->getName($useDbConfig);
- $db =& ConnectionManager::getDataSource($useDbConfig);
- $useTable = Inflector::tableize($currentModelName);
- $fullTableName = $db->fullTableName($useTable, false);
- $tableIsGood = false;
-
- if (array_search($useTable, $this->__tables) === false) {
- $this->out('');
- $this->out(sprintf(__("Given your model named '%s', Cake would expect a database table named %s", true), $currentModelName, $fullTableName));
- $tableIsGood = $this->in(__('Do you want to use this table?', true), array('y','n'), 'y');
- }
-
- if (low($tableIsGood) == 'n' || low($tableIsGood) == 'no') {
- $useTable = $this->in(__('What is the name of the table (enter "null" to use NO table)?', true));
- }
-
- while ($tableIsGood == false && low($useTable) != 'null') {
- if (is_array($this->__tables) && !in_array($useTable, $this->__tables)) {
- $fullTableName = $db->fullTableName($useTable, false);
- $this->out($fullTableName . ' does not exist.');
- $useTable = $this->in(__('What is the name of the table (enter "null" to use NO table)?', true));
- $tableIsGood = false;
- } else {
- $tableIsGood = true;
- }
- }
-
- $wannaDoValidation = $this->in(__('Would you like to supply validation criteria for the fields in your model?', true), array('y','n'), 'y');
+ $currentModelName = $this->getName();
+ $useTable = $this->getTable($currentModelName);
+ $db =& ConnectionManager::getDataSource($this->connection);
+ $fullTableName = $db->fullTableName($useTable);
if (in_array($useTable, $this->__tables)) {
- App::import('Model');
- $tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $useDbConfig));
-
+ $tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $this->connection));
$fields = $tempModel->schema();
if (!array_key_exists('id', $fields)) {
- foreach ($fields as $name => $field) {
- if (isset($field['key']) && $field['key'] == 'primary') {
- break;
- }
- }
- $primaryKey = $this->in(__('What is the primaryKey?', true), null, $name);
+ $primaryKey = $this->findPrimaryKey($fields);
}
+ } else {
+ $this->err(sprintf(__('Table %s does not exist, cannot bake a model without a table.', true), $useTable));
+ $this->_stop();
+ return false;
+ }
+ $displayField = $tempModel->hasField(array('name', 'title'));
+ if (!$displayField) {
+ $displayField = $this->findDisplayField($tempModel->schema());
}
- if (array_search($useTable, $this->__tables) !== false && (low($wannaDoValidation) == 'y' || low($wannaDoValidation) == 'yes')) {
+ $prompt = __("Would you like to supply validation criteria \nfor the fields in your model?", true);
+ $wannaDoValidation = $this->in($prompt, array('y','n'), 'y');
+ if (array_search($useTable, $this->__tables) !== false && strtolower($wannaDoValidation) == 'y') {
$validate = $this->doValidation($tempModel);
}
- $wannaDoAssoc = $this->in(__('Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)?', true), array('y','n'), 'y');
- if ((low($wannaDoAssoc) == 'y' || low($wannaDoAssoc) == 'yes')) {
+ $prompt = __("Would you like to define model associations\n(hasMany, hasOne, belongsTo, etc.)?", true);
+ $wannaDoAssoc = $this->in($prompt, array('y','n'), 'y');
+ if (strtolower($wannaDoAssoc) == 'y') {
$associations = $this->doAssociations($tempModel);
}
@@ -159,51 +226,35 @@ class ModelTask extends Shell {
$this->hr();
$this->out("Name: " . $currentModelName);
- if ($useDbConfig !== 'default') {
- $this->out("DB Config: " . $useDbConfig);
+ if ($this->connection !== 'default') {
+ $this->out(sprintf(__("DB Config: %s", true), $this->connection));
}
if ($fullTableName !== Inflector::tableize($currentModelName)) {
- $this->out("DB Table: " . $fullTableName);
+ $this->out(sprintf(__("DB Table: %s", true), $fullTableName));
}
if ($primaryKey != 'id') {
- $this->out("Primary Key: " . $primaryKey);
+ $this->out(sprintf(__("Primary Key: %s", true), $primaryKey));
}
if (!empty($validate)) {
- $this->out("Validation: " . print_r($validate, true));
+ $this->out(sprintf(__("Validation: %s", true), print_r($validate, true)));
}
if (!empty($associations)) {
- $this->out("Associations:");
-
- if (!empty($associations['belongsTo'])) {
- for ($i = 0; $i < count($associations['belongsTo']); $i++) {
- $this->out(" $currentModelName belongsTo {$associations['belongsTo'][$i]['alias']}");
- }
- }
-
- if (!empty($associations['hasOne'])) {
- for ($i = 0; $i < count($associations['hasOne']); $i++) {
- $this->out(" $currentModelName hasOne {$associations['hasOne'][$i]['alias']}");
- }
- }
-
- if (!empty($associations['hasMany'])) {
- for ($i = 0; $i < count($associations['hasMany']); $i++) {
- $this->out(" $currentModelName hasMany {$associations['hasMany'][$i]['alias']}");
- }
- }
-
- if (!empty($associations['hasAndBelongsToMany'])) {
- for ($i = 0; $i < count($associations['hasAndBelongsToMany']); $i++) {
- $this->out(" $currentModelName hasAndBelongsToMany {$associations['hasAndBelongsToMany'][$i]['alias']}");
- }
+ $this->out(__("Associations:", true));
+ $assocKeys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
+ foreach ($assocKeys as $assocKey) {
+ $this->_printAssociation($currentModelName, $assocKey, $associations);
}
}
+
$this->hr();
$looksGood = $this->in(__('Look okay?', true), array('y','n'), 'y');
- if (low($looksGood) == 'y' || low($looksGood) == 'yes') {
- if ($this->bake($currentModelName, $associations, $validate, $primaryKey, $useTable, $useDbConfig)) {
+ if (strtolower($looksGood) == 'y') {
+ $vars = compact('associations', 'validate', 'primaryKey', 'useTable', 'displayField');
+ $vars['useDbConfig'] = $this->connection;
+ if ($this->bake($currentModelName, $vars)) {
if ($this->_checkUnitTest()) {
+ $this->bakeFixture($currentModelName, $useTable);
$this->bakeTest($currentModelName, $useTable, $associations);
}
}
@@ -211,15 +262,67 @@ class ModelTask extends Shell {
return false;
}
}
+
/**
- * Handles associations
+ * Print out all the associations of a particular type
*
- * @param object $model
- * @param boolean $interactive
- * @return array $validate
+ * @param string $modelName Name of the model relations belong to.
+ * @param string $type Name of association you want to see. i.e. 'belongsTo'
+ * @param string $associations Collection of associations.
+ * @access protected
+ * @return void
+ **/
+ function _printAssociation($modelName, $type, $associations) {
+ if (!empty($associations[$type])) {
+ for ($i = 0; $i < count($associations[$type]); $i++) {
+ $out = "\t" . $modelName . ' ' . $type . ' ' . $associations[$type][$i]['alias'];
+ $this->out($out);
+ }
+ }
+ }
+
+/**
+ * Finds a primary Key in a list of fields.
+ *
+ * @param array $fields Array of fields that might have a primary key.
+ * @return string Name of field that is a primary key.
+ * @access public
+ **/
+ function findPrimaryKey($fields) {
+ foreach ($fields as $name => $field) {
+ if (isset($field['key']) && $field['key'] == 'primary') {
+ break;
+ }
+ }
+ return $this->in(__('What is the primaryKey?', true), null, $name);
+ }
+
+/**
+ * interact with the user to find the displayField value for a model.
+ *
+ * @param array $fields Array of fields to look for and choose as a displayField
+ * @return mixed Name of field to use for displayField or false if the user declines to choose
+ **/
+ function findDisplayField($fields) {
+ $fieldNames = array_keys($fields);
+ $prompt = __("A displayField could not be automatically detected\nwould you like to choose one?", true);
+ $continue = $this->in($prompt, array('y', 'n'));
+ if (strtolower($continue) == 'n') {
+ return false;
+ }
+ $prompt = __('Choose a field from the options above:', true);
+ $choice = $this->inOptions($fieldNames, $prompt);
+ return $fieldNames[$choice];
+ }
+
+/**
+ * Handles Generation and user interaction for creating validation.
+ *
+ * @param object $model Model to have validations generated for.
+ * @return array $validate Array of user selected validations.
* @access public
*/
- function doValidation(&$model, $interactive = true) {
+ function doValidation(&$model) {
if (!is_object($model)) {
return false;
}
@@ -228,67 +331,110 @@ class ModelTask extends Shell {
if (empty($fields)) {
return false;
}
-
$validate = array();
+ $this->initValidations();
+ foreach ($fields as $fieldName => $field) {
+ $validation = $this->fieldValidation($fieldName, $field, $model->primaryKey);
+ if (!empty($validation)) {
+ $validate[$fieldName] = $validation;
+ }
+ }
+ return $validate;
+ }
- $options = array();
-
+/**
+ * Populate the __validations array
+ *
+ * @return void
+ **/
+ function initValidations() {
+ $options = $choices = array();
if (class_exists('Validation')) {
$parent = get_class_methods(get_parent_class('Validation'));
$options = array_diff(get_class_methods('Validation'), $parent);
}
+ sort($options);
+ $default = 1;
+ foreach ($options as $key => $option) {
+ if ($option{0} != '_' && strtolower($option) != 'getinstance') {
+ $choices[$default] = strtolower($option);
+ $default++;
+ }
+ }
+ $this->__validations = $choices;
+ return $choices;
+ }
- foreach ($fields as $fieldName => $field) {
- $prompt = 'Field: ' . $fieldName . "\n";
- $prompt .= 'Type: ' . $field['type'] . "\n";
- $prompt .= '---------------------------------------------------------------'."\n";
- $prompt .= 'Please select one of the following validation options:'."\n";
- $prompt .= '---------------------------------------------------------------'."\n";
+/**
+ * Does individual field validation handling.
+ *
+ * @param string $fieldName Name of field to be validated.
+ * @param array $metaData metadata for field
+ * @return array Array of validation for the field.
+ **/
+ function fieldValidation($fieldName, $metaData, $primaryKey = 'id') {
+ $defaultChoice = count($this->__validations);
+ $validate = $alreadyChosen = array();
- sort($options);
-
- $skip = 1;
- foreach ($options as $key => $option) {
- if ($option{0} != '_' && strtolower($option) != 'getinstance') {
- $prompt .= "{$skip} - {$option}\n";
- $choices[$skip] = strtolower($option);
- $skip++;
- }
+ $anotherValidator = 'y';
+ while ($anotherValidator == 'y') {
+ if ($this->interactive) {
+ $this->out('');
+ $this->out(sprintf(__('Field: %s', true), $fieldName));
+ $this->out(sprintf(__('Type: %s', true), $metaData['type']));
+ $this->hr();
+ $this->out(__('Please select one of the following validation options:', true));
+ $this->hr();
}
- $methods = array_flip($choices);
+ $prompt = '';
+ for ($i = 1; $i < $defaultChoice; $i++) {
+ $prompt .= $i . ' - ' . $this->__validations[$i] . "\n";
+ }
+ $prompt .= sprintf(__("%s - Do not do any validation on this field.\n", true), $defaultChoice);
+ $prompt .= __("... or enter in a valid regex validation string.\n", true);
- $prompt .= "{$skip} - Do not do any validation on this field.\n";
- $prompt .= "... or enter in a valid regex validation string.\n";
-
- $guess = $skip;
- if ($field['null'] != 1 && $fieldName != $model->primaryKey && !in_array($fieldName, array('created', 'modified', 'updated'))) {
+ $methods = array_flip($this->__validations);
+ $guess = $defaultChoice;
+ if ($metaData['null'] != 1 && !in_array($fieldName, array($primaryKey, 'created', 'modified', 'updated'))) {
if ($fieldName == 'email') {
$guess = $methods['email'];
- } elseif ($field['type'] == 'string') {
+ } elseif ($metaData['type'] == 'string') {
$guess = $methods['notempty'];
- } elseif ($field['type'] == 'integer') {
+ } elseif ($metaData['type'] == 'integer') {
$guess = $methods['numeric'];
- } elseif ($field['type'] == 'boolean') {
+ } elseif ($metaData['type'] == 'boolean') {
$guess = $methods['numeric'];
- } elseif ($field['type'] == 'datetime') {
+ } elseif ($metaData['type'] == 'datetime' || $metaData['type'] == 'date') {
$guess = $methods['date'];
+ } elseif ($metaData['type'] == 'time') {
+ $guess = $methods['time'];
}
}
- if ($interactive === true) {
- $this->out('');
+ if ($this->interactive === true) {
$choice = $this->in($prompt, null, $guess);
+ if (in_array($choice, $alreadyChosen)) {
+ $this->out(__("You have already chosen that validation rule,\nplease choose again", true));
+ continue;
+ }
+ $alreadyChosen[] = $choice;
} else {
$choice = $guess;
}
- if ($choice != $skip) {
- if (is_numeric($choice) && isset($choices[$choice])) {
- $validate[$fieldName] = $choices[$choice];
+ $validatorName = $this->__validations[$choice];
+ if ($choice != $defaultChoice) {
+ if (is_numeric($choice) && isset($this->__validations[$choice])) {
+ $validate[$validatorName] = $this->__validations[$choice];
} else {
- $validate[$fieldName] = $choice;
+ $validate[$validatorName] = $choice;
}
}
+ if ($this->interactive == true && $choice != $defaultChoice) {
+ $anotherValidator = $this->in(__('Would you like to add another validation rule?', true), array('y', 'n'), 'n');
+ } else {
+ $anotherValidator = 'n';
+ }
}
return $validate;
}
@@ -297,376 +443,312 @@ class ModelTask extends Shell {
* Handles associations
*
* @param object $model
- * @param boolean $interactive
* @return array $assocaitons
* @access public
*/
- function doAssociations(&$model, $interactive = true) {
-
+ function doAssociations(&$model) {
if (!is_object($model)) {
return false;
}
- $this->out(__('One moment while the associations are detected.', true));
+ if ($this->interactive === true) {
+ $this->out(__('One moment while the associations are detected.', true));
+ }
$fields = $model->schema();
-
if (empty($fields)) {
return false;
}
- $primaryKey = $model->primaryKey;
- $foreignKey = $this->_modelKey($model->name);
-
- $associations = array('belongsTo' => array(), 'hasMany' => array(), 'hasOne'=> array(), 'hasAndBelongsToMany' => array());
+ $associations = array(
+ 'belongsTo' => array(), 'hasMany' => array(), 'hasOne'=> array(), 'hasAndBelongsToMany' => array()
+ );
$possibleKeys = array();
- //Look for belongsTo
- $i = 0;
- foreach ($fields as $fieldName => $field) {
- $offset = strpos($fieldName, '_id');
- if ($fieldName != $model->primaryKey && $offset !== false) {
- $tmpModelName = $this->_modelNameFromKey($fieldName);
- $associations['belongsTo'][$i]['alias'] = $tmpModelName;
- $associations['belongsTo'][$i]['className'] = $tmpModelName;
- $associations['belongsTo'][$i]['foreignKey'] = $fieldName;
- $i++;
- }
- }
- //Look for hasOne and hasMany and hasAndBelongsToMany
- $i = $j = 0;
+ $associations = $this->findBelongsTo($model, $associations);
+ $associations = $this->findHasOneAndMany($model, $associations);
+ $associations = $this->findHasAndBelongsToMany($model, $associations);
- foreach ($this->__tables as $otherTable) {
- App::import('Model');
- $tmpModelName = $this->_modelName($otherTable);
- $tempOtherModel = & new Model(array('name' => $tmpModelName, 'table' => $otherTable, 'ds' => $model->useDbConfig));
- $modelFieldsTemp = $tempOtherModel->schema();
-
- $offset = strpos($otherTable, $model->table . '_');
- $otherOffset = strpos($otherTable, '_' . $model->table);
-
- foreach ($modelFieldsTemp as $fieldName => $field) {
- if ($field['type'] == 'integer' || $field['type'] == 'string') {
- $possibleKeys[$otherTable][] = $fieldName;
- }
- if ($fieldName != $model->primaryKey && $fieldName == $foreignKey && $offset === false && $otherOffset === false) {
- $associations['hasOne'][$j]['alias'] = $tempOtherModel->name;
- $associations['hasOne'][$j]['className'] = $tempOtherModel->name;
- $associations['hasOne'][$j]['foreignKey'] = $fieldName;
-
- $associations['hasMany'][$j]['alias'] = $tempOtherModel->name;
- $associations['hasMany'][$j]['className'] = $tempOtherModel->name;
- $associations['hasMany'][$j]['foreignKey'] = $fieldName;
- $j++;
- }
- }
-
- if ($offset !== false) {
- $offset = strlen($model->table . '_');
- $tmpModelName = $this->_modelName(substr($otherTable, $offset));
- $associations['hasAndBelongsToMany'][$i]['alias'] = $tmpModelName;
- $associations['hasAndBelongsToMany'][$i]['className'] = $tmpModelName;
- $associations['hasAndBelongsToMany'][$i]['foreignKey'] = $foreignKey;
- $associations['hasAndBelongsToMany'][$i]['associationForeignKey'] = $this->_modelKey($tmpModelName);
- $associations['hasAndBelongsToMany'][$i]['joinTable'] = $otherTable;
- $i++;
- }
-
- if ($otherOffset !== false) {
- $tmpModelName = $this->_modelName(substr($otherTable, 0, $otherOffset));
- $associations['hasAndBelongsToMany'][$i]['alias'] = $tmpModelName;
- $associations['hasAndBelongsToMany'][$i]['className'] = $tmpModelName;
- $associations['hasAndBelongsToMany'][$i]['foreignKey'] = $foreignKey;
- $associations['hasAndBelongsToMany'][$i]['associationForeignKey'] = $this->_modelKey($tmpModelName);
- $associations['hasAndBelongsToMany'][$i]['joinTable'] = $otherTable;
- $i++;
- }
- }
-
- if ($interactive !== true) {
+ if ($this->interactive !== true) {
unset($associations['hasOne']);
}
- if ($interactive === true) {
+ if ($this->interactive === true) {
$this->hr();
if (empty($associations)) {
$this->out(__('None found.', true));
} else {
$this->out(__('Please confirm the following associations:', true));
$this->hr();
- foreach ($associations as $type => $settings) {
- if (!empty($associations[$type])) {
- $count = count($associations[$type]);
- $response = 'y';
- for ($i = 0; $i < $count; $i++) {
- $prompt = "{$model->name} {$type} {$associations[$type][$i]['alias']}";
- $response = $this->in("{$prompt}?", array('y','n'), 'y');
-
- if ('n' == low($response) || 'no' == low($response)) {
- unset($associations[$type][$i]);
- } else {
- if ($model->name === $associations[$type][$i]['alias']) {
- if ($type === 'belongsTo') {
- $alias = 'Parent' . $associations[$type][$i]['alias'];
- }
- if ($type === 'hasOne' || $type === 'hasMany') {
- $alias = 'Child' . $associations[$type][$i]['alias'];
- }
-
- $alternateAlias = $this->in(sprintf(__('This is a self join. Use %s as the alias', true), $alias), array('y', 'n'), 'y');
-
- if ('n' == low($alternateAlias) || 'no' == low($alternateAlias)) {
- $associations[$type][$i]['alias'] = $this->in(__('Specify an alternate alias.', true));
- } else {
- $associations[$type][$i]['alias'] = $alias;
- }
- }
- }
- }
- $associations[$type] = array_merge($associations[$type]);
- }
- }
+ $associations = $this->confirmAssociations($model, $associations);
}
+ $associations = $this->doMoreAssociations($model, $associations);
+ }
+ return $associations;
+ }
- $wannaDoMoreAssoc = $this->in(__('Would you like to define some additional model associations?', true), array('y','n'), 'n');
-
- while ((low($wannaDoMoreAssoc) == 'y' || low($wannaDoMoreAssoc) == 'yes')) {
- $assocs = array(1 => 'belongsTo', 2 => 'hasOne', 3 => 'hasMany', 4 => 'hasAndBelongsToMany');
- $bad = true;
- while ($bad) {
- $this->out(__('What is the association type?', true));
- $prompt = "1. belongsTo\n";
- $prompt .= "2. hasOne\n";
- $prompt .= "3. hasMany\n";
- $prompt .= "4. hasAndBelongsToMany\n";
- $assocType = intval($this->in($prompt, null, __("Enter a number", true)));
-
- if (intval($assocType) < 1 || intval($assocType) > 4) {
- $this->out(__('The selection you entered was invalid. Please enter a number between 1 and 4.', true));
- } else {
- $bad = false;
- }
- }
- $this->out(__('For the following options be very careful to match your setup exactly. Any spelling mistakes will cause errors.', true));
- $this->hr();
- $alias = $this->in(__('What is the alias for this association?', true));
- $className = $this->in(sprintf(__('What className will %s use?', true), $alias), null, $alias );
- $suggestedForeignKey = null;
- if ($assocType == '1') {
- $showKeys = $possibleKeys[$model->table];
- $suggestedForeignKey = $this->_modelKey($alias);
- } else {
- $otherTable = Inflector::tableize($className);
- if (in_array($otherTable, $this->__tables)) {
- if ($assocType < '4') {
- $showKeys = $possibleKeys[$otherTable];
- } else {
- $showKeys = null;
- }
- } else {
- $otherTable = $this->in(__('What is the table for this model?', true));
- $showKeys = $possibleKeys[$otherTable];
- }
- $suggestedForeignKey = $this->_modelKey($model->name);
- }
- if (!empty($showKeys)) {
- $this->out(__('A helpful List of possible keys', true));
- for ($i = 0; $i < count($showKeys); $i++) {
- $this->out($i + 1 . ". " . $showKeys[$i]);
- }
- $foreignKey = $this->in(__('What is the foreignKey?', true), null, __("Enter a number", true));
- if (intval($foreignKey) > 0 && intval($foreignKey) <= $i ) {
- $foreignKey = $showKeys[intval($foreignKey) - 1];
- }
- }
- if (!isset($foreignKey)) {
- $foreignKey = $this->in(__('What is the foreignKey? Specify your own.', true), null, $suggestedForeignKey);
- }
- if ($assocType == '4') {
- $associationForeignKey = $this->in(__('What is the associationForeignKey?', true), null, $this->_modelKey($model->name));
- $joinTable = $this->in(__('What is the joinTable?', true));
- }
- $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]);
- $count = count($associations[$assocs[$assocType]]);
- $i = ($count > 0) ? $count : 0;
- $associations[$assocs[$assocType]][$i]['alias'] = $alias;
- $associations[$assocs[$assocType]][$i]['className'] = $className;
- $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
- if ($assocType == '4') {
- $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
- $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
- }
- $wannaDoMoreAssoc = $this->in(__('Define another association?', true), array('y','n'), 'y');
+/**
+ * Find belongsTo relations and add them to the associations list.
+ *
+ * @param object $model Model instance of model being generated.
+ * @param array $associations Array of inprogress associations
+ * @return array $associations with belongsTo added in.
+ **/
+ function findBelongsTo(&$model, $associations) {
+ $fields = $model->schema();
+ foreach ($fields as $fieldName => $field) {
+ $offset = strpos($fieldName, '_id');
+ if ($fieldName != $model->primaryKey && $fieldName != 'parent_id' && $offset !== false) {
+ $tmpModelName = $this->_modelNameFromKey($fieldName);
+ $associations['belongsTo'][] = array(
+ 'alias' => $tmpModelName,
+ 'className' => $tmpModelName,
+ 'foreignKey' => $fieldName,
+ );
+ } elseif ($fieldName == 'parent_id') {
+ $associations['belongsTo'][] = array(
+ 'alias' => 'Parent' . $model->name,
+ 'className' => $model->name,
+ 'foreignKey' => $fieldName,
+ );
}
}
return $associations;
}
+
+/**
+ * Find the hasOne and HasMany relations and add them to associations list
+ *
+ * @param object $model Model instance being generated
+ * @param array $associations Array of inprogress associations
+ * @return array $associations with hasOne and hasMany added in.
+ **/
+ function findHasOneAndMany(&$model, $associations) {
+ $foreignKey = $this->_modelKey($model->name);
+ foreach ($this->__tables as $otherTable) {
+ $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable));
+ $modelFieldsTemp = $tempOtherModel->schema();
+
+ $pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/';
+ $possibleJoinTable = preg_match($pattern , $otherTable);
+ if ($possibleJoinTable == true) {
+ continue;
+ }
+ foreach ($modelFieldsTemp as $fieldName => $field) {
+ $assoc = false;
+ if ($fieldName != $model->primaryKey && $fieldName == $foreignKey) {
+ $assoc = array(
+ 'alias' => $tempOtherModel->name,
+ 'className' => $tempOtherModel->name,
+ 'foreignKey' => $fieldName
+ );
+ } elseif ($otherTable == $model->table && $fieldName == 'parent_id') {
+ $assoc = array(
+ 'alias' => 'Child' . $model->name,
+ 'className' => $model->name,
+ 'foreignKey' => $fieldName
+ );
+ }
+ if ($assoc) {
+ $associations['hasOne'][] = $assoc;
+ $associations['hasMany'][] = $assoc;
+ }
+
+ }
+ }
+ return $associations;
+ }
+
+/**
+ * Find the hasAndBelongsToMany relations and add them to associations list
+ *
+ * @param object $model Model instance being generated
+ * @param array $associations Array of inprogress associations
+ * @return array $associations with hasAndBelongsToMany added in.
+ **/
+ function findHasAndBelongsToMany(&$model, $associations) {
+ $foreignKey = $this->_modelKey($model->name);
+ foreach ($this->__tables as $otherTable) {
+ $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable));
+ $modelFieldsTemp = $tempOtherModel->schema();
+
+ $offset = strpos($otherTable, $model->table . '_');
+ $otherOffset = strpos($otherTable, '_' . $model->table);
+
+ if ($offset !== false) {
+ $offset = strlen($model->table . '_');
+ $habtmName = $this->_modelName(substr($otherTable, $offset));
+ $associations['hasAndBelongsToMany'][] = array(
+ 'alias' => $habtmName,
+ 'className' => $habtmName,
+ 'foreignKey' => $foreignKey,
+ 'associationForeignKey' => $this->_modelKey($habtmName),
+ 'joinTable' => $otherTable
+ );
+ } elseif ($otherOffset !== false) {
+ $habtmName = $this->_modelName(substr($otherTable, 0, $otherOffset));
+ $associations['hasAndBelongsToMany'][] = array(
+ 'alias' => $habtmName,
+ 'className' => $habtmName,
+ 'foreignKey' => $foreignKey,
+ 'associationForeignKey' => $this->_modelKey($habtmName),
+ 'joinTable' => $otherTable
+ );
+ }
+ }
+ return $associations;
+ }
+
+/**
+ * Interact with the user and confirm associations.
+ *
+ * @param array $model Temporary Model instance.
+ * @param array $associations Array of associations to be confirmed.
+ * @return array Array of confirmed associations
+ **/
+ function confirmAssociations(&$model, $associations) {
+ foreach ($associations as $type => $settings) {
+ if (!empty($associations[$type])) {
+ $count = count($associations[$type]);
+ $response = 'y';
+ for ($i = 0; $i < $count; $i++) {
+ $prompt = "{$model->name} {$type} {$associations[$type][$i]['alias']}";
+ $response = $this->in("{$prompt}?", array('y','n'), 'y');
+
+ if ('n' == low($response)) {
+ unset($associations[$type][$i]);
+ } elseif ($type == 'hasMany') {
+ unset($associations['hasOne'][$i]);
+ }
+ }
+ $associations[$type] = array_merge($associations[$type]);
+ }
+ }
+ return $associations;
+ }
+
+/**
+ * Interact with the user and generate additional non-conventional associations
+ *
+ * @param object $model Temporary model instance
+ * @param array $associations Array of associations.
+ * @return array Array of associations.
+ **/
+ function doMoreAssociations($model, $associations) {
+ $prompt = __('Would you like to define some additional model associations?', true);
+ $wannaDoMoreAssoc = $this->in($prompt, array('y','n'), 'n');
+ $possibleKeys = $this->_generatePossibleKeys();
+ while (low($wannaDoMoreAssoc) == 'y') {
+ $assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
+ $this->out(__('What is the association type?', true));
+ $assocType = intval($this->inOptions($assocs, __('Enter a number',true)));
+
+ $this->out(__("For the following options be very careful to match your setup exactly.\nAny spelling mistakes will cause errors.", true));
+ $this->hr();
+
+ $alias = $this->in(__('What is the alias for this association?', true));
+ $className = $this->in(sprintf(__('What className will %s use?', true), $alias), null, $alias );
+ $suggestedForeignKey = null;
+
+ if ($assocType == 0) {
+ $showKeys = $possibleKeys[$model->table];
+ $suggestedForeignKey = $this->_modelKey($alias);
+ } else {
+ $otherTable = Inflector::tableize($className);
+ if (in_array($otherTable, $this->__tables)) {
+ if ($assocType < 3) {
+ $showKeys = $possibleKeys[$otherTable];
+ } else {
+ $showKeys = null;
+ }
+ } else {
+ $otherTable = $this->in(__('What is the table for this model?', true));
+ $showKeys = $possibleKeys[$otherTable];
+ }
+ $suggestedForeignKey = $this->_modelKey($model->name);
+ }
+ if (!empty($showKeys)) {
+ $this->out(__('A helpful List of possible keys', true));
+ $foreignKey = $this->inOptions($showKeys, __('What is the foreignKey?', true));
+ $foreignKey = $showKeys[intval($foreignKey)];
+ }
+ if (!isset($foreignKey)) {
+ $foreignKey = $this->in(__('What is the foreignKey? Specify your own.', true), null, $suggestedForeignKey);
+ }
+ if ($assocType == 3) {
+ $associationForeignKey = $this->in(__('What is the associationForeignKey?', true), null, $this->_modelKey($model->name));
+ $joinTable = $this->in(__('What is the joinTable?', true));
+ }
+ $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]);
+ $count = count($associations[$assocs[$assocType]]);
+ $i = ($count > 0) ? $count : 0;
+ $associations[$assocs[$assocType]][$i]['alias'] = $alias;
+ $associations[$assocs[$assocType]][$i]['className'] = $className;
+ $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
+ if ($assocType == 3) {
+ $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
+ $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
+ }
+ $wannaDoMoreAssoc = $this->in(__('Define another association?', true), array('y','n'), 'y');
+ }
+ return $associations;
+ }
+
+/**
+ * Finds all possible keys to use on custom associations.
+ *
+ * @return array array of tables and possible keys
+ **/
+ function _generatePossibleKeys() {
+ $possible = array();
+ foreach ($this->__tables as $otherTable) {
+ $tempOtherModel = & new Model(array('table' => $otherTable, 'ds' => $this->connection));
+ $modelFieldsTemp = $tempOtherModel->schema();
+ foreach ($modelFieldsTemp as $fieldName => $field) {
+ if ($field['type'] == 'integer' || $field['type'] == 'string') {
+ $possible[$otherTable][] = $fieldName;
+ }
+ }
+ }
+ return $possible;
+ }
+
/**
* Assembles and writes a Model file.
*
* @param mixed $name Model name or object
- * @param mixed $associations if array and $name is not an object assume Model associations array otherwise boolean interactive
- * @param array $validate Validation rules
- * @param string $primaryKey Primary key to use
- * @param string $useTable Table to use
- * @param string $useDbConfig Database configuration setting to use
+ * @param mixed $data if array and $name is not an object assume bake data, otherwise boolean.
* @access private
*/
- function bake($name, $associations = array(), $validate = array(), $primaryKey = 'id', $useTable = null, $useDbConfig = 'default') {
-
+ function bake($name, $data = array()) {
if (is_object($name)) {
- if (!is_array($associations)) {
- $associations = $this->doAssociations($name, $associations);
- $validate = $this->doValidation($name, $associations);
+ if ($data == false) {
+ $data = $associations = array();
+ $data['associations'] = $this->doAssociations($name, $associations);
+ $data['validate'] = $this->doValidation($name);
}
- $primaryKey = $name->primaryKey;
- $useTable = $name->table;
- $useDbConfig = $name->useDbConfig;
- $name = $name->name;
+ $data['primaryKey'] = $name->primaryKey;
+ $data['useTable'] = $name->table;
+ $data['useDbConfig'] = $name->useDbConfig;
+ $data['name'] = $name = $name->name;
+ } else {
+ $data['name'] = $name;
}
+ $defaults = array('associations' => array(), 'validate' => array(), 'primaryKey' => 'id',
+ 'useTable' => null, 'useDbConfig' => 'default', 'displayField' => null);
+ $data = array_merge($defaults, $data);
- $out = "plugin}AppModel {\n\n";
- $out .= "\tvar \$name = '{$name}';\n";
+ $this->Template->set($data);
+ $this->Template->set('plugin', Inflector::camelize($this->plugin));
+ $out = $this->Template->generate('classes', 'model');
- if ($useDbConfig !== 'default') {
- $out .= "\tvar \$useDbConfig = '$useDbConfig';\n";
+ $path = $this->path;
+ if (isset($this->plugin)) {
+ $path = $this->_pluginPath($this->plugin) . 'models' . DS;
}
-
- if (($useTable && $useTable !== Inflector::tableize($name)) || $useTable === false) {
- $table = "'$useTable'";
- if (!$useTable) {
- $table = 'false';
- }
- $out .= "\tvar \$useTable = $table;\n";
- }
-
- if ($primaryKey !== 'id') {
- $out .= "\tvar \$primaryKey = '$primaryKey';\n";
- }
-
- $validateCount = count($validate);
- if (is_array($validate) && $validateCount > 0) {
- $out .= "\tvar \$validate = array(\n";
- $keys = array_keys($validate);
- for ($i = 0; $i < $validateCount; $i++) {
- $val = "'" . $validate[$keys[$i]] . "'";
- $out .= "\t\t'" . $keys[$i] . "' => array({$val})";
- if ($i + 1 < $validateCount) {
- $out .= ",";
- }
- $out .= "\n";
- }
- $out .= "\t);\n";
- }
- $out .= "\n";
-
- if (!empty($associations)) {
- if (!empty($associations['belongsTo']) || !empty($associations['hasOne']) || !empty($associations['hasMany']) || !empty($associations['hasAndBelongsToMany'])) {
- $out.= "\t//The Associations below have been created with all possible keys, those that are not needed can be removed\n";
- }
-
- if (!empty($associations['belongsTo'])) {
- $out .= "\tvar \$belongsTo = array(\n";
- $belongsToCount = count($associations['belongsTo']);
-
- for ($i = 0; $i < $belongsToCount; $i++) {
- $out .= "\t\t'{$associations['belongsTo'][$i]['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$associations['belongsTo'][$i]['className']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$associations['belongsTo'][$i]['foreignKey']}',\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $belongsToCount) {
- $out .= ",";
- }
- $out .= "\n";
-
- }
- $out .= "\t);\n\n";
- }
-
- if (!empty($associations['hasOne'])) {
- $out .= "\tvar \$hasOne = array(\n";
- $hasOneCount = count($associations['hasOne']);
-
- for ($i = 0; $i < $hasOneCount; $i++) {
- $out .= "\t\t'{$associations['hasOne'][$i]['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$associations['hasOne'][$i]['className']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$associations['hasOne'][$i]['foreignKey']}',\n";
- $out .= "\t\t\t'dependent' => false,\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $hasOneCount) {
- $out .= ",";
- }
- $out .= "\n";
-
- }
- $out .= "\t);\n\n";
- }
-
- if (!empty($associations['hasMany'])) {
- $out .= "\tvar \$hasMany = array(\n";
- $hasManyCount = count($associations['hasMany']);
-
- for ($i = 0; $i < $hasManyCount; $i++) {
- $out .= "\t\t'{$associations['hasMany'][$i]['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$associations['hasMany'][$i]['className']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$associations['hasMany'][$i]['foreignKey']}',\n";
- $out .= "\t\t\t'dependent' => false,\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => '',\n";
- $out .= "\t\t\t'limit' => '',\n";
- $out .= "\t\t\t'offset' => '',\n";
- $out .= "\t\t\t'exclusive' => '',\n";
- $out .= "\t\t\t'finderQuery' => '',\n";
- $out .= "\t\t\t'counterQuery' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $hasManyCount) {
- $out .= ",";
- }
- $out .= "\n";
- }
- $out .= "\t);\n\n";
- }
-
- if (!empty($associations['hasAndBelongsToMany'])) {
- $out .= "\tvar \$hasAndBelongsToMany = array(\n";
- $hasAndBelongsToManyCount = count($associations['hasAndBelongsToMany']);
-
- for ($i = 0; $i < $hasAndBelongsToManyCount; $i++) {
- $out .= "\t\t'{$associations['hasAndBelongsToMany'][$i]['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$associations['hasAndBelongsToMany'][$i]['className']}',\n";
- $out .= "\t\t\t'joinTable' => '{$associations['hasAndBelongsToMany'][$i]['joinTable']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$associations['hasAndBelongsToMany'][$i]['foreignKey']}',\n";
- $out .= "\t\t\t'associationForeignKey' => '{$associations['hasAndBelongsToMany'][$i]['associationForeignKey']}',\n";
- $out .= "\t\t\t'unique' => true,\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => '',\n";
- $out .= "\t\t\t'limit' => '',\n";
- $out .= "\t\t\t'offset' => '',\n";
- $out .= "\t\t\t'finderQuery' => '',\n";
- $out .= "\t\t\t'deleteQuery' => '',\n";
- $out .= "\t\t\t'insertQuery' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $hasAndBelongsToManyCount) {
- $out .= ",";
- }
- $out .= "\n";
- }
- $out .= "\t);\n\n";
- }
- }
- $out .= "}\n";
- $out .= "?>";
- $filename = $this->path . Inflector::underscore($name) . '.php';
+ $filename = $path . Inflector::underscore($name) . '.php';
$this->out("\nBaking model class for $name...");
- return $this->createFile($filename, $out);
+ $this->createFile($filename, $out);
+ return $out;
}
/**
@@ -675,80 +757,75 @@ class ModelTask extends Shell {
* @param string $className Model class name
* @access private
*/
- function bakeTest($className, $useTable = null, $associations = array()) {
- $results = $this->fixture($className, $useTable);
-
- if ($results) {
- $fixtureInc = 'app';
- if ($this->plugin) {
- $fixtureInc = 'plugin.'.Inflector::underscore($this->plugin);
- }
-
- $fixture[] = "'{$fixtureInc}." . Inflector::underscore($className) ."'";
-
- if (!empty($associations)) {
- $assoc[] = Set::extract($associations, 'belongsTo.{n}.className');
- $assoc[] = Set::extract($associations, 'hasOne.{n}.className');
- $assoc[] = Set::extract($associations, 'hasMany.{n}.className');
- foreach ($assoc as $key => $value) {
- if (is_array($value)) {
- foreach ($value as $class) {
- $fixture[] = "'{$fixtureInc}." . Inflector::underscore($class) ."'";
- }
- }
- }
- }
- $fixture = join(", ", $fixture);
-
- $import = $className;
- if (isset($this->plugin)) {
- $import = $this->plugin . '.' . $className;
- }
-
- $out = "App::import('Model', '$import');\n\n";
- $out .= "class {$className}TestCase extends CakeTestCase {\n";
- $out .= "\tvar \${$className} = null;\n";
- $out .= "\tvar \$fixtures = array($fixture);\n\n";
- $out .= "\tfunction startTest() {\n";
- $out .= "\t\t\$this->{$className} =& ClassRegistry::init('{$className}');\n";
- $out .= "\t}\n\n";
- $out .= "\tfunction test{$className}Instance() {\n";
- $out .= "\t\t\$this->assertTrue(is_a(\$this->{$className}, '{$className}'));\n";
- $out .= "\t}\n\n";
- $out .= "\tfunction test{$className}Find() {\n";
- $out .= "\t\t\$this->{$className}->recursive = -1;\n";
- $out .= "\t\t\$results = \$this->{$className}->find('first');\n\t\t\$this->assertTrue(!empty(\$results));\n\n";
- $out .= "\t\t\$expected = array('$className' => array(\n$results\n\t\t));\n";
- $out .= "\t\t\$this->assertEqual(\$results, \$expected);\n";
- $out .= "\t}\n";
- $out .= "}\n";
-
- $path = MODEL_TESTS;
- if (isset($this->plugin)) {
- $pluginPath = 'plugins' . DS . Inflector::underscore($this->plugin) . DS;
- $path = APP . $pluginPath . 'tests' . DS . 'cases' . DS . 'models' . DS;
- }
-
- $filename = Inflector::underscore($className).'.test.php';
- $this->out("\nBaking unit test for $className...");
-
- $header = '$Id';
- $content = "";
- return $this->createFile($path . $filename, $content);
- }
- return false;
+ function bakeTest($className) {
+ $this->Test->plugin = $this->plugin;
+ $this->Test->connection = $this->connection;
+ return $this->Test->bake('Model', $className);
}
+
/**
* outputs the a list of possible models or controllers from database
*
* @param string $useDbConfig Database configuration name
* @access public
*/
- function listAll($useDbConfig = 'default', $interactive = true) {
+ function listAll($useDbConfig = null) {
+ $this->__tables = $this->getAllTables($useDbConfig);
+
+ if ($this->interactive === true) {
+ $this->out(__('Possible Models based on your current database:', true));
+ $this->_modelNames = array();
+ $count = count($this->__tables);
+ for ($i = 0; $i < $count; $i++) {
+ $this->_modelNames[] = $this->_modelName($this->__tables[$i]);
+ $this->out($i + 1 . ". " . $this->_modelNames[$i]);
+ }
+ }
+ return $this->__tables;
+ }
+
+/**
+ * Interact with the user to determine the table name of a particular model
+ *
+ * @param string $modelName Name of the model you want a table for.
+ * @param string $useDbConfig Name of the database config you want to get tables from.
+ * @return void
+ **/
+ function getTable($modelName, $useDbConfig = null) {
+ if (!isset($useDbConfig)) {
+ $useDbConfig = $this->connection;
+ }
+ $db =& ConnectionManager::getDataSource($useDbConfig);
+ $useTable = Inflector::tableize($modelName);
+ $fullTableName = $db->fullTableName($useTable, false);
+ $tableIsGood = false;
+
+ if (array_search($useTable, $this->__tables) === false) {
+ $this->out('');
+ $this->out(sprintf(__("Given your model named '%s',\nCake would expect a database table named '%s'", true), $modelName, $fullTableName));
+ $tableIsGood = $this->in(__('Do you want to use this table?', true), array('y','n'), 'y');
+ }
+ if (strtolower($tableIsGood) == 'n') {
+ $useTable = $this->in(__('What is the name of the table?', true));
+ }
+ return $useTable;
+ }
+
+/**
+ * Get an Array of all the tables in the supplied connection
+ * will halt the script if no tables are found.
+ *
+ * @param string $useDbConfig Connection name to scan.
+ * @return array Array of tables in the database.
+ **/
+ function getAllTables($useDbConfig = null) {
+ if (!isset($useDbConfig)) {
+ $useDbConfig = $this->connection;
+ }
+ $tables = array();
$db =& ConnectionManager::getDataSource($useDbConfig);
$usePrefix = empty($db->config['prefix']) ? '' : $db->config['prefix'];
if ($usePrefix) {
- $tables = array();
foreach ($db->listSources() as $table) {
if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
$tables[] = substr($table, strlen($usePrefix));
@@ -761,32 +838,22 @@ class ModelTask extends Shell {
$this->err(__('Your database does not have any tables.', true));
$this->_stop();
}
-
- $this->__tables = $tables;
-
- if ($interactive === true) {
- $this->out(__('Possible Models based on your current database:', true));
- $this->_modelNames = array();
- $count = count($tables);
- for ($i = 0; $i < $count; $i++) {
- $this->_modelNames[] = $this->_modelName($tables[$i]);
- $this->out($i + 1 . ". " . $this->_modelNames[$i]);
- }
- }
+ return $tables;
}
+
/**
* Forces the user to specify the model he wants to bake, and returns the selected model name.
*
* @return string the model name
* @access public
*/
- function getName($useDbConfig) {
+ function getName($useDbConfig = null) {
$this->listAll($useDbConfig);
$enteredModel = '';
while ($enteredModel == '') {
- $enteredModel = $this->in(__("Enter a number from the list above, type in the name of another model, or 'q' to exit", true), null, 'q');
+ $enteredModel = $this->in(__("Enter a number from the list above,\ntype in the name of another model, or 'q' to exit", true), null, 'q');
if ($enteredModel === 'q') {
$this->out(__("Exit", true));
@@ -794,19 +861,18 @@ class ModelTask extends Shell {
}
if ($enteredModel == '' || intval($enteredModel) > count($this->_modelNames)) {
- $this->err(__("The model name you supplied was empty, or the number you selected was not an option. Please try again.", true));
+ $this->err(__("The model name you supplied was empty,\nor the number you selected was not an option. Please try again.", true));
$enteredModel = '';
}
}
-
if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) {
$currentModelName = $this->_modelNames[intval($enteredModel) - 1];
} else {
$currentModelName = $enteredModel;
}
-
return $currentModelName;
}
+
/**
* Displays help contents
*
@@ -817,122 +883,32 @@ class ModelTask extends Shell {
$this->out("Usage: cake bake model ");
$this->hr();
$this->out('Commands:');
- $this->out("\n\tmodel\n\t\tbakes model in interactive mode.");
- $this->out("\n\tmodel \n\t\tbakes model file with no associations or validation");
+ $this->out('');
+ $this->out("model");
+ $this->out("\tbakes model in interactive mode.");
+ $this->out('');
+ $this->out("model ");
+ $this->out("\tbakes model file with no associations or validation");
+ $this->out('');
+ $this->out("model all");
+ $this->out("\tbakes all model files with associations and validation");
$this->out("");
$this->_stop();
}
+
/**
- * Builds the tests fixtures for the model and create the file
+ * Interact with FixtureTask to automatically bake fixtures when baking models.
*
- * @param string $model the name of the model
- * @param string $useTable table name
- * @return array $records, used in ModelTask::bakeTest() to create $expected
- * @todo move this to a task
- */
- function fixture($model, $useTable = null) {
- if (!class_exists('CakeSchema')) {
- App::import('Model', 'CakeSchema');
- }
- $out = "\nclass {$model}Fixture extends CakeTestFixture {\n";
- $out .= "\tvar \$name = '$model';\n";
-
- if (!$useTable) {
- $useTable = Inflector::tableize($model);
- } else {
- $out .= "\tvar \$table = '$useTable';\n";
- }
- $schema = new CakeSchema();
- $data = $schema->read(array('models' => false));
-
- if (!isset($data['tables'][$useTable])) {
- return false;
- }
- $tables[$model] = $data['tables'][$useTable];
-
- foreach ($tables as $table => $fields) {
- if (!is_numeric($table) && $table !== 'missing') {
- $out .= "\tvar \$fields = array(\n";
- $records = array();
- if (is_array($fields)) {
- $cols = array();
- foreach ($fields as $field => $value) {
- if ($field != 'indexes') {
- if (is_string($value)) {
- $type = $value;
- $value = array('type'=> $type);
- }
- $col = "\t\t'{$field}' => array('type'=>'" . $value['type'] . "', ";
-
- switch ($value['type']) {
- case 'integer':
- $insert = 1;
- break;
- case 'string';
- $insert = "Lorem ipsum dolor sit amet";
- if (!empty($value['length'])) {
- $insert = substr($insert, 0, (int)$value['length'] - 2);
- }
- $insert = "'$insert'";
- break;
- case 'datetime':
- $ts = date('Y-m-d H:i:s');
- $insert = "'$ts'";
- break;
- case 'date':
- $ts = date('Y-m-d');
- $insert = "'$ts'";
- break;
- case 'time':
- $ts = date('H:i:s');
- $insert = "'$ts'";
- break;
- case 'boolean':
- $insert = 1;
- break;
- case 'text':
- $insert =
- "'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,";
- $insert .= "phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,";
- $insert .= "vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,";
- $insert .= "feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.'";
- break;
- }
- $records[] = "\t\t'$field' => $insert";
- unset($value['type']);
- $col .= join(', ', $schema->__values($value));
- } else {
- $col = "\t\t'indexes' => array(";
- $props = array();
- foreach ((array)$value as $key => $index) {
- $props[] = "'{$key}' => array(".join(', ', $schema->__values($index)).")";
- }
- $col .= join(', ', $props);
- }
- $col .= ")";
- $cols[] = $col;
- }
- $out .= join(",\n", $cols);
- }
- $out .= "\n\t);\n";
- }
- }
- $records = join(",\n", $records);
- $out .= "\tvar \$records = array(array(\n$records\n\t));\n";
- $out .= "}\n";
- $path = TESTS . DS . 'fixtures' . DS;
- if (isset($this->plugin)) {
- $pluginPath = 'plugins' . DS . Inflector::underscore($this->plugin) . DS;
- $path = APP . $pluginPath . 'tests' . DS . 'fixtures' . DS;
- }
- $filename = Inflector::underscore($model).'_fixture.php';
- $header = '$Id';
- $content = "";
- $this->out("\nBaking test fixture for $model...");
- if ($this->createFile($path . $filename, $content)) {
- return str_replace("\t\t", "\t\t\t", $records);
- }
- return false;
+ * @param string $className Name of class to bake fixture for
+ * @param string $useTable Optional table name for fixture to use.
+ * @access public
+ * @return void
+ * @see FixtureTask::bake
+ **/
+ function bakeFixture($className, $useTable = null) {
+ $this->Fixture->connection = $this->connection;
+ $this->Fixture->plugin = $this->plugin;
+ $this->Fixture->bake($className, $useTable);
}
}
?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/plugin.php b/cake/console/libs/tasks/plugin.php
index 1fc81374b..833f67be6 100644
--- a/cake/console/libs/tasks/plugin.php
+++ b/cake/console/libs/tasks/plugin.php
@@ -1,5 +1,4 @@
path = APP . 'plugins' . DS;
}
+
/**
* Execution method always used for tasks
*
@@ -62,27 +60,27 @@ class PluginTask extends Shell {
function execute() {
if (empty($this->params['skel'])) {
$this->params['skel'] = '';
- if (is_dir(CAKE_CORE_INCLUDE_PATH.DS.'cake'.DS.'console'.DS.'libs'.DS.'templates'.DS.'skel') === true) {
- $this->params['skel'] = CAKE_CORE_INCLUDE_PATH.DS.'cake'.DS.'console'.DS.'libs'.DS.'templates'.DS.'skel';
+ if (is_dir(CAKE_CORE_INCLUDE_PATH . DS . CONSOLE_LIBS . 'templates' . DS . 'skel') === true) {
+ $this->params['skel'] = CAKE_CORE_INCLUDE_PATH . DS . CONSOLE_LIBS . 'templates' . DS . 'skel';
}
}
-
$plugin = null;
if (isset($this->args[0])) {
$plugin = Inflector::camelize($this->args[0]);
- $pluginPath = Inflector::underscore($plugin) . DS;
+ $pluginPath = $this->_pluginPath($plugin);
$this->Dispatch->shiftArgs();
- if (is_dir($this->path . $pluginPath)) {
- $this->out(sprintf('Plugin: %s', $plugin));
- $this->out(sprintf('Path: %s', $this->path . $pluginPath));
- $this->hr();
+ if (is_dir($pluginPath)) {
+ $this->out(sprintf(__('Plugin: %s', true), $plugin));
+ $this->out(sprintf(__('Path: %s', true), $pluginPath));
} elseif (isset($this->args[0])) {
- $this->err(sprintf('%s in path %s not found.', $plugin, $this->path . $pluginPath));
+ $this->err(sprintf(__('%s in path %s not found.', true), $plugin, $pluginPath));
$this->_stop();
} else {
$this->__interactive($plugin);
}
+ } else {
+ return $this->__interactive();
}
if (isset($this->args[0])) {
@@ -90,13 +88,13 @@ class PluginTask extends Shell {
$this->Dispatch->shiftArgs();
if (in_array($task, $this->tasks)) {
$this->{$task}->plugin = $plugin;
- $this->{$task}->path = $this->path . $pluginPath . Inflector::underscore(Inflector::pluralize($task)) . DS;
+ $this->{$task}->path = $pluginPath . Inflector::underscore(Inflector::pluralize($task)) . DS;
if (!is_dir($this->{$task}->path)) {
$this->err(sprintf(__("%s directory could not be found.\nBe sure you have created %s", true), $task, $this->{$task}->path));
}
$this->{$task}->loadTasks();
- $this->{$task}->execute();
+ return $this->{$task}->execute();
}
}
}
@@ -125,28 +123,49 @@ class PluginTask extends Shell {
* @return bool
*/
function bake($plugin) {
-
$pluginPath = Inflector::underscore($plugin);
+ $pathOptions = App::path('plugins');
+ if (count($pathOptions) > 1) {
+ $this->findPath($pathOptions);
+ }
+
$this->hr();
- $this->out("Plugin Name: $plugin");
- $this->out("Plugin Directory: {$this->path}{$pluginPath}");
+ $this->out(sprintf(__("Plugin Name: %s", true), $plugin));
+ $this->out(sprintf(__("Plugin Directory: %s", true), $this->path . $pluginPath));
$this->hr();
+ $looksGood = $this->in(__('Look okay?', true), array('y', 'n', 'q'), 'y');
- $looksGood = $this->in('Look okay?', array('y', 'n', 'q'), 'y');
-
- if (low($looksGood) == 'y' || low($looksGood) == 'yes') {
+ if (strtolower($looksGood) == 'y') {
$verbose = $this->in(__('Do you want verbose output?', true), array('y', 'n'), 'n');
- $Folder = new Folder($this->path . $pluginPath);
- $directories = array('models' . DS . 'behaviors', 'controllers' . DS . 'components', 'views' . DS . 'helpers');
+ $Folder =& new Folder($this->path . $pluginPath);
+ $directories = array(
+ 'config' . DS . 'sql',
+ 'models' . DS . 'behaviors',
+ 'controllers' . DS . 'components',
+ 'views' . DS . 'helpers',
+ 'tests' . DS . 'cases' . DS . 'components',
+ 'tests' . DS . 'cases' . DS . 'helpers',
+ 'tests' . DS . 'cases' . DS . 'behaviors',
+ 'tests' . DS . 'cases' . DS . 'controllers',
+ 'tests' . DS . 'cases' . DS . 'models',
+ 'tests' . DS . 'groups',
+ 'tests' . DS . 'fixtures',
+ 'vendors' . DS . 'img',
+ 'vendors' . DS . 'js',
+ 'vendors' . DS . 'css',
+ 'vendors' . DS . 'shells'
+ );
foreach ($directories as $directory) {
- $Folder->create($this->path . $pluginPath . DS . $directory);
+ $dirPath = $this->path . $pluginPath . DS . $directory;
+ $Folder->create($dirPath);
+ $File =& new File($dirPath . DS . 'empty', true);
}
- if (low($verbose) == 'y' || low($verbose) == 'yes') {
+ if (strtolower($verbose) == 'y') {
foreach ($Folder->messages() as $message) {
$this->out($message);
}
@@ -180,6 +199,28 @@ class PluginTask extends Shell {
return true;
}
+
+/**
+ * find and change $this->path to the user selection
+ *
+ * @return void
+ **/
+ function findPath($pathOptions) {
+ $valid = false;
+ $max = count($pathOptions);
+ while (!$valid) {
+ foreach ($pathOptions as $i => $option) {
+ $this->out($i + 1 .'. ' . $option);
+ }
+ $prompt = __('Choose a plugin path from the paths above.', true);
+ $choice = $this->in($prompt);
+ if (intval($choice) > 0 && intval($choice) <= $max) {
+ $valid = true;
+ }
+ }
+ $this->path = $pathOptions[$choice - 1];
+ }
+
/**
* Help
*
@@ -191,10 +232,18 @@ class PluginTask extends Shell {
$this->out("Usage: cake bake plugin ...");
$this->hr();
$this->out('Commands:');
- $this->out("\n\tplugin \n\t\tbakes plugin directory structure");
- $this->out("\n\tplugin model\n\t\tbakes model. Run 'cake bake model help' for more info.");
- $this->out("\n\tplugin controller\n\t\tbakes controller. Run 'cake bake controller help' for more info.");
- $this->out("\n\tplugin view\n\t\tbakes view. Run 'cake bake view help' for more info.");
+ $this->out('');
+ $this->out("plugin ");
+ $this->out("\tbakes plugin directory structure");
+ $this->out('');
+ $this->out("plugin model");
+ $this->out("\tbakes model. Run 'cake bake model help' for more info.");
+ $this->out('');
+ $this->out("plugin controller");
+ $this->out("\tbakes controller. Run 'cake bake controller help' for more info.");
+ $this->out('');
+ $this->out("plugin view");
+ $this->out("\tbakes view. Run 'cake bake view help' for more info.");
$this->out("");
$this->_stop();
}
diff --git a/cake/console/libs/tasks/project.php b/cake/console/libs/tasks/project.php
index 0502f8429..e14b5af78 100644
--- a/cake/console/libs/tasks/project.php
+++ b/cake/console/libs/tasks/project.php
@@ -1,32 +1,25 @@
in('A project already exists in this location: '.$project.' Overwrite?', array('y','n'), 'n');
+ $response = $this->in('A project already exists in this location: ' . $project . ' Overwrite?', array('y','n'), 'n');
if (strtolower($response) === 'n') {
$response = $project = false;
}
@@ -108,6 +109,7 @@ class ProjectTask extends Shell {
return true;
}
}
+
/**
* Looks for a skeleton template of a Cake application,
* and if not found asks the user for a path. When there is a path
@@ -144,7 +146,7 @@ class ProjectTask extends Shell {
$looksGood = $this->in('Look okay?', array('y', 'n', 'q'), 'y');
- if (low($looksGood) == 'y' || low($looksGood) == 'yes') {
+ if (strtolower($looksGood) == 'y') {
$verbose = $this->in(__('Do you want verbose output?', true), array('y', 'n'), 'n');
$Folder = new Folder($skel);
@@ -153,24 +155,25 @@ class ProjectTask extends Shell {
$this->out(sprintf(__("Created: %s in %s", true), $app, $path));
$this->hr();
} else {
- $this->err(" '".$app."' could not be created properly");
+ $this->err(" '" . $app . "' could not be created properly");
return false;
}
- if (low($verbose) == 'y' || low($verbose) == 'yes') {
+ if (strtolower($verbose) == 'y') {
foreach ($Folder->messages() as $message) {
$this->out($message);
}
}
return true;
- } elseif (low($looksGood) == 'q' || low($looksGood) == 'quit') {
+ } elseif (strtolower($looksGood) == 'q') {
$this->out('Bake Aborted.');
} else {
$this->execute(false);
return false;
}
}
+
/**
* Writes a file with a default home page to the project.
*
@@ -181,9 +184,10 @@ class ProjectTask extends Shell {
function createHome($dir) {
$app = basename($dir);
$path = $dir . 'views' . DS . 'pages' . DS;
- include(CAKE_CORE_INCLUDE_PATH.DS.'cake'.DS.'console'.DS.'libs'.DS.'templates'.DS.'views'.DS.'home.ctp');
+ include(CAKE_CORE_INCLUDE_PATH.DS.'cake'.DS.'console'.DS.'libs'.DS.'templates'.DS.'default'.DS.'views'.DS.'home.ctp');
return $this->createFile($path.'home.ctp', $output);
}
+
/**
* Generates and writes 'Security.salt'
*
@@ -207,6 +211,7 @@ class ProjectTask extends Shell {
}
return false;
}
+
/**
* Generates and writes CAKE_CORE_INCLUDE_PATH
*
@@ -219,7 +224,7 @@ class ProjectTask extends Shell {
$File =& new File($path . 'webroot' . DS . 'index.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*define\\(\\\'CAKE_CORE_INCLUDE_PATH\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
- $result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', '".CAKE_CORE_INCLUDE_PATH."');", $contents);
+ $result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', '" . CAKE_CORE_INCLUDE_PATH . "');", $contents);
if (!$File->write($result)) {
return false;
}
@@ -230,7 +235,7 @@ class ProjectTask extends Shell {
$File =& new File($path . 'webroot' . DS . 'test.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*define\\(\\\'CAKE_CORE_INCLUDE_PATH\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
- $result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', '".CAKE_CORE_INCLUDE_PATH."');", $contents);
+ $result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', '" . CAKE_CORE_INCLUDE_PATH . "');", $contents);
if (!$File->write($result)) {
return false;
}
@@ -240,6 +245,7 @@ class ProjectTask extends Shell {
return true;
}
}
+
/**
* Enables Configure::read('Routing.admin') in /app/config/core.php
*
@@ -248,7 +254,8 @@ class ProjectTask extends Shell {
* @access public
*/
function cakeAdmin($name) {
- $File =& new File(CONFIGS . 'core.php');
+ $path = (empty($this->configPath)) ? CONFIGS : $this->configPath;
+ $File =& new File($path . 'core.php');
$contents = $File->read();
if (preg_match('%([/\\t\\x20]*Configure::write\(\'Routing.admin\',[\\t\\x20\'a-z]*\\);)%', $contents, $match)) {
$result = str_replace($match[0], "\t" . 'Configure::write(\'Routing.admin\', \''.$name.'\');', $contents);
@@ -262,6 +269,34 @@ class ProjectTask extends Shell {
return false;
}
}
+
+/**
+ * Checks for Configure::read('Routing.admin') and forces user to input it if not enabled
+ *
+ * @return string Admin route to use
+ * @access public
+ */
+ function getAdmin() {
+ $admin = '';
+ $cakeAdmin = null;
+ $adminRoute = Configure::read('Routing.admin');
+ if (!empty($adminRoute)) {
+ return $adminRoute . '_';
+ }
+ $this->out('You need to enable Configure::write(\'Routing.admin\',\'admin\') in /app/config/core.php to use admin routing.');
+ $this->out('What would you like the admin route to be?');
+ $this->out('Example: www.example.com/admin/controller');
+ while ($admin == '') {
+ $admin = $this->in("What would you like the admin route to be?", null, 'admin');
+ }
+ if ($this->cakeAdmin($admin) !== true) {
+ $this->out('Unable to write to /app/config/core.php.');
+ $this->out('You need to enable Configure::write(\'Routing.admin\',\'admin\') in /app/config/core.php to use admin routing.');
+ $this->_stop();
+ }
+ return $admin . '_';
+ }
+
/**
* Help
*
@@ -273,7 +308,10 @@ class ProjectTask extends Shell {
$this->out("Usage: cake bake project ");
$this->hr();
$this->out('Commands:');
- $this->out("\n\tproject \n\t\tbakes app directory structure.\n\t\tif begins with '/' path is absolute.");
+ $this->out('');
+ $this->out("project ");
+ $this->out("\tbakes app directory structure.");
+ $this->out("\tif begins with '/' path is absolute.");
$this->out("");
$this->_stop();
}
diff --git a/cake/console/libs/tasks/template.php b/cake/console/libs/tasks/template.php
new file mode 100644
index 000000000..2fa426ddb
--- /dev/null
+++ b/cake/console/libs/tasks/template.php
@@ -0,0 +1,191 @@
+ $path
+ *
+ * @var array
+ **/
+ var $templatePaths = array();
+
+/**
+ * Initialize callback. Setup paths for the template task.
+ *
+ * @access public
+ * @return void
+ **/
+ function initialize() {
+ $this->templatePaths = $this->_findThemes();
+ }
+
+/**
+ * Find the paths to all the installed shell themes in the app.
+ *
+ * Bake themes are directories not named `skel` inside a `vendors/shells/templates` path.
+ *
+ * @return array Array of bake themes that are installed.
+ **/
+ function _findThemes() {
+ $paths = $this->Dispatch->shellPaths;
+ $themes = array();
+ foreach ($paths as $path) {
+ $Folder =& new Folder($path . 'templates', false);
+ $contents = $Folder->read();
+ $subDirs = $contents[0];
+ foreach ($subDirs as $dir) {
+ if (empty($dir) || $dir == 'skel') {
+ continue;
+ }
+ $templateDir = $path . 'templates' . DS . $dir . DS;
+ $themes[$dir] = $templateDir;
+ }
+ }
+ return $themes;
+ }
+
+/**
+ * Set variable values to the template scope
+ *
+ * @param mixed $one A string or an array of data.
+ * @param mixed $two Value in case $one is a string (which then works as the key).
+ * Unused if $one is an associative array, otherwise serves as the values to $one's keys.
+ * @return void
+ */
+ function set($one, $two = null) {
+ $data = null;
+ if (is_array($one)) {
+ if (is_array($two)) {
+ $data = array_combine($one, $two);
+ } else {
+ $data = $one;
+ }
+ } else {
+ $data = array($one => $two);
+ }
+
+ if ($data == null) {
+ return false;
+ }
+
+ foreach ($data as $name => $value) {
+ $this->templateVars[$name] = $value;
+ }
+ }
+
+/**
+ * Runs the template
+ *
+ * @param string $directory directory / type of thing you want
+ * @param string $filename template name
+ * @param string $vars Additional vars to set to template scope.
+ * @access public
+ * @return contents of generated code template
+ **/
+ function generate($directory, $filename, $vars = null) {
+ if ($vars !== null) {
+ $this->set($vars);
+ }
+ if (empty($this->templatePaths)) {
+ $this->initialize();
+ }
+ $themePath = $this->getThemePath();
+ $templateFile = $this->_findTemplate($themePath, $directory, $filename);
+ if ($templateFile) {
+ extract($this->templateVars);
+ ob_start();
+ ob_implicit_flush(0);
+ include($templateFile);
+ $content = ob_get_clean();
+ return $content;
+ }
+ return '';
+ }
+
+/**
+ * Find the theme name for the current operation.
+ * If there is only one theme in $templatePaths it will be used.
+ * If there is a -theme param in the cli args, it will be used.
+ * If there is more than one installed theme user interaction will happen
+ *
+ * @return string returns the path to the selected theme.
+ **/
+ function getThemePath() {
+ if (count($this->templatePaths) == 1) {
+ $paths = array_values($this->templatePaths);
+ return $paths[0];
+ }
+ if (!empty($this->params['theme']) && isset($this->templatePaths[$this->params['theme']])) {
+ return $this->templatePaths[$this->params['theme']];
+ }
+
+ $this->hr();
+ $this->out(__('You have more than one set of templates installed.', true));
+ $this->out(__('Please choose the template set you wish to use:', true));
+ $this->hr();
+
+ $i = 1;
+ $indexedPaths = array();
+ foreach ($this->templatePaths as $key => $path) {
+ $this->out($i . '. ' . $key);
+ $indexedPaths[$i] = $path;
+ $i++;
+ }
+ $index = $this->in(__('Which bake theme would you like to use?', true), range(1, $i - 1), 1);
+ $themeNames = array_keys($this->templatePaths);
+ $this->Dispatch->params['theme'] = $themeNames[$index - 1];
+ return $indexedPaths[$index];
+ }
+
+/**
+ * Find a template inside a directory inside a path.
+ * Will scan all other theme dirs if the template is not found in the first directory.
+ *
+ * @param string $path The initial path to look for the file on. If it is not found fallbacks will be used.
+ * @param string $directory Subdirectory to look for ie. 'views', 'objects'
+ * @param string $filename lower_case_underscored filename you want.
+ * @access public
+ * @return string filename will exit program if template is not found.
+ **/
+ function _findTemplate($path, $directory, $filename) {
+ $themeFile = $path . $directory . DS . $filename . '.ctp';
+ if (file_exists($themeFile)) {
+ return $themeFile;
+ }
+ foreach ($this->templatePaths as $path) {
+ $templatePath = $path . $directory . DS . $filename . '.ctp';
+ if (file_exists($templatePath)) {
+ return $templatePath;
+ }
+ }
+ $this->err(sprintf(__('Could not find template for %s', true), $filename));
+ $this->_stop();
+ return false;
+ }
+}
+?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/test.php b/cake/console/libs/tasks/test.php
index 45b853448..9978c66e4 100644
--- a/cake/console/libs/tasks/test.php
+++ b/cake/console/libs/tasks/test.php
@@ -1,29 +1,24 @@
args) > 1) {
- $class = Inflector::underscore($this->args[0]);
- if ($this->bake($class, $this->args[1])) {
+ $type = Inflector::underscore($this->args[0]);
+ if ($this->bake($type, $this->args[1])) {
$this->out('done');
}
}
}
+
/**
* Handles interactive baking
*
* @access private
*/
- function __interactive($class = null) {
+ function __interactive($type = null) {
+ $this->interactive = true;
$this->hr();
- $this->out(sprintf("Bake Tests\nPath: %s", $this->path));
+ $this->out(__('Bake Tests', true));
+ $this->out(sprintf(__("Path: %s", true), $this->path));
$this->hr();
- $key = null;
- $options = array('Behavior', 'Helper', 'Component', 'Model', 'Controller');
-
- if ($class !== null) {
- $class = Inflector::camelize($class);
- if (in_array($class, $options)) {
- $key = array_search($class);
+ $selection = null;
+ if ($type) {
+ $type = Inflector::camelize($type);
+ if (!in_array($type, $this->classTypes)) {
+ unset($type);
}
}
-
- while ($class == null) {
- $cases = array();
- $this->hr();
- $this->out("Select a class:");
- $this->hr();
-
- $keys = array();
- foreach ($options as $key => $option) {
- $this->out(++$key . '. ' . $option);
- $keys[] = $key;
- }
- $keys[] = 'q';
-
- $key = $this->in(__("Enter the class to test or (q)uit", true), $keys, 'q');
-
- if ($key != 'q') {
- if (isset($options[--$key])) {
- $class = $options[$key];
- }
-
- if ($class) {
- $name = $this->in(__("Enter the name for the test or (q)uit", true), null, 'q');
- if ($name !== 'q') {
- $case = null;
- while ($case !== 'q') {
- $case = $this->in(__("Enter a test case or (q)uit", true), null, 'q');
- if ($case !== 'q') {
- $cases[] = $case;
- }
- }
- if ($this->bake($class, $name, $cases)) {
- $this->out(__("Test baked\n", true));
- $type = null;
- }
- $class = null;
- }
- }
- } else {
- $this->_stop();
- }
+ if (!$type) {
+ $type = $this->getObjectType();
}
+ $className = $this->getClassName($type);
+ return $this->bake($type, $className);
}
+
/**
- * Writes File
+ * Completes final steps for generating data to create test case.
*
+ * @param string $type Type of object to bake test case for ie. Model, Controller
+ * @param string $className the 'cake name' for the class ie. Posts for the PostsController
* @access public
*/
- function bake($class, $name = null, $cases = array()) {
- if (!$name) {
- return false;
+ function bake($type, $className) {
+ if ($this->typeCanDetectFixtures($type) && $this->isLoadableClass($type, $className)) {
+ $this->out(__('Bake is detecting possible fixtures..', true));
+ $testSubject =& $this->buildTestSubject($type, $className);
+ $this->generateFixtureList($testSubject);
+ } elseif ($this->interactive) {
+ $this->getUserFixtures();
+ }
+ $fullClassName = $this->getRealClassName($type, $className);
+
+ $methods = array();
+ if (class_exists($fullClassName)) {
+ $methods = $this->getTestableMethods($fullClassName);
+ }
+ $mock = $this->hasMockClass($type, $fullClassName);
+ $construction = $this->generateConstructor($type, $fullClassName);
+
+ $plugin = null;
+ if ($this->plugin) {
+ $plugin = $this->plugin . '.';
}
- if (!is_array($cases)) {
- $cases = array($cases);
- }
+ $this->Template->set('fixtures', $this->_fixtures);
+ $this->Template->set('plugin', $plugin);
+ $this->Template->set(compact('className', 'methods', 'type', 'fullClassName', 'mock', 'construction'));
+ $out = $this->Template->generate('classes', 'test');
- if (strpos($this->path, $class) === false) {
- $this->filePath = $this->path . 'cases' . DS . Inflector::tableize($class) . DS;
+ $filename = $this->testCaseFileName($type, $className);
+ $made = $this->createFile($filename, $out);
+ if ($made) {
+ return $out;
}
-
- $class = Inflector::classify($class);
- $name = Inflector::classify($name);
-
- $import = $name;
- if (isset($this->plugin)) {
- $import = $this->plugin . '.' . $name;
- }
- $extras = $this->__extras($class);
- $out = "App::import('$class', '$import');\n";
- if ($class == 'Model') {
- $class = null;
- }
- $out .= "class Test{$name} extends {$name}{$class} {\n";
- $out .= "{$extras}";
- $out .= "}\n\n";
- $out .= "class {$name}{$class}Test extends CakeTestCase {\n";
- $out .= "\n\tfunction startTest() {";
- $out .= "\n\t\t\$this->{$name} = new Test{$name}();";
- $out .= "\n\t}\n";
- $out .= "\n\tfunction test{$name}Instance() {\n";
- $out .= "\t\t\$this->assertTrue(is_a(\$this->{$name}, '{$name}{$class}'));\n\t}\n";
- foreach ($cases as $case) {
- $case = Inflector::classify($case);
- $out .= "\n\tfunction test{$case}() {\n\n\t}\n";
- }
- $out .= "}\n";
-
- $this->out("Baking unit test for $name...");
- $this->out($out);
- $ok = $this->in(__('Is this correct?', true), array('y', 'n'), 'y');
- if ($ok == 'n') {
- return false;
- }
-
- $header = '$Id';
- $content = "";
- return $this->createFile($this->filePath . Inflector::underscore($name) . '.test.php', $content);
+ return false;
}
+
/**
- * Handles the extra stuff needed
+ * Interact with the user and get their chosen type. Can exit the script.
*
- * @access private
- */
- function __extras($class) {
- $extras = null;
- switch ($class) {
- case 'Model':
- $extras = "\n\tvar \$cacheSources = false;";
- $extras .= "\n\tvar \$useDbConfig = 'test_suite';\n";
- break;
+ * @return string Users chosen type.
+ **/
+ function getObjectType() {
+ $this->hr();
+ $this->out(__("Select an object type:", true));
+ $this->hr();
+
+ $keys = array();
+ foreach ($this->classTypes as $key => $option) {
+ $this->out(++$key . '. ' . $option);
+ $keys[] = $key;
}
- return $extras;
+ $keys[] = 'q';
+ $selection = $this->in(__("Enter the type of object to bake a test for or (q)uit", true), $keys, 'q');
+ if ($selection == 'q') {
+ return $this->_stop();
+ }
+ return $this->classTypes[$selection - 1];
+ }
+
+/**
+ * Get the user chosen Class name for the chosen type
+ *
+ * @param string $objectType Type of object to list classes for i.e. Model, Controller.
+ * @return string Class name the user chose.
+ **/
+ function getClassName($objectType) {
+ $options = Configure::listObjects(strtolower($objectType));
+ $this->out(sprintf(__('Choose a %s class', true), $objectType));
+ $keys = array();
+ foreach ($options as $key => $option) {
+ $this->out(++$key . '. ' . $option);
+ $keys[] = $key;
+ }
+ $selection = $this->in(__('Choose an existing class, or enter the name of a class that does not exist', true));
+ if (isset($options[$selection - 1])) {
+ return $options[$selection - 1];
+ }
+ return $selection;
+ }
+
+/**
+ * Checks whether the chosen type can find its own fixtures.
+ * Currently only model, and controller are supported
+ *
+ * @return boolean
+ **/
+ function typeCanDetectFixtures($type) {
+ $type = strtolower($type);
+ return ($type == 'controller' || $type == 'model');
+ }
+
+/**
+ * Check if a class with the given type is loaded or can be loaded.
+ *
+ * @return boolean
+ **/
+ function isLoadableClass($type, $class) {
+ return App::import($type, $class);
+ }
+
+/**
+ * Construct an instance of the class to be tested.
+ * So that fixtures can be detected
+ *
+ * @return object
+ **/
+ function &buildTestSubject($type, $class) {
+ ClassRegistry::flush();
+ App::import($type, $class);
+ $class = $this->getRealClassName($type, $class);
+ if (strtolower($type) == 'model') {
+ $instance =& ClassRegistry::init($class);
+ } else {
+ $instance =& new $class();
+ }
+ return $instance;
+ }
+
+/**
+ * Gets the real class name from the cake short form.
+ *
+ * @return string Real classname
+ **/
+ function getRealClassName($type, $class) {
+ if (strtolower($type) == 'model') {
+ return $class;
+ }
+ return $class . $type;
+ }
+
+/**
+ * Get methods declared in the class given.
+ * No parent methods will be returned
+ *
+ * @param string $className Name of class to look at.
+ * @return array Array of method names.
+ **/
+ function getTestableMethods($className) {
+ $classMethods = get_class_methods($className);
+ $parentMethods = get_class_methods(get_parent_class($className));
+ $thisMethods = array_diff($classMethods, $parentMethods);
+ $out = array();
+ foreach ($thisMethods as $method) {
+ if (substr($method, 0, 1) != '_') {
+ $out[] = $method;
+ }
+ }
+ return $out;
+ }
+
+/**
+ * Generate the list of fixtures that will be required to run this test based on
+ * loaded models.
+ *
+ * @param object The object you want to generate fixtures for.
+ * @return array Array of fixtures to be included in the test.
+ **/
+ function generateFixtureList(&$subject) {
+ $this->_fixtures = array();
+ if (is_a($subject, 'Model')) {
+ $this->_processModel($subject);
+ } elseif (is_a($subject, 'Controller')) {
+ $this->_processController($subject);
+ }
+ return array_values($this->_fixtures);
+ }
+
+/**
+ * Process a model recursively and pull out all the
+ * model names converting them to fixture names.
+ *
+ * @return void
+ * @access protected
+ **/
+ function _processModel(&$subject) {
+ $this->_addFixture($subject->name);
+ $associated = $subject->getAssociated();
+ foreach ($associated as $alias => $type) {
+ $className = $subject->{$alias}->name;
+ if (!isset($this->_fixtures[$className])) {
+ $this->_processModel($subject->{$alias});
+ }
+ if ($type == 'hasAndBelongsToMany') {
+ $joinModel = Inflector::classify($subject->hasAndBelongsToMany[$alias]['joinTable']);
+ if (!isset($this->_fixtures[$joinModel])) {
+ $this->_processModel($subject->{$joinModel});
+ }
+ }
+ }
+ }
+
+/**
+ * Process all the models attached to a controller
+ * and generate a fixture list.
+ *
+ * @return void
+ * @access protected
+ **/
+ function _processController(&$subject) {
+ $subject->constructClasses();
+ $models = array(Inflector::classify($subject->name));
+ if (!empty($subject->uses)) {
+ $models = $subject->uses;
+ }
+ foreach ($models as $model) {
+ $this->_processModel($subject->{$model});
+ }
+ }
+
+/**
+ * Add classname to the fixture list.
+ * Sets the app. or plugin.plugin_name. prefix.
+ *
+ * @return void
+ * @access protected
+ **/
+ function _addFixture($name) {
+ $parent = get_parent_class($name);
+ $prefix = 'app.';
+ if (strtolower($parent) != 'appmodel' && strtolower(substr($parent, -8)) == 'appmodel') {
+ $pluginName = substr($parent, 0, strlen($parent) -8);
+ $prefix = 'plugin.' . Inflector::underscore($pluginName) . '.';
+ }
+ $fixture = $prefix . Inflector::underscore($name);
+ $this->_fixtures[$name] = $fixture;
+ }
+
+/**
+ * Interact with the user to get additional fixtures they want to use.
+ *
+ * @return void
+ **/
+ function getUserFixtures() {
+ $proceed = $this->in(__('Bake could not detect fixtures, would you like to add some?', true), array('y','n'), 'n');
+ $fixtures = array();
+ if (strtolower($proceed) == 'y') {
+ $fixtureList = $this->in(__("Please provide a comma separated list of the fixtures names you'd like to use.\nExample: 'app.comment, app.post, plugin.forums.post'", true));
+ $fixtureListTrimmed = str_replace(' ', '', $fixtureList);
+ $fixtures = explode(',', $fixtureListTrimmed);
+ }
+ $this->_fixtures = array_merge($this->_fixtures, $fixtures);
+ return $fixtures;
+ }
+
+/**
+ * Is a mock class required for this type of test?
+ * Controllers require a mock class.
+ *
+ * @return boolean
+ **/
+ function hasMockClass($type) {
+ $type = strtolower($type);
+ return $type == 'controller';
+ }
+
+/**
+ * Generate a constructor code snippet for the type and classname
+ *
+ * @return string Constructor snippet for the thing you are building.
+ **/
+ function generateConstructor($type, $fullClassName) {
+ $type = strtolower($type);
+ if ($type == 'model') {
+ return "ClassRegistry::init('$fullClassName');\n";
+ }
+ if ($type == 'controller') {
+ return "new Test$fullClassName();\n\t\t\$this->{$fullClassName}->constructClasses();\n";
+ }
+ return "new $fullClassName()\n";
+ }
+
+/**
+ * make the filename for the test case. resolve the suffixes for controllers
+ * and get the plugin path if needed.
+ *
+ * @return string filename the test should be created on
+ **/
+ function testCaseFileName($type, $className) {
+ $path = $this->path;
+ if (isset($this->plugin)) {
+ $path = $this->_pluginPath($this->plugin) . 'tests' . DS;
+ }
+ $path .= 'cases' . DS . Inflector::tableize($type) . DS;
+ if (strtolower($type) == 'controller') {
+ $className = $this->getRealClassName($type, $className);
+ }
+ return $path . Inflector::underscore($className) . '.test.php';
}
}
?>
\ No newline at end of file
diff --git a/cake/console/libs/tasks/view.php b/cake/console/libs/tasks/view.php
index 4dfdc5089..18e86b995 100644
--- a/cake/console/libs/tasks/view.php
+++ b/cake/console/libs/tasks/view.php
@@ -1,5 +1,4 @@
args[0])) {
+ if (!isset($this->connection)) {
+ $this->connection = 'default';
+ }
$controller = $action = $alias = null;
$this->controllerName = Inflector::camelize($this->args[0]);
$this->controllerPath = Inflector::underscore($this->controllerName);
@@ -115,37 +124,92 @@ class ViewTask extends Shell {
$action = $this->template;
}
+ if (strtolower($this->args[0]) == 'all') {
+ return $this->all();
+ }
+
if (in_array($action, $this->scaffoldActions)) {
$this->bake($action, true);
} elseif ($action) {
$this->bake($action, true);
} else {
$vars = $this->__loadController();
- if ($vars) {
-
- $methods = array_diff(
- array_map('strtolower', get_class_methods($this->controllerName . 'Controller')),
- array_map('strtolower', get_class_methods('appcontroller'))
- );
- if (empty($methods)) {
- $methods = $this->scaffoldActions;
- }
- $adminDelete = null;
-
- $adminRoute = Configure::read('Routing.admin');
- if (!empty($adminRoute)) {
- $adminDelete = $adminRoute.'_delete';
- }
- foreach ($methods as $method) {
- if ($method{0} != '_' && !in_array($method, array('delete', $adminDelete))) {
- $content = $this->getContent($method, $vars);
- $this->bake($method, $content);
+ $methods = $this->_methodsToBake();
+ $methods = array_diff(
+ array_map('strtolower', get_class_methods($this->controllerName . 'Controller')),
+ array_map('strtolower', get_class_methods('appcontroller'))
+ );
+ if (empty($methods)) {
+ $methods = $this->scaffoldActions;
+ }
+ $adminRoute = Configure::read('Routing.admin');
+ if ($adminRoute && isset($this->params['admin'])) {
+ foreach ($methods as $i => $method) {
+ if (strpos($method, $adminRoute . '_') === false) {
+ unset($methods[$i]);
}
}
}
+ $adminDelete = null;
+ if (!empty($adminRoute)) {
+ $adminDelete = $adminRoute . '_delete';
+ }
+ foreach ($methods as $method) {
+ if ($method{0} != '_' && !in_array($method, array('delete', $adminDelete))) {
+ $content = $this->getContent($method, $vars);
+ $this->bake($method, $content);
+ }
+ }
}
}
}
+
+/**
+ * Get a list of actions that can / should have views baked for them.
+ *
+ * @return array Array of action names that should be baked
+ **/
+ function _methodsToBake() {
+ $methods = array_diff(
+ array_map('strtolower', get_class_methods($this->controllerName . 'Controller')),
+ array_map('strtolower', get_class_methods('appcontroller'))
+ );
+ if (empty($methods)) {
+ $methods = $this->scaffoldActions;
+ }
+ $adminRoute = Configure::read('Routing.admin');
+ foreach ($methods as $i => $method) {
+ if ($method == 'delete' || $method = $adminRoute . '_delete' || $method{0} == '_') {
+ unset($methods[$i]);
+ }
+ if ($adminRoute && isset($this->params['admin']) && strpos($method, $adminRoute . '_') === false) {
+ unset($methods[$i]);
+ }
+ }
+ return $methods;
+ }
+
+/**
+ * Bake All views for All controllers.
+ *
+ * @return void
+ **/
+ function all() {
+ $actions = $this->scaffoldActions;
+ $this->Controller->interactive = false;
+ $tables = $this->Controller->listAll($this->connection, false);
+ $this->interactive = false;
+ foreach ($tables as $table) {
+ $model = $this->_modelName($table);
+ $this->controllerName = $this->_controllerName($model);
+ $this->controllerPath = Inflector::underscore($this->controllerName);
+ if (App::import('Model', $model)) {
+ $vars = $this->__loadController();
+ $this->bakeActions($actions, $vars);
+ }
+ }
+ }
+
/**
* Handles interactive baking
*
@@ -155,72 +219,51 @@ class ViewTask extends Shell {
$this->hr();
$this->out(sprintf("Bake View\nPath: %s", $this->path));
$this->hr();
- $wannaDoAdmin = 'n';
- $wannaDoScaffold = 'y';
- $this->interactive = false;
+ if (empty($this->connection)) {
+ $this->connection = $this->DbConfig->getConfig();
+ }
+
+ $this->Controller->connection = $this->connection;
$this->controllerName = $this->Controller->getName();
- $this->controllerPath = low(Inflector::underscore($this->controllerName));
+ $this->controllerPath = strtolower(Inflector::underscore($this->controllerName));
- $interactive = $this->in("Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite {$this->controllerName} views if it exist.", array('y','n'), 'y');
+ $prompt = sprintf(__("Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite %s views if it exist.", true), $this->controllerName);
+ $interactive = $this->in($prompt, array('y', 'n'), 'n');
- if (low($interactive) == 'y' || low($interactive) == 'yes') {
- $this->interactive = true;
- $wannaDoScaffold = $this->in("Would you like to create some scaffolded views (index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller and model classes (including associated models).", array('y','n'), 'n');
+ if (strtolower($interactive) == 'n') {
+ $this->interactive = false;
}
- if (low($wannaDoScaffold) == 'y' || low($wannaDoScaffold) == 'yes') {
- $wannaDoAdmin = $this->in("Would you like to create the views for admin routing?", array('y','n'), 'y');
- }
- $admin = false;
+ $prompt = __("Would you like to create some CRUD views\n(index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller\nand model classes (including associated models).", true);
+ $wannaDoScaffold = $this->in($prompt, array('y','n'), 'y');
- if ((low($wannaDoAdmin) == 'y' || low($wannaDoAdmin) == 'yes')) {
- $admin = $this->getAdmin();
- }
+ $wannaDoAdmin = $this->in(__("Would you like to create the views for admin routing?", true), array('y','n'), 'n');
- if (low($wannaDoScaffold) == 'y' || low($wannaDoScaffold) == 'yes') {
- $actions = $this->scaffoldActions;
- if ($admin) {
- foreach ($actions as $action) {
- $actions[] = $admin . $action;
- }
- }
+ if (strtolower($wannaDoScaffold) == 'y' || strtolower($wannaDoAdmin) == 'y') {
$vars = $this->__loadController();
- if ($vars) {
- foreach ($actions as $action) {
- $content = $this->getContent($action, $vars);
- $this->bake($action, $content);
+ if (strtolower($wannaDoScaffold) == 'y') {
+ $actions = $this->scaffoldActions;
+ $this->bakeActions($actions, $vars);
+ }
+ if (strtolower($wannaDoAdmin) == 'y') {
+ $admin = $this->Project->getAdmin();
+ $regularActions = $this->scaffoldActions;
+ $adminActions = array();
+ foreach ($regularActions as $action) {
+ $adminActions[] = $admin . $action;
}
+ $this->bakeActions($adminActions, $vars);
}
$this->hr();
$this->out('');
- $this->out('View Scaffolding Complete.'."\n");
+ $this->out(__("View Scaffolding Complete.\n", true));
} else {
- $action = '';
- while ($action == '') {
- $action = $this->in('Action Name? (use camelCased function name)');
- if ($action == '') {
- $this->out('The action name you supplied was empty. Please try again.');
- }
- }
- $this->out('');
- $this->hr();
- $this->out('The following view will be created:');
- $this->hr();
- $this->out("Controller Name: {$this->controllerName}");
- $this->out("Action Name: {$action}");
- $this->out("Path: ".$this->params['app'] . DS . $this->controllerPath . DS . Inflector::underscore($action) . ".ctp");
- $this->hr();
- $looksGood = $this->in('Look okay?', array('y','n'), 'y');
- if (low($looksGood) == 'y' || low($looksGood) == 'yes') {
- $this->bake($action);
- $this->_stop();
- } else {
- $this->out('Bake Aborted.');
- }
+ $this->customAction();
}
}
+
/**
* Loads Controller and sets variables for the template
* Available template variables
@@ -247,7 +290,7 @@ class ViewTask extends Shell {
$this->_stop();
}
$controllerClassName = $this->controllerName . 'Controller';
- $controllerObj = & new $controllerClassName();
+ $controllerObj =& new $controllerClassName();
$controllerObj->constructClasses();
$modelClass = $controllerObj->modelClass;
$modelObj =& ClassRegistry::getObject($controllerObj->modelKey);
@@ -277,6 +320,50 @@ class ViewTask extends Shell {
return compact('modelClass', 'schema', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
'singularHumanName', 'pluralHumanName', 'fields','associations');
}
+
+/**
+ * Bake a view file for each of the supplied actions
+ *
+ * @param array $actions Array of actions to make files for.
+ * @return void
+ **/
+ function bakeActions($actions, $vars) {
+ foreach ($actions as $action) {
+ $content = $this->getContent($action, $vars);
+ $this->bake($action, $content);
+ }
+ }
+
+/**
+ * handle creation of baking a custom action view file
+ *
+ * @return void
+ **/
+ function customAction() {
+ $action = '';
+ while ($action == '') {
+ $action = $this->in(__('Action Name? (use lowercase_underscored function name)', true));
+ if ($action == '') {
+ $this->out(__('The action name you supplied was empty. Please try again.', true));
+ }
+ }
+ $this->out('');
+ $this->hr();
+ $this->out(__('The following view will be created:', true));
+ $this->hr();
+ $this->out(sprintf(__('Controller Name: %s', true), $this->controllerName));
+ $this->out(sprintf(__('Action Name: %s', true), $action));
+ $this->out(sprintf(__('Path: %s', true), $this->params['app'] . DS . $this->controllerPath . DS . Inflector::underscore($action) . ".ctp"));
+ $this->hr();
+ $looksGood = $this->in(__('Look okay?', true), array('y','n'), 'y');
+ if (strtolower($looksGood) == 'y') {
+ $this->bake($action);
+ $this->_stop();
+ } else {
+ $this->out(__('Bake Aborted.', true));
+ }
+ }
+
/**
* Assembles and writes bakes the view file.
*
@@ -287,21 +374,16 @@ class ViewTask extends Shell {
*/
function bake($action, $content = '') {
if ($content === true) {
- $content = $this->getContent();
+ $content = $this->getContent($action);
}
- $filename = $this->path . $this->controllerPath . DS . Inflector::underscore($action) . '.ctp';
- $Folder =& new Folder($this->path . $this->controllerPath, true);
- $errors = $Folder->errors();
- if (empty($errors)) {
- $path = $Folder->slashTerm($Folder->pwd());
- return $this->createFile($filename, $content);
- } else {
- foreach ($errors as $error) {
- $this->err($error);
- }
+ $path = $this->path;
+ if (isset($this->plugin)) {
+ $path = $this->_pluginPath($this->plugin) . 'views' . DS;
}
- return false;
+ $filename = $path . $this->controllerPath . DS . Inflector::underscore($action) . '.ctp';
+ return $this->createFile($filename, $content);
}
+
/**
* Builds content from template and variables
*
@@ -318,35 +400,29 @@ class ViewTask extends Shell {
$adminRoute = Configure::read('Routing.admin');
if (!empty($adminRoute) && strpos($template, $adminRoute) !== false) {
- $template = str_replace($adminRoute.'_', '', $template);
+ $template = str_replace($adminRoute . '_', '', $template);
}
if (in_array($template, array('add', 'edit'))) {
$action = $template;
$template = 'form';
}
- $loaded = false;
- foreach ($this->Dispatch->shellPaths as $path) {
- $templatePath = $path . 'templates' . DS . 'views' . DS .Inflector::underscore($template).'.ctp';
- if (file_exists($templatePath) && is_file($templatePath)) {
- $loaded = true;
- break;
- }
- }
if (!$vars) {
$vars = $this->__loadController();
}
- if ($loaded) {
- extract($vars);
- ob_start();
- ob_implicit_flush(0);
- include($templatePath);
- $content = ob_get_clean();
- return $content;
+
+ $this->Template->set('action', $action);
+ $this->Template->set('plugin', $this->plugin);
+ $this->Template->set($vars);
+ $output = $this->Template->generate('views', $template);
+
+ if (!empty($output)) {
+ return $output;
}
$this->hr();
$this->err(sprintf(__('Template for %s could not be found', true), $template));
return false;
}
+
/**
* Displays help contents
*
@@ -357,12 +433,28 @@ class ViewTask extends Shell {
$this->out("Usage: cake bake view ...");
$this->hr();
$this->out('Commands:');
- $this->out("\n\tview \n\t\twill read the given controller for methods\n\t\tand bake corresponding views.\n\t\tIf var scaffold is found it will bake the scaffolded actions\n\t\t(index,view,add,edit)");
- $this->out("\n\tview \n\t\twill bake a template. core templates: (index, add, edit, view)");
- $this->out("\n\tview \n\t\twill use the template specified but name the file based on the alias");
- $this->out("");
+ $this->out('');
+ $this->out("view ");
+ $this->out("\tWill read the given controller for methods");
+ $this->out("\tand bake corresponding views.");
+ $this->out("\tUsing the -admin flag will only bake views for actions");
+ $this->out("\tthat begin with Routing.admin.");
+ $this->out("\tIf var scaffold is found it will bake the CRUD actions");
+ $this->out("\t(index,view,add,edit)");
+ $this->out('');
+ $this->out("view ");
+ $this->out("\tWill bake a template. core templates: (index, add, edit, view)");
+ $this->out('');
+ $this->out("view ");
+ $this->out("\tWill use the template specified");
+ $this->out("\tbut name the file based on the alias");
+ $this->out('');
+ $this->out("view all");
+ $this->out("\tBake all CRUD action views for all controllers.");
+ $this->out("\tRequires that models and controllers exist.");
$this->_stop();
}
+
/**
* Returns associations for controllers models.
*
diff --git a/cake/console/libs/templates/default/actions/controller_actions.ctp b/cake/console/libs/templates/default/actions/controller_actions.ctp
new file mode 100644
index 000000000..30b1e1459
--- /dev/null
+++ b/cake/console/libs/templates/default/actions/controller_actions.ctp
@@ -0,0 +1,142 @@
+
+
+ function index() {
+ $this->->recursive = 0;
+ $this->set('', $this->paginate());
+ }
+
+ function view($id = null) {
+ if (!$id) {
+
+ $this->Session->setFlash(__('Invalid ', true));
+ $this->redirect(array('action' => 'index'));
+
+ $this->flash(__('Invalid ', true), array('action' => 'index'));
+
+ }
+ $this->set('', $this->->read(null, $id));
+ }
+
+
+ function add() {
+ if (!empty($this->data)) {
+ $this->->create();
+ if ($this->->save($this->data)) {
+
+ $this->Session->setFlash(__('The has been saved', true));
+ $this->redirect(array('action' => 'index'));
+
+ $this->flash(__(' saved.', true), array('action' => 'index'));
+
+ } else {
+
+ $this->Session->setFlash(__('The could not be saved. Please, try again.', true));
+
+ }
+ }
+{$assoc} as $associationName => $relation):
+ if (!empty($associationName)):
+ $otherModelName = $this->_modelName($associationName);
+ $otherPluralName = $this->_pluralName($associationName);
+ echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n";
+ $compact[] = "'{$otherPluralName}'";
+ endif;
+ endforeach;
+ endforeach;
+ if (!empty($compact)):
+ echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
+ endif;
+?>
+ }
+
+
+ function edit($id = null) {
+ if (!$id && empty($this->data)) {
+
+ $this->Session->setFlash(__('Invalid ', true));
+ $this->redirect(array('action' => 'index'));
+
+ $this->flash(__('Invalid ', true), array('action' => 'index'));
+
+ }
+ if (!empty($this->data)) {
+ if ($this->->save($this->data)) {
+
+ $this->Session->setFlash(__('The has been saved', true));
+ $this->redirect(array('action' => 'index'));
+
+ $this->flash(__('The has been saved.', true), array('action' => 'index'));
+
+ } else {
+
+ $this->Session->setFlash(__('The could not be saved. Please, try again.', true));
+
+ }
+ }
+ if (empty($this->data)) {
+ $this->data = $this->->read(null, $id);
+ }
+{$assoc} as $associationName => $relation):
+ if (!empty($associationName)):
+ $otherModelName = $this->_modelName($associationName);
+ $otherPluralName = $this->_pluralName($associationName);
+ echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n";
+ $compact[] = "'{$otherPluralName}'";
+ endif;
+ endforeach;
+ endforeach;
+ if (!empty($compact)):
+ echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
+ endif;
+ ?>
+ }
+
+ function delete($id = null) {
+ if (!$id) {
+
+ $this->Session->setFlash(__('Invalid id for ', true));
+ $this->redirect(array('action'=>'index'));
+
+ $this->flash(__('Invalid ', true), array('action' => 'index'));
+
+ }
+ if ($this->->del($id)) {
+
+ $this->Session->setFlash(__(' deleted', true));
+ $this->redirect(array('action'=>'index'));
+
+ $this->flash(__(' deleted', true), array('action' => 'index'));
+
+ }
+
+ $this->Session->setFlash(__(' was not deleted', true));
+
+ $this->flash(__(' was not deleted', true), array('action' => 'index'));
+
+ $this->redirect(array('action' => 'index'));
+ }
\ No newline at end of file
diff --git a/cake/console/libs/templates/default/classes/controller.ctp b/cake/console/libs/templates/default/classes/controller.ctp
new file mode 100644
index 000000000..539210d2e
--- /dev/null
+++ b/cake/console/libs/templates/default/classes/controller.ctp
@@ -0,0 +1,57 @@
+
+class Controller extends AppController {
+
+ var $name = '';
+
+ var $scaffold;
+
+
+}
+"; ?>
\ No newline at end of file
diff --git a/cake/console/libs/templates/default/classes/fixture.ctp b/cake/console/libs/templates/default/classes/fixture.ctp
new file mode 100644
index 000000000..aa8c0678c
--- /dev/null
+++ b/cake/console/libs/templates/default/classes/fixture.ctp
@@ -0,0 +1,42 @@
+
+
+/* Fixture generated on: */
+class Fixture extends CakeTestFixture {
+ var $name = '';
+
+ var $table = '';
+
+
+ var $import = ;
+
+
+
+ var $fields = ;
+
+
+
+ var $records = ;
+
+}
+'; ?>
\ No newline at end of file
diff --git a/cake/console/libs/templates/default/classes/model.ctp b/cake/console/libs/templates/default/classes/model.ctp
new file mode 100644
index 000000000..7ca0c8c80
--- /dev/null
+++ b/cake/console/libs/templates/default/classes/model.ctp
@@ -0,0 +1,130 @@
+
+class extends AppModel {
+ var $name = '';
+
+ var $useDbConfig = '';
+
+
+ var $primaryKey = '';
+
+ var $displayField = '';
+ $validations):
+ echo "\t\t'$field' => array(\n";
+ foreach ($validations as $key => $validator):
+ echo "\t\t\t'$key' => array('rule' => array('$validator')),\n";
+ endforeach;
+ echo "\t\t),\n";
+ endforeach;
+ echo "\t);\n";
+endif;
+
+?>
+ //The Associations below have been created with all possible keys, those that are not needed can be removed
+ $relation):
+ $out = "\n\t\t'{$relation['alias']}' => array(\n";
+ $out .= "\t\t\t'className' => '{$relation['className']}',\n";
+ $out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
+ $out .= "\t\t\t'conditions' => '',\n";
+ $out .= "\t\t\t'fields' => '',\n";
+ $out .= "\t\t\t'order' => ''\n";
+ $out .= "\t\t)";
+ if ($i + 1 < $typeCount) {
+ $out .= ",";
+ }
+ echo $out;
+ endforeach;
+ echo "\n\t);\n";
+ endif;
+endforeach;
+
+if (!empty($associations['hasMany'])):
+ $belongsToCount = count($associations['hasMany']);
+ echo "\n\tvar \$hasMany = array(";
+ foreach ($associations['hasMany'] as $i => $relation):
+ $out = "\n\t\t'{$relation['alias']}' => array(\n";
+ $out .= "\t\t\t'className' => '{$relation['className']}',\n";
+ $out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
+ $out .= "\t\t\t'dependent' => false,\n";
+ $out .= "\t\t\t'conditions' => '',\n";
+ $out .= "\t\t\t'fields' => '',\n";
+ $out .= "\t\t\t'order' => '',\n";
+ $out .= "\t\t\t'limit' => '',\n";
+ $out .= "\t\t\t'offset' => '',\n";
+ $out .= "\t\t\t'exclusive' => '',\n";
+ $out .= "\t\t\t'finderQuery' => '',\n";
+ $out .= "\t\t\t'counterQuery' => ''\n";
+ $out .= "\t\t)";
+ if ($i + 1 < $belongsToCount) {
+ $out .= ",";
+ }
+ echo $out;
+ endforeach;
+ echo "\n\t);\n\n";
+endif;
+
+if (!empty($associations['hasAndBelongsToMany'])):
+ $habtmCount = count($associations['hasAndBelongsToMany']);
+ echo "\n\tvar \$hasAndBelongsToMany = array(";
+ foreach ($associations['hasAndBelongsToMany'] as $i => $relation):
+ $out = "\n\t\t'{$relation['alias']}' => array(\n";
+ $out .= "\t\t\t'className' => '{$relation['className']}',\n";
+ $out .= "\t\t\t'joinTable' => '{$relation['joinTable']}',\n";
+ $out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
+ $out .= "\t\t\t'associationForeignKey' => '{$relation['associationForeignKey']}',\n";
+ $out .= "\t\t\t'unique' => true,\n";
+ $out .= "\t\t\t'conditions' => '',\n";
+ $out .= "\t\t\t'fields' => '',\n";
+ $out .= "\t\t\t'order' => '',\n";
+ $out .= "\t\t\t'limit' => '',\n";
+ $out .= "\t\t\t'offset' => '',\n";
+ $out .= "\t\t\t'finderQuery' => '',\n";
+ $out .= "\t\t\t'deleteQuery' => '',\n";
+ $out .= "\t\t\t'insertQuery' => ''\n";
+ $out .= "\t\t)";
+ if ($i + 1 < $habtmCount) {
+ $out .= ",";
+ }
+ echo $out;
+ endforeach;
+ echo "\n\t);\n\n";
+endif;
+?>
+}
+'; ?>
\ No newline at end of file
diff --git a/cake/console/libs/templates/default/classes/test.ctp b/cake/console/libs/templates/default/classes/test.ctp
new file mode 100644
index 000000000..f84220c30
--- /dev/null
+++ b/cake/console/libs/templates/default/classes/test.ctp
@@ -0,0 +1,57 @@
+
+App::import('', '');
+
+
+class Test extends {
+ var $autoRender = false;
+
+ function redirect($url, $status = null, $exit = true) {
+ $this->redirectUrl = $url;
+ }
+}
+
+
+class TestCase extends CakeTestCase {
+
+ var $fixtures = array('');
+
+
+ function startTest() {
+ $this->
+ }
+
+ function endTest() {
+ unset($this->);
+ ClassRegistry::flush();
+ }
+
+
+ function test() {
+
+ }
+
+
+}
+'; ?>
\ No newline at end of file
diff --git a/cake/console/libs/templates/views/form.ctp b/cake/console/libs/templates/default/views/form.ctp
similarity index 81%
rename from cake/console/libs/templates/views/form.ctp
rename to cake/console/libs/templates/default/views/form.ctp
index 78ebdda7b..264221c3d 100644
--- a/cake/console/libs/templates/views/form.ctp
+++ b/cake/console/libs/templates/default/views/form.ctp
@@ -1,5 +1,6 @@
form">
create('{$modelClass}');?>\n";?>
- ";?>
+ ";?>
$data) {
foreach ($data as $alias => $details) {
if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
- echo "\t\tlink(__('List ".Inflector::humanize($details['controller'])."', true), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
- echo "\t\tlink(__('New ".Inflector::humanize(Inflector::underscore($alias))."', true), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
+ echo "\t\tlink(__('List " . Inflector::humanize($details['controller']) . "', true), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
+ echo "\t\tlink(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "', true), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
$done[] = $details['controller'];
}
}
}
?>
-
+
\ No newline at end of file
diff --git a/cake/console/libs/templates/views/home.ctp b/cake/console/libs/templates/default/views/home.ctp
similarity index 96%
rename from cake/console/libs/templates/views/home.ctp
rename to cake/console/libs/templates/default/views/home.ctp
index 39020d488..f97a8a4ef 100644
--- a/cake/console/libs/templates/views/home.ctp
+++ b/cake/console/libs/templates/default/views/home.ctp
@@ -1,5 +1,5 @@
Sweet, \"".Inflector::humanize($app)."\" got Baked by CakePHP!\n";
+$output = "Sweet, \"" . Inflector::humanize($app) . "\" got Baked by CakePHP! \n";
$output .="
0):
@@ -79,4 +79,4 @@ $output .= "\t\tYou can also add some CSS styles for your pages at: %s', true),\
$output .= "\t\tAPP . 'views' . DS . 'pages' . DS . 'home.ctp. ', APP . 'views' . DS . 'layouts' . DS . 'default.ctp. ', APP . 'webroot' . DS . 'css');\n";
$output .= "?>\n";
$output .= "
\n";
-?>
+?>
\ No newline at end of file
diff --git a/cake/console/libs/templates/views/index.ctp b/cake/console/libs/templates/default/views/index.ctp
similarity index 90%
rename from cake/console/libs/templates/views/index.ctp
rename to cake/console/libs/templates/default/views/index.ctp
index af2c5acb5..e68fea588 100644
--- a/cake/console/libs/templates/views/index.ctp
+++ b/cake/console/libs/templates/default/views/index.ctp
@@ -1,5 +1,6 @@
\n";
foreach ($associations as $type => $data) {
foreach ($data as $alias => $details) {
if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
- echo "\t\tlink(__('List ".Inflector::humanize($details['controller'])."', true), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
- echo "\t\tlink(__('New ".Inflector::humanize(Inflector::underscore($alias))."', true), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
+ echo "\t\tlink(__('List " . Inflector::humanize($details['controller']) . "', true), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
+ echo "\t\tlink(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "', true), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
$done[] = $details['controller'];
}
}
}
?>
-
+
\ No newline at end of file
diff --git a/cake/console/libs/templates/views/view.ctp b/cake/console/libs/templates/default/views/view.ctp
similarity index 81%
rename from cake/console/libs/templates/views/view.ctp
rename to cake/console/libs/templates/default/views/view.ctp
index a25b7574c..e79f06d81 100644
--- a/cake/console/libs/templates/views/view.ctp
+++ b/cake/console/libs/templates/default/views/view.ctp
@@ -1,5 +1,6 @@
$details) {
if ($field === $details['foreignKey']) {
$isKey = true;
- echo "\t\t> \n";
+ echo "\t\t> \n";
echo "\t\t>\n\t\t\tlink(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t\t \n\t\t \n";
break;
}
}
}
if ($isKey !== true) {
- echo "\t\t> \n";
+ echo "\t\t> \n";
echo "\t\t>\n\t\t\t\n\t\t\t \n\t\t \n";
}
}
@@ -58,8 +59,8 @@ foreach ($fields as $field) {
foreach ($associations as $type => $data) {
foreach ($data as $alias => $details) {
if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
- echo "\t\tlink(__('List ".Inflector::humanize($details['controller'])."', true), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
- echo "\t\tlink(__('New ".Inflector::humanize(Inflector::underscore($alias))."', true), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
+ echo "\t\tlink(__('List " . Inflector::humanize($details['controller']) . "', true), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
+ echo "\t\tlink(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "', true), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
$done[] = $details['controller'];
}
}
@@ -71,12 +72,12 @@ foreach ($fields as $field) {
if (!empty($associations['hasOne'])) :
foreach ($associations['hasOne'] as $alias => $details): ?>
@@ -110,7 +111,7 @@ foreach ($relations as $alias => $details):
\n";
+ echo "\t\t \n";
}
?>
";?>
@@ -143,7 +144,7 @@ echo "\t\n";
\n\n";?>
- link(__('New ".Inflector::humanize(Inflector::underscore($alias))."', true), array('controller' => '{$details['controller']}', 'action' => 'add'));?>";?>
+ link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "', true), array('controller' => '{$details['controller']}', 'action' => 'add'));?>";?>
diff --git a/cake/console/libs/templates/skel/app_controller.php b/cake/console/libs/templates/skel/app_controller.php
index 2412447bc..96c7ac334 100644
--- a/cake/console/libs/templates/skel/app_controller.php
+++ b/cake/console/libs/templates/skel/app_controller.php
@@ -1,5 +1,6 @@
array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
+ * 'models' => array('/full/path/to/models/', '/next/full/path/to/models/'),
+ * 'views' => array('/full/path/to/views/', '/next/full/path/to/views/'),
+ * 'controllers' => array(/full/path/to/controllers/', '/next/full/path/to/controllers/'),
+ * 'datasources' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'),
+ * 'behaviors' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'),
+ * 'components' => array('/full/path/to/components/', '/next/full/path/to/components/'),
+ * 'helpers' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
+ * 'vendors' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
+ * 'shells' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
+ * 'locales' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
+ * ));
+ *
+ */
+
+/**
+ * As of 1.3, additional rules for the inflector are added below
+ *
+ * Inflector::rule('singular', array('rules' => array(), irregular' => array(), 'uninflected' => array()));
+ * Inflector::rule('plural', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
*
*/
-//EOF
?>
\ No newline at end of file
diff --git a/cake/console/libs/templates/skel/config/core.php b/cake/console/libs/templates/skel/config/core.php
index fbd02e74a..8108c1999 100644
--- a/cake/console/libs/templates/skel/config/core.php
+++ b/cake/console/libs/templates/skel/config/core.php
@@ -1,5 +1,6 @@
value array of regex used to match words.
* If key matches then the value is returned.
@@ -32,6 +34,7 @@
* $pluralRules = array('/(s)tatus$/i' => '\1\2tatuses', '/^(ox)$/i' => '\1\2en', '/([m|l])ouse$/i' => '\1ice');
*/
$pluralRules = array();
+
/**
* This is a key only array of plural words that should not be inflected.
* Notice the last comma
@@ -39,6 +42,7 @@
* $uninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox');
*/
$uninflectedPlural = array();
+
/**
* This is a key => value array of plural irregular words.
* If key matches then the value is returned.
@@ -46,6 +50,7 @@
* $irregularPlural = array('atlas' => 'atlases', 'beef' => 'beefs', 'brother' => 'brothers')
*/
$irregularPlural = array();
+
/**
* This is a key => value array of regex used to match words.
* If key matches then the value is returned.
@@ -53,12 +58,14 @@
* $singularRules = array('/(s)tatuses$/i' => '\1\2tatus', '/(matr)ices$/i' =>'\1ix','/(vert|ind)ices$/i')
*/
$singularRules = array();
+
/**
* This is a key only array of singular words that should not be inflected.
* You should not have to change this value below if you do change it use same format
* as the $uninflectedPlural above.
*/
$uninflectedSingular = $uninflectedPlural;
+
/**
* This is a key => value array of singular irregular words.
* Most of the time this will be a reverse of the above $irregularPlural array
diff --git a/cake/console/libs/templates/skel/config/routes.php b/cake/console/libs/templates/skel/config/routes.php
index b14e435c3..77168cb45 100644
--- a/cake/console/libs/templates/skel/config/routes.php
+++ b/cake/console/libs/templates/skel/config/routes.php
@@ -1,5 +1,6 @@
'pages', 'action' => 'display', 'home'));
+
/**
* ...and connect the rest of 'Pages' controller's urls.
*/
diff --git a/cake/console/libs/templates/skel/config/sql/db_acl.php b/cake/console/libs/templates/skel/config/sql/db_acl.php
index 19434d0c6..99fe1d64e 100644
--- a/cake/console/libs/templates/skel/config/sql/db_acl.php
+++ b/cake/console/libs/templates/skel/config/sql/db_acl.php
@@ -1,6 +1,8 @@
This email was sent using the CakePHP Framework