Merge branch 'master' into 2.3

This commit is contained in:
mark_story 2012-08-09 20:43:47 -04:00
commit 4487673060
7 changed files with 143 additions and 88 deletions

View file

@ -64,70 +64,96 @@ class ConsoleShell extends AppShell {
foreach ($this->models as $model) { foreach ($this->models as $model) {
$this->out(" - {$model}"); $this->out(" - {$model}");
} }
$this->_loadRoutes();
if (!$this->_loadRoutes()) {
$message = __d(
'cake_console',
'There was an error loading the routes config. Please check that the file exists and contains no errors.'
);
$this->err($message);
}
} }
public function getOptionParser() {
$description = array(
'The interactive console is a tool for testing parts of your',
'app before you write code.',
'',
'See below for a list of supported commands.'
);
$epilog = array(
'<info>Model testing</info>',
'',
'To test model results, use the name of your model without a leading $',
'e.g. Foo->find("all")',
"",
'To dynamically set associations, you can do the following:',
'',
"\tModelA bind <association> ModelB",
'',
"where the supported associations are hasOne, hasMany, belongsTo, hasAndBelongsToMany",
"",
'To dynamically remove associations, you can do the following:',
'',
"\t ModelA unbind <association> ModelB",
'',
"where the supported associations are the same as above",
"",
"To save a new field in a model, you can do the following:",
'',
"\tModelA->save(array('foo' => 'bar', 'baz' => 0))",
'',
"where you are passing a hash of data to be saved in the format",
"of field => value pairs",
"",
"To get column information for a model, use the following:",
'',
"\tModelA columns",
'',
"which returns a list of columns and their type",
"",
'<info>Route testing</info>',
"",
'To test URLs against your app\'s route configuration, type:',
"",
"\tRoute <url>",
"",
"where url is the path to your your action plus any query parameters,",
"minus the application's base path. For example:",
"",
"\tRoute /posts/view/1",
"",
"will return something like the following:",
"",
"\tarray(",
"\t [...]",
"\t 'controller' => 'posts',",
"\t 'action' => 'view',",
"\t [...]",
"\t)",
"",
'Alternatively, you can use simple array syntax to test reverse',
'To reload your routes config (Config/routes.php), do the following:',
"",
"\tRoutes reload",
"",
'To show all connected routes, do the following:',
'',
"\tRoutes show",
);
return parent::getOptionParser()
->description($description)
->epilog($epilog);
}
/** /**
* Prints the help message * Prints the help message
* *
* @return void * @return void
*/ */
public function help() { public function help() {
$out = 'Console help:'; $optionParser = $this->getOptionParser();
$out .= '-------------'; $this->out($optionParser->epilog());
$out .= 'The interactive console is a tool for testing parts of your app before you';
$out .= 'write code.';
$out .= "\n";
$out .= 'Model testing:';
$out .= 'To test model results, use the name of your model without a leading $';
$out .= 'e.g. Foo->find("all")';
$out .= "\n";
$out .= 'To dynamically set associations, you can do the following:';
$out .= "\tModelA bind <association> ModelB";
$out .= "where the supported associations are hasOne, hasMany, belongsTo, hasAndBelongsToMany";
$out .= "\n";
$out .= 'To dynamically remove associations, you can do the following:';
$out .= "\t ModelA unbind <association> ModelB";
$out .= "where the supported associations are the same as above";
$out .= "\n";
$out .= "To save a new field in a model, you can do the following:";
$out .= "\tModelA->save(array('foo' => 'bar', 'baz' => 0))";
$out .= "where you are passing a hash of data to be saved in the format";
$out .= "of field => value pairs";
$out .= "\n";
$out .= "To get column information for a model, use the following:";
$out .= "\tModelA columns";
$out .= "which returns a list of columns and their type";
$out .= "\n";
$out .= "\n";
$out .= 'Route testing:';
$out .= "\n";
$out .= 'To test URLs against your app\'s route configuration, type:';
$out .= "\n";
$out .= "\tRoute <url>";
$out .= "\n";
$out .= "where url is the path to your your action plus any query parameters,";
$out .= "minus the application's base path. For example:";
$out .= "\n";
$out .= "\tRoute /posts/view/1";
$out .= "\n";
$out .= "will return something like the following:";
$out .= "\n";
$out .= "\tarray(";
$out .= "\t [...]";
$out .= "\t 'controller' => 'posts',";
$out .= "\t 'action' => 'view',";
$out .= "\t [...]";
$out .= "\t)";
$out .= "\n";
$out .= 'Alternatively, you can use simple array syntax to test reverse';
$out .= 'To reload your routes config (Config/routes.php), do the following:';
$out .= "\n";
$out .= "\tRoutes reload";
$out .= "\n";
$out .= 'To show all connected routes, do the following:';
$out .= "\tRoutes show";
$this->out($out);
} }
/** /**
@ -291,16 +317,14 @@ class ConsoleShell extends AppShell {
} }
break; break;
case (preg_match("/^routes\s+reload/i", $command, $tmp) == true): case (preg_match("/^routes\s+reload/i", $command, $tmp) == true):
$router = Router::getInstance();
if (!$this->_loadRoutes()) { if (!$this->_loadRoutes()) {
$this->out(__d('cake_console', "There was an error loading the routes config. Please check that the file exists and is free of parse errors.")); $this->err(__d('cake_console', "There was an error loading the routes config. Please check that the file exists and is free of parse errors."));
break; break;
} }
$this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count($router->routes))); $this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count(Router::$routes)));
break; break;
case (preg_match("/^routes\s+show/i", $command, $tmp) == true): case (preg_match("/^routes\s+show/i", $command, $tmp) == true):
$router = Router::getInstance(); $this->out(print_r(Hash::combine(Router::$routes, '{n}.template', '{n}.defaults'), true));
$this->out(implode("\n", Hash::extract($router->routes, '{n}.0')));
break; break;
case (preg_match("/^route\s+(\(.*\))$/i", $command, $tmp) == true): case (preg_match("/^route\s+(\(.*\))$/i", $command, $tmp) == true):
if ($url = eval('return array' . $tmp[1] . ';')) { if ($url = eval('return array' . $tmp[1] . ';')) {
@ -345,14 +369,6 @@ class ConsoleShell extends AppShell {
CakePlugin::routes(); CakePlugin::routes();
Router::parse('/'); Router::parse('/');
foreach (array_keys(Router::getNamedExpressions()) as $var) {
unset(${$var});
}
foreach (Router::$routes as $route) {
$route->compile();
}
return true; return true;
} }

View file

@ -411,11 +411,13 @@ class ModelTask extends BakeTask {
$this->hr(); $this->hr();
$optionText = ''; $optionText = '';
for ($i = 1, $m = $defaultChoice / 2; $i < $m; $i++) { for ($i = 1, $m = $defaultChoice / 2; $i <= $m; $i++) {
$line = sprintf("%2d. %s", $i, $this->_validations[$i]); $line = sprintf("%2d. %s", $i, $this->_validations[$i]);
$optionText .= $line . str_repeat(" ", 31 - strlen($line)); $optionText .= $line . str_repeat(" ", 31 - strlen($line));
if ($m + $i !== $defaultChoice) {
$optionText .= sprintf("%2d. %s\n", $m + $i, $this->_validations[$m + $i]); $optionText .= sprintf("%2d. %s\n", $m + $i, $this->_validations[$m + $i]);
} }
}
$this->out($optionText); $this->out($optionText);
$this->out(__d('cake_console', "%s - Do not do any validation on this field.", $defaultChoice)); $this->out(__d('cake_console', "%s - Do not do any validation on this field.", $defaultChoice));
$this->hr(); $this->hr();

View file

@ -25,17 +25,19 @@ $paths = explode(PATH_SEPARATOR, ini_get('include_path'));
foreach ($paths as $path) { foreach ($paths as $path) {
if (file_exists($path . $ds . $dispatcher)) { if (file_exists($path . $ds . $dispatcher)) {
$found = $path; $found = $path;
break;
} }
} }
if (!$found && function_exists('ini_set')) { if (!$found) {
$root = dirname(dirname(dirname(__FILE__))); $root = dirname(dirname(dirname(__FILE__)));
ini_set('include_path', $root . $ds . PATH_SEPARATOR . ini_get('include_path')); if (!include $root . $ds . $dispatcher) {
trigger_error('Could not locate CakePHP core files.', E_USER_ERROR);
}
} else {
include $found . $ds . $dispatcher;
} }
if (!include $dispatcher) {
trigger_error('Could not locate CakePHP core files.', E_USER_ERROR);
}
unset($paths, $path, $found, $dispatcher, $root, $ds); unset($paths, $path, $found, $dispatcher, $root, $ds);
return ShellDispatcher::run($argv); return ShellDispatcher::run($argv);

View file

@ -261,15 +261,11 @@ class Configure {
* @throws ConfigureException Will throw any exceptions the reader raises. * @throws ConfigureException Will throw any exceptions the reader raises.
*/ */
public static function load($key, $config = 'default', $merge = true) { public static function load($key, $config = 'default', $merge = true) {
if (!isset(self::$_readers[$config])) { $reader = self::_getReader($config);
if ($config === 'default') { if (!$reader) {
App::uses('PhpReader', 'Configure');
self::$_readers[$config] = new PhpReader();
} else {
return false; return false;
} }
} $values = $reader->read($key);
$values = self::$_readers[$config]->read($key);
if ($merge) { if ($merge) {
$keys = array_keys($values); $keys = array_keys($values);
@ -309,17 +305,36 @@ class Configure {
* @throws ConfigureException if the adapter does not implement a `dump` method. * @throws ConfigureException if the adapter does not implement a `dump` method.
*/ */
public static function dump($key, $config = 'default', $keys = array()) { public static function dump($key, $config = 'default', $keys = array()) {
if (empty(self::$_readers[$config])) { $reader = self::_getReader($config);
if (!$reader) {
throw new ConfigureException(__d('cake', 'There is no "%s" adapter.', $config)); throw new ConfigureException(__d('cake', 'There is no "%s" adapter.', $config));
} }
if (!method_exists(self::$_readers[$config], 'dump')) { if (!method_exists($reader, 'dump')) {
throw new ConfigureException(__d('cake', 'The "%s" adapter, does not have a dump() method.', $config)); throw new ConfigureException(__d('cake', 'The "%s" adapter, does not have a dump() method.', $config));
} }
$values = self::$_values; $values = self::$_values;
if (!empty($keys) && is_array($keys)) { if (!empty($keys) && is_array($keys)) {
$values = array_intersect_key($values, array_flip($keys)); $values = array_intersect_key($values, array_flip($keys));
} }
return (bool)self::$_readers[$config]->dump($key, $values); return (bool)$reader->dump($key, $values);
}
/**
* Get the configured reader. Internally used by `Configure::load()` and `Configure::dump()`
* Will create new PhpReader for default if not configured yet.
*
* @param string $config The name of the configured adapter
* @return mixed Reader instance or false
*/
protected static function _getReader($config) {
if (!isset(self::$_readers[$config])) {
if ($config !== 'default') {
return false;
}
App::uses('PhpReader', 'Configure');
self::config($config, new PhpReader());
}
return self::$_readers[$config];
} }
/** /**

View file

@ -513,6 +513,16 @@ TEXT;
$this->assertEquals($expected, $output); $this->assertEquals($expected, $output);
} }
/**
* Test that exportVar() doesn't loop through recursive structures.
*
* @return void
*/
public function testExportVarRecursion() {
$output = Debugger::exportVar($GLOBALS);
$this->assertContains("'GLOBALS' => [recursion]", $output);
}
/** /**
* test trace exclude * test trace exclude
* *

View file

@ -542,9 +542,15 @@ class Debugger {
if ($depth >= 0) { if ($depth >= 0) {
foreach ($var as $key => $val) { foreach ($var as $key => $val) {
// Sniff for globals as !== explodes in < 5.4
if ($key === 'GLOBALS' && is_array($val) && isset($val['GLOBALS'])) {
$val = '[recursion]';
} else if ($val !== $var) {
$val = self::_export($val, $depth, $indent);
}
$vars[] = $break . self::exportVar($key) . $vars[] = $break . self::exportVar($key) .
' => ' . ' => ' .
self::_export($val, $depth, $indent); $val;
} }
} else { } else {
$vars[] = $break . '[maximum depth reached]'; $vars[] = $break . '[maximum depth reached]';

View file

@ -90,12 +90,16 @@ if (!defined('TMP')) {
/** /**
* Path to the logs directory. * Path to the logs directory.
*/ */
if (!defined('LOGS')) {
define('LOGS', TMP . 'logs' . DS); define('LOGS', TMP . 'logs' . DS);
}
/** /**
* Path to the cache files directory. It can be shared between hosts in a multi-server setup. * Path to the cache files directory. It can be shared between hosts in a multi-server setup.
*/ */
if (!defined('CACHE')) {
define('CACHE', TMP . 'cache' . DS); define('CACHE', TMP . 'cache' . DS);
}
/** /**
* Path to the vendors directory. * Path to the vendors directory.