CakePHP 2.5.0

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (Darwin)
 
 iQEcBAABAgAGBQJTcYCoAAoJEDwHD15Vs66g4PQH+wZkDgvrGK5AoMBU63tLhM68
 txYUfV2g7YCjoWC/q0R5QbEYa7otBAAtREEdPisTU34pWPPGcar4/Q8M+bsztaJv
 UfOWOzmVLqNqDGMfvJKL5Y3kWtuKDpUVGupa4SBdt/jQ0RxwsG5SBolwu7QQ15gr
 BstQjA6RpTmdBjzbHVfX6WO3a//4utY3Nf0G4+aL5Q/y1FDNzyAmBq4OKahbBY0K
 MnaWiANHXN/3YfFFaWxDk+P23gsiWckaqq3Q2ipaGGGQoWq0rMeWFw3OrSc4w4xS
 L94poTkNDPqEzEjO7A4GvyvgXW4NhuuDbGkrSXciArfxihVSyB1mziDWSSYanAI=
 =y8NE
 -----END PGP SIGNATURE-----

CakePHP 2.5.0
This commit is contained in:
Jose Lorenzo Rodriguez 2014-05-13 09:14:43 +02:00
commit 3c57300816
199 changed files with 7235 additions and 2048 deletions

33
.gitattributes vendored Normal file
View file

@ -0,0 +1,33 @@
# Define the line ending behavior of the different file extensions
# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto
# Explicitly declare text files we want to always be normalized and converted
# to native line endings on checkout.
*.php text
*.default text
*.ctp text
*.sql text
*.md text
*.po text
*.js text
*.css text
*.ini text
*.properties text
*.txt text
*.xml text
*.yml text
.htaccess text
# Declare files that will always have CRLF line endings on checkout.
*.bat eol=crlf
# Declare files that will always have LF line endings on checkout.
*.pem eol=lf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.gif binary
*.ico binary
*.mo binary

View file

@ -12,6 +12,9 @@ env:
- DB=pgsql
- DB=sqlite
services:
- memcached
matrix:
include:
- php: 5.4
@ -32,6 +35,7 @@ before_script:
- sudo apt-get install lighttpd
- sh -c "if [ '$PHPCS' = '1' ]; then pear channel-discover pear.cakephp.org; fi"
- sh -c "if [ '$PHPCS' = '1' ]; then pear install --alldeps cakephp/CakePHP_CodeSniffer; fi"
- echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- phpenv rehash
- set +H
- echo "<?php

View file

@ -1,73 +1,73 @@
# How to contribute
CakePHP loves to welcome your contributions. There are several ways to help out:
* Create an [issue](https://github.com/cakephp/cakephp/issues) on GitHub, if you have found a bug
* Write test cases for open bug issues
* Write patches for open bug/feature issues, preferably with test cases included
* Contribute to the [documentation](https://github.com/cakephp/docs)
There are a few guidelines that we need contributors to follow so that we have a
chance of keeping on top of things.
## Getting Started
* Make sure you have a [GitHub account](https://github.com/signup/free).
* Submit an [issue](https://github.com/cakephp/cakephp/issues), assuming one does not already exist.
* Clearly describe the issue including steps to reproduce when it is a bug.
* Make sure you fill in the earliest version that you know has the issue.
* Fork the repository on GitHub.
## Making Changes
* Create a topic branch from where you want to base your work.
* This is usually the master branch.
* Only target release branches if you are certain your fix must be on that
branch.
* To quickly create a topic branch based on master; `git branch
master/my_contribution master` then checkout the new branch with `git
checkout master/my_contribution`. Better avoid working directly on the
`master` branch, to avoid conflicts if you pull in updates from origin.
* Make commits of logical units.
* Check for unnecessary whitespace with `git diff --check` before committing.
* Use descriptive commit messages and reference the #issue number.
* Core test cases should continue to pass. You can run tests locally or enable
[travis-ci](https://travis-ci.org/) for your fork, so all tests and codesniffs
will be executed.
* Your work should apply the CakePHP coding standards.
## Which branch to base the work
* Bugfix branches will be based on master.
* New features that are backwards compatible will be based on next minor release
branch.
* New features or other non-BC changes will go in the next major release branch.
## Submitting Changes
* Push your changes to a topic branch in your fork of the repository.
* Submit a pull request to the repository in the cakephp organization, with the
correct target branch.
## Test cases and codesniffer
CakePHP tests requires [PHPUnit](http://www.phpunit.de/manual/current/en/installation.html)
3.5 or higher. To run the test cases locally use the following command:
./lib/Cake/Console/cake test core AllTests --stderr
To run the sniffs for CakePHP coding standards:
phpcs -p --extensions=php --standard=CakePHP ./lib/Cake
Check the [cakephp-codesniffer](https://github.com/cakephp/cakephp-codesniffer)
repository to setup the CakePHP standard. The README contains installation info
for the sniff and phpcs.
# Additional Resources
* [CakePHP coding standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html)
* [Existing issues](https://github.com/cakephp/cakephp/issues)
* [Development Roadmaps](https://github.com/cakephp/cakephp/wiki#roadmaps)
* [General GitHub documentation](https://help.github.com/)
* [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
* #cakephp IRC channel on freenode.org
# How to contribute
CakePHP loves to welcome your contributions. There are several ways to help out:
* Create an [issue](https://github.com/cakephp/cakephp/issues) on GitHub, if you have found a bug
* Write test cases for open bug issues
* Write patches for open bug/feature issues, preferably with test cases included
* Contribute to the [documentation](https://github.com/cakephp/docs)
There are a few guidelines that we need contributors to follow so that we have a
chance of keeping on top of things.
## Getting Started
* Make sure you have a [GitHub account](https://github.com/signup/free).
* Submit an [issue](https://github.com/cakephp/cakephp/issues), assuming one does not already exist.
* Clearly describe the issue including steps to reproduce when it is a bug.
* Make sure you fill in the earliest version that you know has the issue.
* Fork the repository on GitHub.
## Making Changes
* Create a topic branch from where you want to base your work.
* This is usually the master branch.
* Only target release branches if you are certain your fix must be on that
branch.
* To quickly create a topic branch based on master; `git branch
master/my_contribution master` then checkout the new branch with `git
checkout master/my_contribution`. Better avoid working directly on the
`master` branch, to avoid conflicts if you pull in updates from origin.
* Make commits of logical units.
* Check for unnecessary whitespace with `git diff --check` before committing.
* Use descriptive commit messages and reference the #issue number.
* Core test cases should continue to pass. You can run tests locally or enable
[travis-ci](https://travis-ci.org/) for your fork, so all tests and codesniffs
will be executed.
* Your work should apply the CakePHP coding standards.
## Which branch to base the work
* Bugfix branches will be based on master.
* New features that are backwards compatible will be based on next minor release
branch.
* New features or other non-BC changes will go in the next major release branch.
## Submitting Changes
* Push your changes to a topic branch in your fork of the repository.
* Submit a pull request to the repository in the cakephp organization, with the
correct target branch.
## Test cases and codesniffer
CakePHP tests requires [PHPUnit](http://www.phpunit.de/manual/current/en/installation.html)
3.5 or higher. To run the test cases locally use the following command:
./lib/Cake/Console/cake test core AllTests --stderr
To run the sniffs for CakePHP coding standards:
phpcs -p --extensions=php --standard=CakePHP ./lib/Cake
Check the [cakephp-codesniffer](https://github.com/cakephp/cakephp-codesniffer)
repository to setup the CakePHP standard. The README contains installation info
for the sniff and phpcs.
# Additional Resources
* [CakePHP coding standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html)
* [Existing issues](https://github.com/cakephp/cakephp/issues)
* [Development Roadmaps](https://github.com/cakephp/cakephp/wiki#roadmaps)
* [General GitHub documentation](https://help.github.com/)
* [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
* #cakephp IRC channel on freenode.org

View file

@ -80,8 +80,9 @@ Cache::config('default', array('engine' => 'File'));
*
* Configure::write('Dispatcher.filters', array(
* 'MyCacheFilter', // will use MyCacheFilter class from the Routing/Filter package in your app.
* 'MyCacheFilter' => array('prefix' => 'my_cache_'), // will use MyCacheFilter class from the Routing/Filter package in your app with settings array.
* 'MyPlugin.MyFilter', // will use MyFilter class from the Routing/Filter package in MyPlugin plugin.
* array('callable' => $aFunction, 'on' => 'before', 'priority' => 9), // A valid PHP callback type to be called on beforeDispatch
* array('callable' => $aFunction, 'on' => 'before', 'priority' => 9), // A valid PHP callback type to be called on beforeDispatch
* array('callable' => $anotherMethod, 'on' => 'after'), // A valid PHP callback type to be called on afterDispatch
*
* ));

View file

@ -315,18 +315,20 @@
* 'password' => 'password', //plaintext password (xcache.admin.pass)
* ));
*
* Memcache (http://www.danga.com/memcached/)
* Memcached (http://www.danga.com/memcached/)
*
* Uses the memcached extension. See http://php.net/memcached
*
* Cache::config('default', array(
* 'engine' => 'Memcache', //[required]
* 'engine' => 'Memcached', //[required]
* 'duration' => 3600, //[optional]
* 'probability' => 100, //[optional]
* 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
* 'servers' => array(
* '127.0.0.1:11211' // localhost, default port 11211
* ), //[optional]
* 'persistent' => true, // [optional] set this to false for non-persistent connections
* 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory)
* 'persistent' => 'my_connection', // [optional] The name of the persistent connection.
* 'compress' => false, // [optional] compress data in Memcached (slower, but uses less memory)
* ));
*
* Wincache (http://php.net/wincache)

View file

@ -58,6 +58,9 @@
* For MySQL : http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
* For Postgres : http://www.postgresql.org/docs/9.2/static/sql-set.html
* For Sql Server : http://msdn.microsoft.com/en-us/library/ms190356.aspx
*
* flags =>
* A key/value array of driver specific connection options.
*/
class DATABASE_CONFIG {

View file

@ -16,7 +16,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2><?php echo $name; ?></h2>
<h2><?php echo $message; ?></h2>
<p class="error">
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
<?php printf(

View file

@ -16,7 +16,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
?>
<h2><?php echo $name; ?></h2>
<h2><?php echo $message; ?></h2>
<p class="error">
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
<?php echo __d('cake', 'An Internal Error Has Occurred.'); ?>

View file

@ -17,6 +17,7 @@
*/
$cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework');
$cakeVersion = __d('cake_dev', 'CakePHP %s', Configure::version())
?>
<!DOCTYPE html>
<html>
@ -51,9 +52,12 @@ $cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework
<?php echo $this->Html->link(
$this->Html->image('cake.power.gif', array('alt' => $cakeDescription, 'border' => '0')),
'http://www.cakephp.org/',
array('target' => '_blank', 'escape' => false)
array('target' => '_blank', 'escape' => false, 'id' => 'cake-powered')
);
?>
<p>
<?php echo $cakeVersion; ?>
</p>
</div>
</div>
<?php echo $this->element('sql_dump'); ?>

View file

@ -107,11 +107,13 @@ p {
#footer {
clear: both;
padding: 6px 10px;
text-align: right;
}
#header a, #footer a {
color: #fff;
}
#cake-powered {
float: right;
}
/** containers **/
div.form,

View file

@ -130,7 +130,7 @@ class Cache {
}
if (!empty($settings)) {
self::$_config[$name] = array_merge($current, $settings);
self::$_config[$name] = $settings + $current;
}
if (empty(self::$_config[$name]['engine'])) {
@ -253,7 +253,7 @@ class Cache {
if (is_string($settings) && $value !== null) {
$settings = array($settings => $value);
}
$settings = array_merge(self::$_config[$config], $settings);
$settings += self::$_config[$config];
if (isset($settings['duration']) && !is_numeric($settings['duration'])) {
$settings['duration'] = strtotime($settings['duration']) - time();
}
@ -538,4 +538,38 @@ class Cache {
throw new CacheException(__d('cake_dev', 'Invalid cache group %s', $group));
}
/**
* Provides the ability to easily do read-through caching.
*
* When called if the $key is not set in $config, the $callable function
* will be invoked. The results will then be stored into the cache config
* at key.
*
* Examples:
*
* Using a Closure to provide data, assume $this is a Model:
*
* {{{
* $model = $this;
* $results = Cache::remember('all_articles', function() use ($model) {
* return $model->find('all');
* });
* }}}
*
* @param string $key The cache key to read/store data at.
* @param callable $callable The callable that provides data in the case when
* the cache key is empty. Can be any callable type supported by your PHP.
* @param string $config The cache configuration to use for this operation.
* Defaults to default.
*/
public static function remember($key, $callable, $config = 'default') {
$existing = self::read($key, $config);
if ($existing !== false) {
return $existing;
}
$results = call_user_func($callable);
self::write($key, $results, $config);
return $results;
}
}

View file

@ -21,7 +21,8 @@
* control you have over expire times far in the future. See MemcacheEngine::write() for
* more information.
*
* @package Cake.Cache.Engine
* @package Cake.Cache.Engine
* @deprecated You should use the Memcached adapter instead.
*/
class MemcacheEngine extends CacheEngine {

View file

@ -0,0 +1,322 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.5.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Memcached storage engine for cache. Memcached has some limitations in the amount of
* control you have over expire times far in the future. See MemcachedEngine::write() for
* more information.
*
* Main advantage of this Memcached engine over the memcached engine is
* support of binary protocol, and igbibnary serialization
* (if memcached extension compiled with --enable-igbinary)
* Compressed keys can also be incremented/decremented
*
* @package Cake.Cache.Engine
*/
class MemcachedEngine extends CacheEngine {
/**
* memcached wrapper.
*
* @var Memcache
*/
protected $_Memcached = null;
/**
* Settings
*
* - servers = string or array of memcached servers, default => 127.0.0.1. If an
* array MemcacheEngine will use them as a pool.
* - compress = boolean, default => false
* - persistent = string The name of the persistent connection. All configurations using
* the same persistent value will share a single underlying connection.
* - serialize = string, default => php. The serializer engine used to serialize data.
* Available engines are php, igbinary and json. Beside php, the memcached extension
* must be compiled with the appropriate serializer support.
*
* @var array
*/
public $settings = array();
/**
* List of available serializer engines
*
* Memcached must be compiled with json and igbinary support to use these engines
*
* @var array
*/
protected $_serializers = array(
'igbinary' => Memcached::SERIALIZER_IGBINARY,
'json' => Memcached::SERIALIZER_JSON,
'php' => Memcached::SERIALIZER_PHP
);
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
* @throws CacheException when you try use authentication without Memcached compiled with SASL support
*/
public function init($settings = array()) {
if (!class_exists('Memcached')) {
return false;
}
if (!isset($settings['prefix'])) {
$settings['prefix'] = Inflector::slug(APP_DIR) . '_';
}
if (defined('Memcached::HAVE_MSGPACK') && Memcached::HAVE_MSGPACK) {
$this->_serializers['msgpack'] = Memcached::SERIALIZER_MSGPACK;
}
$settings += array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1'),
'compress' => false,
'persistent' => false,
'login' => null,
'password' => null,
'serialize' => 'php'
);
parent::init($settings);
if (!is_array($this->settings['servers'])) {
$this->settings['servers'] = array($this->settings['servers']);
}
if (isset($this->_Memcached)) {
return true;
}
$this->_Memcached = new Memcached($this->settings['persistent'] ? (string)$this->settings['persistent'] : null);
$this->_setOptions();
if (count($this->_Memcached->getServerList())) {
return true;
}
$servers = array();
foreach ($this->settings['servers'] as $server) {
$servers[] = $this->_parseServerString($server);
}
if (!$this->_Memcached->addServers($servers)) {
return false;
}
if ($this->settings['login'] !== null && $this->settings['password'] !== null) {
if (!method_exists($this->_Memcached, 'setSaslAuthData')) {
throw new CacheException(
__d('cake_dev', 'Memcached extension is not build with SASL support')
);
}
$this->_Memcached->setSaslAuthData($this->settings['login'], $this->settings['password']);
}
return true;
}
/**
* Settings the memcached instance
*
* @throws CacheException when the Memcached extension is not built with the desired serializer engine
*/
protected function _setOptions() {
$this->_Memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$serializer = strtolower($this->settings['serialize']);
if (!isset($this->_serializers[$serializer])) {
throw new CacheException(
__d('cake_dev', '%s is not a valid serializer engine for Memcached', $serializer)
);
}
if ($serializer !== 'php' && !constant('Memcached::HAVE_' . strtoupper($serializer))) {
throw new CacheException(
__d('cake_dev', 'Memcached extension is not compiled with %s support', $serializer)
);
}
$this->_Memcached->setOption(Memcached::OPT_SERIALIZER, $this->_serializers[$serializer]);
// Check for Amazon ElastiCache instance
if (defined('Memcached::OPT_CLIENT_MODE') && defined('Memcached::DYNAMIC_CLIENT_MODE')) {
$this->_Memcached->setOption(Memcached::OPT_CLIENT_MODE, Memcached::DYNAMIC_CLIENT_MODE);
}
$this->_Memcached->setOption(Memcached::OPT_COMPRESSION, (bool)$this->settings['compress']);
}
/**
* Parses the server address into the host/port. Handles both IPv6 and IPv4
* addresses and Unix sockets
*
* @param string $server The server address string.
* @return array Array containing host, port
*/
protected function _parseServerString($server) {
if ($server[0] === 'u') {
return array($server, 0);
}
if (substr($server, 0, 1) === '[') {
$position = strpos($server, ']:');
if ($position !== false) {
$position++;
}
} else {
$position = strpos($server, ':');
}
$port = 11211;
$host = $server;
if ($position !== false) {
$host = substr($server, 0, $position);
$port = substr($server, $position + 1);
}
return array($host, (int)$port);
}
/**
* Write data for key into cache. When using memcached as your cache engine
* remember that the Memcached pecl extension does not support cache expiry times greater
* than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
* @see http://php.net/manual/en/memcache.set.php
*/
public function write($key, $value, $duration) {
if ($duration > 30 * DAY) {
$duration = 0;
}
return $this->_Memcached->set($key, $value, $duration);
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public function read($key) {
return $this->_Memcached->get($key);
}
/**
* Increments the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to increment
* @return New incremented value, false otherwise
* @throws CacheException when you try to increment with compress = true
*/
public function increment($key, $offset = 1) {
return $this->_Memcached->increment($key, $offset);
}
/**
* Decrements the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New decremented value, false otherwise
* @throws CacheException when you try to decrement with compress = true
*/
public function decrement($key, $offset = 1) {
return $this->_Memcached->decrement($key, $offset);
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
return $this->_Memcached->delete($key);
}
/**
* Delete all keys from the cache
*
* @param boolean $check
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public function clear($check) {
if ($check) {
return true;
}
$keys = $this->_Memcached->getAllKeys();
foreach ($keys as $key) {
if (strpos($key, $this->settings['prefix']) === 0) {
$this->_Memcached->delete($key);
}
}
return true;
}
/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
* the group accordingly.
*
* @return array
*/
public function groups() {
if (empty($this->_compiledGroupNames)) {
foreach ($this->settings['groups'] as $group) {
$this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
}
}
$groups = $this->_Memcached->getMulti($this->_compiledGroupNames);
if (count($groups) !== count($this->settings['groups'])) {
foreach ($this->_compiledGroupNames as $group) {
if (!isset($groups[$group])) {
$this->_Memcached->set($group, 1, 0);
$groups[$group] = 1;
}
}
ksort($groups);
}
$result = array();
$groups = array_values($groups);
foreach ($this->settings['groups'] as $i => $group) {
$result[] = $group . $groups[$i];
}
return $result;
}
/**
* Increments the group value to simulate deletion of all keys under a group
* old values will remain in storage until they expire.
*
* @return boolean success
*/
public function clearGroup($group) {
return (bool)$this->_Memcached->increment($this->settings['prefix'] . $group);
}
}

View file

@ -34,9 +34,11 @@ class RedisEngine extends CacheEngine {
* Settings
*
* - server = string URL or ip to the Redis server host
* - database = integer database number to use for connection
* - port = integer port number to the Redis server (default: 6379)
* - timeout = float timeout in seconds (default: 0)
* - persistent = boolean Connects to the Redis server with a persistent connection (default: true)
* - unix_socket = path to the unix socket file (default: false)
*
* @var array
*/
@ -59,10 +61,12 @@ class RedisEngine extends CacheEngine {
'engine' => 'Redis',
'prefix' => null,
'server' => '127.0.0.1',
'database' => 0,
'port' => 6379,
'password' => false,
'timeout' => 0,
'persistent' => true
'persistent' => true,
'unix_socket' => false
), $settings)
);
@ -78,10 +82,13 @@ class RedisEngine extends CacheEngine {
$return = false;
try {
$this->_Redis = new Redis();
if (empty($this->settings['persistent'])) {
if (!empty($this->settings['unix_socket'])) {
$return = $this->_Redis->connect($this->settings['unix_socket']);
} elseif (empty($this->settings['persistent'])) {
$return = $this->_Redis->connect($this->settings['server'], $this->settings['port'], $this->settings['timeout']);
} else {
$return = $this->_Redis->pconnect($this->settings['server'], $this->settings['port'], $this->settings['timeout']);
$persistentId = $this->settings['port'] . $this->settings['timeout'] . $this->settings['database'];
$return = $this->_Redis->pconnect($this->settings['server'], $this->settings['port'], $this->settings['timeout'], $persistentId);
}
} catch (RedisException $e) {
return false;
@ -89,6 +96,9 @@ class RedisEngine extends CacheEngine {
if ($return && $this->settings['password']) {
$return = $this->_Redis->auth($this->settings['password']);
}
if ($return) {
$return = $this->_Redis->select($this->settings['database']);
}
return $return;
}

View file

@ -363,9 +363,9 @@ class AclShell extends AppShell {
}
/**
* Get the option parser.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
@ -378,142 +378,141 @@ class AclShell extends AppShell {
$parser->description(
__d('cake_console', 'A console tool for managing the DbAcl')
)->addSubcommand('create', array(
'help' => __d('cake_console', 'Create a new ACL node'),
'parser' => array(
'description' => __d('cake_console', 'Creates a new ACL object <node> under the parent'),
'epilog' => __d('cake_console', 'You can use `root` as the parent when creating nodes to create top level nodes.'),
'arguments' => array(
'type' => $type,
'parent' => array(
'help' => __d('cake_console', 'The node selector for the parent.'),
'required' => true
),
'alias' => array(
'help' => __d('cake_console', 'The alias to use for the newly created node.'),
'required' => true
)
)
)
))->addSubcommand('delete', array(
'help' => __d('cake_console', 'Deletes the ACL object with the given <node> reference'),
'parser' => array(
'description' => __d('cake_console', 'Delete an ACL node.'),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __d('cake_console', 'The node identifier to delete.'),
'required' => true,
)
)
)
))->addSubcommand('setparent', array(
'help' => __d('cake_console', 'Moves the ACL node under a new parent.'),
'parser' => array(
'description' => __d('cake_console', 'Moves the ACL object specified by <node> beneath <parent>'),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __d('cake_console', 'The node to move'),
'required' => true,
),
'parent' => array(
'help' => __d('cake_console', 'The new parent for <node>.'),
'required' => true
)
)
)
))->addSubcommand('getpath', array(
'help' => __d('cake_console', 'Print out the path to an ACL node.'),
'parser' => array(
'description' => array(
__d('cake_console', "Returns the path to the ACL object specified by <node>."),
__d('cake_console', "This command is useful in determining the inheritance of permissions for a certain object in the tree.")
)->addSubcommand('create', array(
'help' => __d('cake_console', 'Create a new ACL node'),
'parser' => array(
'description' => __d('cake_console', 'Creates a new ACL object <node> under the parent'),
'epilog' => __d('cake_console', 'You can use `root` as the parent when creating nodes to create top level nodes.'),
'arguments' => array(
'type' => $type,
'parent' => array(
'help' => __d('cake_console', 'The node selector for the parent.'),
'required' => true
),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __d('cake_console', 'The node to get the path of'),
'required' => true,
)
'alias' => array(
'help' => __d('cake_console', 'The alias to use for the newly created node.'),
'required' => true
)
)
))->addSubcommand('check', array(
'help' => __d('cake_console', 'Check the permissions between an ACO and ARO.'),
'parser' => array(
'description' => array(
__d('cake_console', 'Use this command to check ACL permissions.')
)
))->addSubcommand('delete', array(
'help' => __d('cake_console', 'Deletes the ACL object with the given <node> reference'),
'parser' => array(
'description' => __d('cake_console', 'Delete an ACL node.'),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __d('cake_console', 'The node identifier to delete.'),
'required' => true,
)
)
)
))->addSubcommand('setparent', array(
'help' => __d('cake_console', 'Moves the ACL node under a new parent.'),
'parser' => array(
'description' => __d('cake_console', 'Moves the ACL object specified by <node> beneath <parent>'),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __d('cake_console', 'The node to move'),
'required' => true,
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to check.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to check.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to check'), 'default' => 'all')
'parent' => array(
'help' => __d('cake_console', 'The new parent for <node>.'),
'required' => true
)
)
))->addSubcommand('grant', array(
'help' => __d('cake_console', 'Grant an ARO permissions to an ACO.'),
'parser' => array(
'description' => array(
__d('cake_console', 'Use this command to grant ACL permissions. Once executed, the ARO specified (and its children, if any) will have ALLOW access to the specified ACO action (and the ACO\'s children, if any).')
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to grant permission to.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to grant access to.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to grant'), 'default' => 'all')
)
))->addSubcommand('getpath', array(
'help' => __d('cake_console', 'Print out the path to an ACL node.'),
'parser' => array(
'description' => array(
__d('cake_console', "Returns the path to the ACL object specified by <node>."),
__d('cake_console', "This command is useful in determining the inheritance of permissions for a certain object in the tree.")
),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __d('cake_console', 'The node to get the path of'),
'required' => true,
)
)
))->addSubcommand('deny', array(
'help' => __d('cake_console', 'Deny an ARO permissions to an ACO.'),
'parser' => array(
'description' => array(
__d('cake_console', 'Use this command to deny ACL permissions. Once executed, the ARO specified (and its children, if any) will have DENY access to the specified ACO action (and the ACO\'s children, if any).')
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to deny.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to deny.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to deny'), 'default' => 'all')
)
)
))->addSubcommand('check', array(
'help' => __d('cake_console', 'Check the permissions between an ACO and ARO.'),
'parser' => array(
'description' => array(
__d('cake_console', 'Use this command to check ACL permissions.')
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to check.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to check.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to check'), 'default' => 'all')
)
))->addSubcommand('inherit', array(
'help' => __d('cake_console', 'Inherit an ARO\'s parent permissions.'),
'parser' => array(
'description' => array(
__d('cake_console', "Use this command to force a child ARO object to inherit its permissions settings from its parent.")
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to have permissions inherit.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to inherit permissions on.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to inherit'), 'default' => 'all')
)
)
))->addSubcommand('grant', array(
'help' => __d('cake_console', 'Grant an ARO permissions to an ACO.'),
'parser' => array(
'description' => array(
__d('cake_console', 'Use this command to grant ACL permissions. Once executed, the ARO specified (and its children, if any) will have ALLOW access to the specified ACO action (and the ACO\'s children, if any).')
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to grant permission to.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to grant access to.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to grant'), 'default' => 'all')
)
))->addSubcommand('view', array(
'help' => __d('cake_console', 'View a tree or a single node\'s subtree.'),
'parser' => array(
'description' => array(
__d('cake_console', "The view command will return the ARO or ACO tree."),
__d('cake_console', "The optional node parameter allows you to return"),
__d('cake_console', "only a portion of the requested tree.")
),
'arguments' => array(
'type' => $type,
'node' => array('help' => __d('cake_console', 'The optional node to view the subtree of.'))
)
)
))->addSubcommand('deny', array(
'help' => __d('cake_console', 'Deny an ARO permissions to an ACO.'),
'parser' => array(
'description' => array(
__d('cake_console', 'Use this command to deny ACL permissions. Once executed, the ARO specified (and its children, if any) will have DENY access to the specified ACO action (and the ACO\'s children, if any).')
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to deny.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to deny.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to deny'), 'default' => 'all')
)
))->addSubcommand('initdb', array(
'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema create DbAcl')
))->epilog(
array(
'Node and parent arguments can be in one of the following formats:',
'',
' - <model>.<id> - The node will be bound to a specific record of the given model.',
'',
' - <alias> - The node will be given a string alias (or path, in the case of <parent>)',
" i.e. 'John'. When used with <parent>, this takes the form of an alias path,",
" i.e. <group>/<subgroup>/<parent>.",
'',
"To add a node at the root level, enter 'root' or '/' as the <parent> parameter."
)
))->addSubcommand('inherit', array(
'help' => __d('cake_console', 'Inherit an ARO\'s parent permissions.'),
'parser' => array(
'description' => array(
__d('cake_console', "Use this command to force a child ARO object to inherit its permissions settings from its parent.")
),
'arguments' => array(
'aro' => array('help' => __d('cake_console', 'ARO to have permissions inherit.'), 'required' => true),
'aco' => array('help' => __d('cake_console', 'ACO to inherit permissions on.'), 'required' => true),
'action' => array('help' => __d('cake_console', 'Action to inherit'), 'default' => 'all')
)
);
)
))->addSubcommand('view', array(
'help' => __d('cake_console', 'View a tree or a single node\'s subtree.'),
'parser' => array(
'description' => array(
__d('cake_console', "The view command will return the ARO or ACO tree."),
__d('cake_console', "The optional node parameter allows you to return"),
__d('cake_console', "only a portion of the requested tree.")
),
'arguments' => array(
'type' => $type,
'node' => array('help' => __d('cake_console', 'The optional node to view the subtree of.'))
)
)
))->addSubcommand('initdb', array(
'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema create DbAcl')
))->epilog(array(
'Node and parent arguments can be in one of the following formats:',
'',
' - <model>.<id> - The node will be bound to a specific record of the given model.',
'',
' - <alias> - The node will be given a string alias (or path, in the case of <parent>)',
" i.e. 'John'. When used with <parent>, this takes the form of an alias path,",
" i.e. <group>/<subgroup>/<parent>.",
'',
"To add a node at the root level, enter 'root' or '/' as the <parent> parameter."
));
return $parser;
}

View file

@ -137,20 +137,24 @@ class ApiShell extends AppShell {
}
/**
* Get and configure the optionparser.
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->addArgument('type', array(
$parser->description(
__d('cake_console', 'Lookup doc block comments for classes in CakePHP.')
)->addArgument('type', array(
'help' => __d('cake_console', 'Either a full path or type of class (model, behavior, controller, component, view, helper)')
))->addArgument('className', array(
'help' => __d('cake_console', 'A CakePHP core class name (e.g: Component, HtmlHelper).')
))->addOption('method', array(
'short' => 'm',
'help' => __d('cake_console', 'The specific method you want help on.')
))->description(__d('cake_console', 'Lookup doc block comments for classes in CakePHP.'));
));
return $parser;
}

View file

@ -203,18 +203,19 @@ class BakeShell extends AppShell {
}
/**
* get the option parser.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__d('cake_console',
'The Bake script generates controllers, views and models for your application.' .
$parser->description(
__d('cake_console', 'The Bake script generates controllers, views and models for your application.' .
' If run with no command line arguments, Bake guides the user through the class creation process.' .
' You can customize the generation process by telling Bake where different parts of your application are using command line arguments.'
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake a complete MVC. optional <name> of a Model'),
' You can customize the generation process by telling Bake where different parts of your application are using command line arguments.')
)->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake a complete MVC. optional <name> of a Model')
))->addSubcommand('project', array(
'help' => __d('cake_console', 'Bake a new app folder in the path supplied or in current directory if no path is specified'),
'parser' => $this->Project->getOptionParser()
@ -247,6 +248,8 @@ class BakeShell extends AppShell {
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
));
return $parser;
}
}

View file

@ -24,6 +24,13 @@ App::uses('Inflector', 'Utility');
*/
class CommandListShell extends AppShell {
/**
* Contains tasks to load and instantiate
*
* @var array
*/
public $tasks = array('Command');
/**
* startup
*
@ -55,7 +62,7 @@ class CommandListShell extends AppShell {
$this->out(__d('cake_console', "<info>Available Shells:</info>"), 2);
}
$shellList = $this->_getShellList();
$shellList = $this->Command->getShellList();
if (empty($shellList)) {
return;
}
@ -67,48 +74,6 @@ class CommandListShell extends AppShell {
}
}
/**
* Gets the shell command listing.
*
* @return array
*/
protected function _getShellList() {
$skipFiles = array('AppShell');
$plugins = CakePlugin::loaded();
$shellList = array_fill_keys($plugins, null) + array('CORE' => null, 'app' => null);
$corePath = App::core('Console/Command');
$shells = App::objects('file', $corePath[0]);
$shells = array_diff($shells, $skipFiles);
$this->_appendShells('CORE', $shells, $shellList);
$appShells = App::objects('Console/Command', null, false);
$appShells = array_diff($appShells, $shells, $skipFiles);
$this->_appendShells('app', $appShells, $shellList);
foreach ($plugins as $plugin) {
$pluginShells = App::objects($plugin . '.Console/Command');
$this->_appendShells($plugin, $pluginShells, $shellList);
}
return array_filter($shellList);
}
/**
* Scan the provided paths for shells, and append them into $shellList
*
* @param string $type
* @param array $shells
* @param array $shellList
* @return void
*/
protected function _appendShells($type, $shells, &$shellList) {
foreach ($shells as $shell) {
$shellList[$type][] = Inflector::underscore(str_replace('Shell', '', $shell));
}
}
/**
* Output text.
*
@ -155,21 +120,24 @@ class CommandListShell extends AppShell {
}
/**
* get the option parser
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__d('cake_console', 'Get the list of available shells for this CakePHP application.'))
->addOption('sort', array(
'help' => __d('cake_console', 'Does nothing (deprecated)'),
'boolean' => true
))
->addOption('xml', array(
'help' => __d('cake_console', 'Get the listing as XML.'),
'boolean' => true
));
$parser->description(
__d('cake_console', 'Get the list of available shells for this CakePHP application.')
)->addOption('sort', array(
'help' => __d('cake_console', 'Does nothing (deprecated)'),
'boolean' => true
))->addOption('xml', array(
'help' => __d('cake_console', 'Get the listing as XML.'),
'boolean' => true
));
return $parser;
}
}

View file

@ -0,0 +1,155 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP Project
* @package Cake.Console.Command
* @since CakePHP v 2.5
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AppShell', 'Console/Command');
/**
* Provide command completion shells such as bash.
*
* @package Cake.Console.Command
*/
class CompletionShell extends AppShell {
/**
* Contains tasks to load and instantiate
*
* @var array
*/
public $tasks = array('Command');
/**
* Echo no header by overriding the startup method
*
* @return void
*/
public function startup() {
}
/**
* Not called by the autocomplete shell - this is for curious users
*
* @return void
*/
public function main() {
return $this->out($this->getOptionParser()->help());
}
/**
* list commands
*
* @return void
*/
public function commands() {
$options = $this->Command->commands();
return $this->_output($options);
}
/**
* list options for the named command
*
* @return void
*/
public function options() {
$commandName = '';
if (!empty($this->args[0])) {
$commandName = $this->args[0];
}
$options = $this->Command->options($commandName);
return $this->_output($options);
}
/**
* list subcommands for the named command
*
* @return void
*/
public function subCommands() {
if (!$this->args) {
return $this->_output();
}
$options = $this->Command->subCommands($this->args[0]);
return $this->_output($options);
}
/**
* Guess autocomplete from the whole argument string
*
* @return void
*/
public function fuzzy() {
return $this->_output();
}
/**
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->description(
__d('cake_console', 'Used by shells like bash to autocomplete command name, options and arguments')
)->addSubcommand('commands', array(
'help' => __d('cake_console', 'Output a list of available commands'),
'parser' => array(
'description' => __d('cake_console', 'List all availables'),
'arguments' => array(
)
)
))->addSubcommand('subcommands', array(
'help' => __d('cake_console', 'Output a list of available subcommands'),
'parser' => array(
'description' => __d('cake_console', 'List subcommands for a command'),
'arguments' => array(
'command' => array(
'help' => __d('cake_console', 'The command name'),
'required' => true,
)
)
)
))->addSubcommand('options', array(
'help' => __d('cake_console', 'Output a list of available options'),
'parser' => array(
'description' => __d('cake_console', 'List options'),
'arguments' => array(
'command' => array(
'help' => __d('cake_console', 'The command name'),
'required' => false,
)
)
)
))->epilog(
__d('cake_console', 'This command is not intended to be called manually')
);
return $parser;
}
/**
* Emit results as a string, space delimited
*
* @param array $options
* @return void
*/
protected function _output($options = array()) {
if ($options) {
return $this->out(implode($options, ' '));
}
}
}

View file

@ -105,19 +105,19 @@ class ConsoleShell extends AppShell {
}
/**
* getOptionParser
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$description = array(
$parser = parent::getOptionParser();
$parser->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(
))->epilog(array(
'<info>Model testing</info>',
'',
'To test model results, use the name of your model without a leading $',
@ -176,10 +176,9 @@ class ConsoleShell extends AppShell {
'To show all connected routes, do the following:',
'',
"\tRoutes show",
);
return parent::getOptionParser()
->description($description)
->epilog($epilog);
));
return $parser;
}
/**
* Prints the help message

View file

@ -100,20 +100,23 @@ class I18nShell extends AppShell {
}
/**
* Get and configure the Option parser
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
$parser->description(
__d('cake_console', 'I18n Shell initializes i18n database table for your application and generates .pot files(s) with translations.')
)->addSubcommand('initdb', array(
'help' => __d('cake_console', 'Initialize the i18n table.')
))->addSubcommand('extract', array(
'help' => __d('cake_console', 'Extract the po translations from your application'),
'parser' => $this->Extract->getOptionParser()
));
)->addSubcommand('initdb', array(
'help' => __d('cake_console', 'Initialize the i18n table.')
))->addSubcommand('extract', array(
'help' => __d('cake_console', 'Extract the po translations from your application'),
'parser' => $this->Extract->getOptionParser()
));
return $parser;
}
}

View file

@ -337,7 +337,10 @@ class SchemaShell extends AppShell {
$this->out("\n" . __d('cake_console', 'The following table(s) will be dropped.'));
$this->out(array_keys($drop));
if ($this->in(__d('cake_console', 'Are you sure you want to drop the table(s)?'), array('y', 'n'), 'n') === 'y') {
if (
!empty($this->params['yes']) ||
$this->in(__d('cake_console', 'Are you sure you want to drop the table(s)?'), array('y', 'n'), 'n') === 'y'
) {
$this->out(__d('cake_console', 'Dropping table(s).'));
$this->_run($drop, 'drop', $Schema);
}
@ -345,7 +348,10 @@ class SchemaShell extends AppShell {
$this->out("\n" . __d('cake_console', 'The following table(s) will be created.'));
$this->out(array_keys($create));
if ($this->in(__d('cake_console', 'Are you sure you want to create the table(s)?'), array('y', 'n'), 'y') === 'y') {
if (
!empty($this->params['yes']) ||
$this->in(__d('cake_console', 'Are you sure you want to create the table(s)?'), array('y', 'n'), 'y') === 'y'
) {
$this->out(__d('cake_console', 'Creating table(s).'));
$this->_run($create, 'create', $Schema);
}
@ -396,7 +402,10 @@ class SchemaShell extends AppShell {
$this->out("\n" . __d('cake_console', 'The following statements will run.'));
$this->out(array_map('trim', $contents));
if ($this->in(__d('cake_console', 'Are you sure you want to alter the tables?'), array('y', 'n'), 'n') === 'y') {
if (
!empty($this->params['yes']) ||
$this->in(__d('cake_console', 'Are you sure you want to alter the tables?'), array('y', 'n'), 'n') === 'y'
) {
$this->out();
$this->out(__d('cake_console', 'Updating Database...'));
$this->_run($contents, 'update', $Schema);
@ -452,11 +461,13 @@ class SchemaShell extends AppShell {
}
/**
* get the option parser
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$plugin = array(
'short' => 'p',
'help' => __d('cake_console', 'The plugin to use.'),
@ -475,7 +486,9 @@ class SchemaShell extends AppShell {
'default' => 'schema.php'
);
$name = array(
'help' => __d('cake_console', 'Classname to use. If its Plugin.class, both name and plugin options will be set.')
'help' => __d('cake_console',
'Classname to use. If its Plugin.class, both name and plugin options will be set.'
)
);
$snapshot = array(
'short' => 's',
@ -486,7 +499,9 @@ class SchemaShell extends AppShell {
'help' => __d('cake_console', 'Specify models as comma separated list.'),
);
$dry = array(
'help' => __d('cake_console', 'Perform a dry run on create and update commands. Queries will be output instead of run.'),
'help' => __d('cake_console',
'Perform a dry run on create and update commands. Queries will be output instead of run.'
),
'boolean' => true
);
$force = array(
@ -500,8 +515,12 @@ class SchemaShell extends AppShell {
$exclude = array(
'help' => __d('cake_console', 'Tables to exclude as comma separated list.')
);
$yes = array(
'short' => 'y',
'help' => __d('cake_console', 'Do not prompt for confirmation. Be careful!'),
'boolean' => true
);
$parser = parent::getOptionParser();
$parser->description(
__d('cake_console', 'The Schema Shell generates a schema object from the database and updates the database from the schema.')
)->addSubcommand('view', array(
@ -527,7 +546,7 @@ class SchemaShell extends AppShell {
))->addSubcommand('create', array(
'help' => __d('cake_console', 'Drop and create tables based on the schema file.'),
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot'),
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot', 'yes'),
'args' => array(
'name' => array(
'help' => __d('cake_console', 'Name of schema to use.')
@ -540,7 +559,7 @@ class SchemaShell extends AppShell {
))->addSubcommand('update', array(
'help' => __d('cake_console', 'Alter the tables based on the schema file.'),
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot', 'force'),
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot', 'force', 'yes'),
'args' => array(
'name' => array(
'help' => __d('cake_console', 'Name of schema to use.')
@ -551,6 +570,7 @@ class SchemaShell extends AppShell {
)
)
));
return $parser;
}

View file

@ -141,29 +141,25 @@ class ServerShell extends AppShell {
}
/**
* Get and configure the optionparser.
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->addOption('host', array(
'short' => 'H',
'help' => __d('cake_console', 'ServerHost')
));
$parser->addOption('port', array(
'short' => 'p',
'help' => __d('cake_console', 'ListenPort')
));
$parser->addOption('document_root', array(
'short' => 'd',
'help' => __d('cake_console', 'DocumentRoot')
));
$parser->description(array(
__d('cake_console', 'PHP Built-in Server for CakePHP'),
__d('cake_console', '<warning>[WARN] Don\'t use this at the production environment</warning>'),
__d('cake_console', '<warning>[WARN] Don\'t use this at the production environment</warning>')
))->addOption('host', array(
'short' => 'H',
'help' => __d('cake_console', 'ServerHost')
))->addOption('port', array(
'short' => 'p',
'help' => __d('cake_console', 'ListenPort')
))->addOption('document_root', array(
'short' => 'd',
'help' => __d('cake_console', 'DocumentRoot')
));
return $parser;

View file

@ -0,0 +1,183 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.5
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('AppShell', 'Console/Command');
/**
* Base class for Shell Command reflection.
*
* @package Cake.Console.Command.Task
*/
class CommandTask extends AppShell {
/**
* Gets the shell command listing.
*
* @return array
*/
public function getShellList() {
$skipFiles = array('AppShell');
$plugins = CakePlugin::loaded();
$shellList = array_fill_keys($plugins, null) + array('CORE' => null, 'app' => null);
$corePath = App::core('Console/Command');
$shells = App::objects('file', $corePath[0]);
$shells = array_diff($shells, $skipFiles);
$this->_appendShells('CORE', $shells, $shellList);
$appShells = App::objects('Console/Command', null, false);
$appShells = array_diff($appShells, $shells, $skipFiles);
$this->_appendShells('app', $appShells, $shellList);
foreach ($plugins as $plugin) {
$pluginShells = App::objects($plugin . '.Console/Command');
$this->_appendShells($plugin, $pluginShells, $shellList);
}
return array_filter($shellList);
}
/**
* Scan the provided paths for shells, and append them into $shellList
*
* @param string $type
* @param array $shells
* @param array $shellList
* @return void
*/
protected function _appendShells($type, $shells, &$shellList) {
foreach ($shells as $shell) {
$shellList[$type][] = Inflector::underscore(str_replace('Shell', '', $shell));
}
}
/**
* Return a list of all commands
*
* @return array
*/
public function commands() {
$shellList = $this->getShellList();
$options = array();
foreach ($shellList as $type => $commands) {
$prefix = '';
if (!in_array(strtolower($type), array('app', 'core'))) {
$prefix = $type . '.';
}
foreach ($commands as $shell) {
$options[] = $prefix . $shell;
}
}
return $options;
}
/**
* Return a list of subcommands for a given command
*
* @param string $commandName
* @return array
*/
public function subCommands($commandName) {
$Shell = $this->getShell($commandName);
if (!$Shell) {
return array();
}
$taskMap = TaskCollection::normalizeObjectArray((array)$Shell->tasks);
$return = array_keys($taskMap);
$return = array_map('Inflector::underscore', $return);
$ShellReflection = new ReflectionClass('AppShell');
$shellMethods = $ShellReflection->getMethods(ReflectionMethod::IS_PUBLIC);
$shellMethodNames = array('main', 'help');
foreach ($shellMethods as $method) {
$shellMethodNames[] = $method->getName();
}
$Reflection = new ReflectionClass($Shell);
$methods = $Reflection->getMethods(ReflectionMethod::IS_PUBLIC);
$methodNames = array();
foreach ($methods as $method) {
$methodNames[] = $method->getName();
}
$return += array_diff($methodNames, $shellMethodNames);
sort($return);
return $return;
}
/**
* Get Shell instance for the given command
*
* @param mixed $commandName
* @return mixed
*/
public function getShell($commandName) {
list($pluginDot, $name) = pluginSplit($commandName, true);
if (in_array(strtolower($pluginDot), array('app.', 'core.'))) {
$commandName = $name;
$pluginDot = '';
}
if (!in_array($commandName, $this->commands())) {
return false;
}
$name = Inflector::camelize($name);
$pluginDot = Inflector::camelize($pluginDot);
$class = $name . 'Shell';
App::uses($class, $pluginDot . 'Console/Command');
$Shell = new $class();
$Shell->plugin = trim($pluginDot, '.');
$Shell->initialize();
return $Shell;
}
/**
* Get Shell instance for the given command
*
* @param mixed $commandName
* @return array
*/
public function options($commandName) {
$Shell = $this->getShell($commandName);
if (!$Shell) {
$parser = new ConsoleOptionParser();
} else {
$parser = $Shell->getOptionParser();
}
$options = array();
$array = $parser->options();
foreach ($array as $name => $obj) {
$options[] = "--$name";
$short = $obj->short();
if ($short) {
$options[] = "-$short";
}
}
return $options;
}
}

View file

@ -466,37 +466,42 @@ class ControllerTask extends BakeTask {
}
/**
* get the option parser.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__d('cake_console', 'Bake a controller for a model. Using options you can bake public, admin or both.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.')
))->addOption('public', array(
'help' => __d('cake_console', 'Bake a controller with basic crud actions (index, view, add, edit, delete).'),
'boolean' => true
))->addOption('admin', array(
'help' => __d('cake_console', 'Bake a controller with crud actions for one of the Routing.prefixes.'),
'boolean' => true
))->addOption('plugin', array(
'short' => 'p',
'help' => __d('cake_console', 'Plugin to bake the controller into.')
))->addOption('connection', array(
'short' => 'c',
'help' => __d('cake_console', 'The connection the controller\'s model is on.')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('force', array(
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake all controllers with CRUD methods.')
))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
$parser->description(
__d('cake_console', 'Bake a controller for a model. Using options you can bake public, admin or both.'
))->addArgument('name', array(
'help' => __d('cake_console', 'Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.')
))->addOption('public', array(
'help' => __d('cake_console', 'Bake a controller with basic crud actions (index, view, add, edit, delete).'),
'boolean' => true
))->addOption('admin', array(
'help' => __d('cake_console', 'Bake a controller with crud actions for one of the Routing.prefixes.'),
'boolean' => true
))->addOption('plugin', array(
'short' => 'p',
'help' => __d('cake_console', 'Plugin to bake the controller into.')
))->addOption('connection', array(
'short' => 'c',
'help' => __d('cake_console', 'The connection the controller\'s model is on.')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('force', array(
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake all controllers with CRUD methods.')
))->epilog(
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
);
return $parser;
}
}

View file

@ -203,7 +203,7 @@ class DbConfigTask extends AppShell {
* @return boolean True if user says it looks good, false otherwise
*/
protected function _verify($config) {
$config = array_merge($this->_defaultConfig, $config);
$config += $this->_defaultConfig;
extract($config);
$this->out();
$this->hr();
@ -264,7 +264,7 @@ class DbConfigTask extends AppShell {
$temp = get_class_vars(get_class($db));
foreach ($temp as $configName => $info) {
$info = array_merge($this->_defaultConfig, $info);
$info += $this->_defaultConfig;
if (!isset($info['schema'])) {
$info['schema'] = null;
@ -307,7 +307,7 @@ class DbConfigTask extends AppShell {
$out .= "class DATABASE_CONFIG {\n\n";
foreach ($configs as $config) {
$config = array_merge($this->_defaultConfig, $config);
$config += $this->_defaultConfig;
extract($config);
if (strpos($datasource, 'Database/') === false) {
@ -368,15 +368,18 @@ class DbConfigTask extends AppShell {
}
/**
* get the option parser
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__d('cake_console', 'Bake new database configuration settings.')
);
$parser->description(
__d('cake_console', 'Bake new database configuration settings.')
);
return $parser;
}
}

View file

@ -296,52 +296,55 @@ class ExtractTask extends AppShell {
}
/**
* Get & configure the option parser
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__d('cake_console', 'CakePHP Language String Extraction:'))
->addOption('app', array('help' => __d('cake_console', 'Directory where your application is located.')))
->addOption('paths', array('help' => __d('cake_console', 'Comma separated list of paths.')))
->addOption('merge', array(
'help' => __d('cake_console', 'Merge all domain and category strings into the default.po file.'),
'choices' => array('yes', 'no')
))
->addOption('output', array('help' => __d('cake_console', 'Full path to output directory.')))
->addOption('files', array('help' => __d('cake_console', 'Comma separated list of files.')))
->addOption('exclude-plugins', array(
'boolean' => true,
'default' => true,
'help' => __d('cake_console', 'Ignores all files in plugins if this command is run inside from the same app directory.')
))
->addOption('plugin', array(
'help' => __d('cake_console', 'Extracts tokens only from the plugin specified and puts the result in the plugin\'s Locale directory.')
))
->addOption('ignore-model-validation', array(
'boolean' => true,
'default' => false,
'help' => __d('cake_console', 'Ignores validation messages in the $validate property.' .
' If this flag is not set and the command is run from the same app directory,' .
' all messages in model validation rules will be extracted as tokens.')
))
->addOption('validation-domain', array(
'help' => __d('cake_console', 'If set to a value, the localization domain to be used for model validation messages.')
))
->addOption('exclude', array(
'help' => __d('cake_console', 'Comma separated list of directories to exclude.' .
' Any path containing a path segment with the provided values will be skipped. E.g. test,vendors')
))
->addOption('overwrite', array(
'boolean' => true,
'default' => false,
'help' => __d('cake_console', 'Always overwrite existing .pot files.')
))
->addOption('extract-core', array(
'help' => __d('cake_console', 'Extract messages from the CakePHP core libs.'),
'choices' => array('yes', 'no')
));
$parser->description(
__d('cake_console', 'CakePHP Language String Extraction:')
)->addOption('app', array(
'help' => __d('cake_console', 'Directory where your application is located.')
))->addOption('paths', array(
'help' => __d('cake_console', 'Comma separated list of paths.')
))->addOption('merge', array(
'help' => __d('cake_console', 'Merge all domain and category strings into the default.po file.'),
'choices' => array('yes', 'no')
))->addOption('output', array(
'help' => __d('cake_console', 'Full path to output directory.')
))->addOption('files', array(
'help' => __d('cake_console', 'Comma separated list of files.')
))->addOption('exclude-plugins', array(
'boolean' => true,
'default' => true,
'help' => __d('cake_console', 'Ignores all files in plugins if this command is run inside from the same app directory.')
))->addOption('plugin', array(
'help' => __d('cake_console', 'Extracts tokens only from the plugin specified and puts the result in the plugin\'s Locale directory.')
))->addOption('ignore-model-validation', array(
'boolean' => true,
'default' => false,
'help' => __d('cake_console', 'Ignores validation messages in the $validate property.' .
' If this flag is not set and the command is run from the same app directory,' .
' all messages in model validation rules will be extracted as tokens.'
)
))->addOption('validation-domain', array(
'help' => __d('cake_console', 'If set to a value, the localization domain to be used for model validation messages.')
))->addOption('exclude', array(
'help' => __d('cake_console', 'Comma separated list of directories to exclude.' .
' Any path containing a path segment with the provided values will be skipped. E.g. test,vendors'
)
))->addOption('overwrite', array(
'boolean' => true,
'default' => false,
'help' => __d('cake_console', 'Always overwrite existing .pot files.')
))->addOption('extract-core', array(
'help' => __d('cake_console', 'Extract messages from the CakePHP core libs.'),
'choices' => array('yes', 'no')
));
return $parser;
}
/**

View file

@ -60,13 +60,14 @@ class FixtureTask extends BakeTask {
}
/**
* get the option parser.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
$parser->description(
__d('cake_console', 'Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Name of the fixture to bake. Can use Plugin.name to bake plugin fixtures.')
@ -80,7 +81,7 @@ class FixtureTask extends BakeTask {
'default' => 'default'
))->addOption('plugin', array(
'help' => __d('cake_console', 'CamelCased name of the plugin to bake fixtures for.'),
'short' => 'p',
'short' => 'p'
))->addOption('schema', array(
'help' => __d('cake_console', 'Importing schema for fixtures rather than hardcoding it.'),
'short' => 's',
@ -92,10 +93,15 @@ class FixtureTask extends BakeTask {
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->addOption('records', array(
'help' => __d('cake_console', 'Used with --count and <name>/all commands to pull [n] records from the live tables, where [n] is either --count or the default of 10.'),
'help' => __d('cake_console', 'Used with --count and <name>/all commands to pull [n] records from the live tables, ' .
'where [n] is either --count or the default of 10.'),
'short' => 'r',
'boolean' => true
))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
))->epilog(
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
);
return $parser;
}
/**

View file

@ -348,18 +348,27 @@ class ModelTask extends BakeTask {
if (!$model instanceof Model) {
return false;
}
$fields = $model->schema();
$fields = $model->schema();
if (empty($fields)) {
return false;
}
$skipFields = false;
$validate = array();
$this->initValidations();
foreach ($fields as $fieldName => $field) {
$validation = $this->fieldValidation($fieldName, $field, $model->primaryKey);
if (isset($validation['_skipFields'])) {
unset($validation['_skipFields']);
$skipFields = true;
}
if (!empty($validation)) {
$validate[$fieldName] = $validation;
}
if ($skipFields) {
return $validate;
}
}
return $validate;
}
@ -399,6 +408,11 @@ class ModelTask extends BakeTask {
$defaultChoice = count($this->_validations);
$validate = $alreadyChosen = array();
$prompt = __d('cake_console',
"or enter in a valid regex validation string.\nAlternatively [s] skip the rest of the fields.\n"
);
$methods = array_flip($this->_validations);
$anotherValidator = 'y';
while ($anotherValidator === 'y') {
if ($this->interactive) {
@ -422,8 +436,6 @@ class ModelTask extends BakeTask {
$this->hr();
}
$prompt = __d('cake_console', "... or enter in a valid regex validation string.\n");
$methods = array_flip($this->_validations);
$guess = $defaultChoice;
if ($metaData['null'] != 1 && !in_array($fieldName, array($primaryKey, 'created', 'modified', 'updated'))) {
if ($fieldName === 'email') {
@ -453,6 +465,10 @@ class ModelTask extends BakeTask {
if ($this->interactive === true) {
$choice = $this->in($prompt, null, $guess);
if ($choice === 's') {
$validate['_skipFields'] = true;
return $validate;
}
if (in_array($choice, $alreadyChosen)) {
$this->out(__d('cake_console', "You have already chosen that validation rule,\nplease choose again"));
continue;
@ -480,7 +496,12 @@ class ModelTask extends BakeTask {
}
$anotherValidator = 'n';
if ($this->interactive && $choice != $defaultChoice) {
$anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n');
$anotherValidator = $this->in(__d('cake_console', "Would you like to add another validation rule\n" .
"or skip the rest of the fields?"), array('y', 'n', 's'), 'n');
if ($anotherValidator === 's') {
$validate['_skipFields'] = true;
return $validate;
}
}
}
return $validate;
@ -978,31 +999,36 @@ class ModelTask extends BakeTask {
}
/**
* get the option parser.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__d('cake_console', 'Bake models.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Name of the model to bake. Can use Plugin.name to bake plugin models.')
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake all model files with associations and validation.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __d('cake_console', 'Plugin to bake the model into.')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('connection', array(
'short' => 'c',
'help' => __d('cake_console', 'The connection the model table is on.')
))->addOption('force', array(
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
$parser->description(
__d('cake_console', 'Bake models.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Name of the model to bake. Can use Plugin.name to bake plugin models.')
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake all model files with associations and validation.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __d('cake_console', 'Plugin to bake the model into.')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('connection', array(
'short' => 'c',
'help' => __d('cake_console', 'The connection the model table is on.')
))->addOption('force', array(
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->epilog(
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
);
return $parser;
}
/**

View file

@ -211,18 +211,21 @@ class PluginTask extends AppShell {
}
/**
* get the option parser for the plugin task
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__d('cake_console',
'Create the directory structure, AppModel and AppController classes for a new plugin. ' .
'Can create plugins in any of your bootstrapped plugin paths.'
))->addArgument('name', array(
$parser->description(
__d('cake_console', 'Create the directory structure, AppModel and AppController classes for a new plugin. ' .
'Can create plugins in any of your bootstrapped plugin paths.')
)->addArgument('name', array(
'help' => __d('cake_console', 'CamelCased name of the plugin to create.')
));
return $parser;
}
}

View file

@ -419,26 +419,30 @@ class ProjectTask extends AppShell {
}
/**
* get the option parser.
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__d('cake_console', 'Generate a new CakePHP project skeleton.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.')
))->addOption('empty', array(
'boolean' => true,
'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('skel', array(
'default' => current(App::core('Console')) . 'Templates' . DS . 'skel',
'help' => __d('cake_console', 'The directory layout to use for the new application skeleton. Defaults to cake/Console/Templates/skel of CakePHP used to create the project.')
));
$parser->description(
__d('cake_console', 'Generate a new CakePHP project skeleton.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.')
))->addOption('empty', array(
'boolean' => true,
'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('skel', array(
'default' => current(App::core('Console')) . 'Templates' . DS . 'skel',
'help' => __d('cake_console', 'The directory layout to use for the new application skeleton.' .
' Defaults to cake/Console/Templates/skel of CakePHP used to create the project.')
));
return $parser;
}
}

View file

@ -543,34 +543,40 @@ class TestTask extends BakeTask {
}
/**
* get the option parser.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__d('cake_console', 'Bake test case skeletons for classes.'))
->addArgument('type', array(
'help' => __d('cake_console', 'Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'),
'choices' => array(
'Controller', 'controller',
'Model', 'model',
'Helper', 'helper',
'Component', 'component',
'Behavior', 'behavior'
)
))->addArgument('name', array(
'help' => __d('cake_console', 'An existing class to bake tests for.')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __d('cake_console', 'CamelCased name of the plugin to bake tests for.')
))->addOption('force', array(
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
$parser->description(
__d('cake_console', 'Bake test case skeletons for classes.')
)->addArgument('type', array(
'help' => __d('cake_console', 'Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'),
'choices' => array(
'Controller', 'controller',
'Model', 'model',
'Helper', 'helper',
'Component', 'component',
'Behavior', 'behavior'
)
))->addArgument('name', array(
'help' => __d('cake_console', 'An existing class to bake tests for.')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __d('cake_console', 'CamelCased name of the plugin to bake tests for.')
))->addOption('force', array(
'short' => 'f',
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->epilog(
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
);
return $parser;
}
}

View file

@ -412,13 +412,14 @@ class ViewTask extends BakeTask {
}
/**
* get the option parser for this task
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
$parser->description(
__d('cake_console', 'Bake views for a controller, using built-in or custom templates.')
)->addArgument('controller', array(
'help' => __d('cake_console', 'Name of the controller views to bake. Can be Plugin.name as a shortcut for plugin baking.')
@ -443,7 +444,11 @@ class ViewTask extends BakeTask {
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Bake all CRUD action views for all controllers. Requires models and controllers to exist.')
))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
))->epilog(
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
);
return $parser;
}
/**

View file

@ -38,20 +38,21 @@ class TestShell extends Shell {
protected $_dispatcher = null;
/**
* get the option parser for the test suite.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = new ConsoleOptionParser($this->name);
$parser->description(array(
__d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line'),
))->addArgument('category', array(
$parser->description(
__d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line')
)->addArgument('category', array(
'help' => __d('cake_console', 'The category for the test, or test file, to test.'),
'required' => false,
'required' => false
))->addArgument('file', array(
'help' => __d('cake_console', 'The path to the file, or test file, to test.'),
'required' => false,
'required' => false
))->addOption('log-junit', array(
'help' => __d('cake_console', '<file> Log test execution in JUnit XML format to file.'),
'default' => false
@ -153,9 +154,9 @@ class TestShell extends Shell {
'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'),
'default' => false
))->addOption('fixture', array(
'help' => __d('cake_console', 'Choose a custom fixture manager.'),
'help' => __d('cake_console', 'Choose a custom fixture manager.')
))->addOption('debug', array(
'help' => __d('cake_console', 'More verbose output.'),
'help' => __d('cake_console', 'More verbose output.')
));
return $parser;

View file

@ -32,15 +32,16 @@ App::uses('CakeTestLoader', 'TestSuite');
class TestsuiteShell extends TestShell {
/**
* get the option parser for the test suite.
* Gets the option parser instance and configures it.
*
* @return void
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->description(array(
__d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line'),
__d('cake_console', "<warning>This shell is for backwards-compatibility only</warning>\nuse the test shell instead"),
__d('cake_console', "<warning>This shell is for backwards-compatibility only</warning>\nuse the test shell instead")
));
return $parser;

View file

@ -199,7 +199,7 @@ class UpgradeShell extends AppShell {
$dir = $options;
$options = array();
}
$options = array_merge($defaultOptions, $options);
$options += $defaultOptions;
$this->_movePhpFiles($dir, $options);
}
}
@ -392,6 +392,11 @@ class UpgradeShell extends AppShell {
'/(\$this->action\b(?!\())/',
'$this->request->action'
),
array(
'$this->request->onlyAllow() -> $this->request->allowMethod()',
'/\$this->request->onlyAllow\(/',
'$this->request->allowMethod('
)
);
$this->_filesRegexpUpdate($patterns);
}
@ -500,6 +505,29 @@ class UpgradeShell extends AppShell {
$this->_filesRegexpUpdate($patterns);
}
/**
* Update controller redirects.
*
* - Make redirect statements return early.
*
* @return void
*/
public function controller_redirects() {
$this->_paths = App::Path('Controller');
if (!empty($this->params['plugin'])) {
$this->_paths = App::Path('Controller', $this->params['plugin']);
}
$patterns = array(
array(
'$this->redirect() to return $this->redirect()',
'/\t\$this-\>redirect\(/',
"\t" . 'return $this->redirect('
),
);
$this->_filesRegexpUpdate($patterns);
}
/**
* Update components.
*
@ -779,11 +807,13 @@ class UpgradeShell extends AppShell {
}
/**
* get the option parser
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$subcommandParser = array(
'options' => array(
'plugin' => array(
@ -808,53 +838,48 @@ class UpgradeShell extends AppShell {
)
);
return parent::getOptionParser()
->description(__d('cake_console', "A shell to help automate upgrading from CakePHP 1.3 to 2.0. \n" .
"Be sure to have a backup of your application before running these commands."))
->addSubcommand('all', array(
'help' => __d('cake_console', 'Run all upgrade commands.'),
'parser' => $subcommandParser
))
->addSubcommand('tests', array(
'help' => __d('cake_console', 'Update tests class names to FooTest rather than FooTestCase.'),
'parser' => $subcommandParser
))
->addSubcommand('locations', array(
'help' => __d('cake_console', 'Move files and folders to their new homes.'),
'parser' => $subcommandParser
))
->addSubcommand('i18n', array(
'help' => __d('cake_console', 'Update the i18n translation method calls.'),
'parser' => $subcommandParser
))
->addSubcommand('helpers', array(
'help' => __d('cake_console', 'Update calls to helpers.'),
'parser' => $subcommandParser
))
->addSubcommand('basics', array(
'help' => __d('cake_console', 'Update removed basics functions to PHP native functions.'),
'parser' => $subcommandParser
))
->addSubcommand('request', array(
'help' => __d('cake_console', 'Update removed request access, and replace with $this->request.'),
'parser' => $subcommandParser
))
->addSubcommand('configure', array(
'help' => __d('cake_console', "Update Configure::read() to Configure::read('debug')"),
'parser' => $subcommandParser
))
->addSubcommand('constants', array(
'help' => __d('cake_console', "Replace Obsolete constants"),
'parser' => $subcommandParser
))
->addSubcommand('components', array(
'help' => __d('cake_console', 'Update components to extend Component class.'),
'parser' => $subcommandParser
))
->addSubcommand('exceptions', array(
'help' => __d('cake_console', 'Replace use of cakeError with exceptions.'),
'parser' => $subcommandParser
));
$parser->description(
__d('cake_console', "A shell to help automate upgrading from CakePHP 1.3 to 2.0. \n" .
"Be sure to have a backup of your application before running these commands."
))->addSubcommand('all', array(
'help' => __d('cake_console', 'Run all upgrade commands.'),
'parser' => $subcommandParser
))->addSubcommand('tests', array(
'help' => __d('cake_console', 'Update tests class names to FooTest rather than FooTestCase.'),
'parser' => $subcommandParser
))->addSubcommand('locations', array(
'help' => __d('cake_console', 'Move files and folders to their new homes.'),
'parser' => $subcommandParser
))->addSubcommand('i18n', array(
'help' => __d('cake_console', 'Update the i18n translation method calls.'),
'parser' => $subcommandParser
))->addSubcommand('helpers', array(
'help' => __d('cake_console', 'Update calls to helpers.'),
'parser' => $subcommandParser
))->addSubcommand('basics', array(
'help' => __d('cake_console', 'Update removed basics functions to PHP native functions.'),
'parser' => $subcommandParser
))->addSubcommand('request', array(
'help' => __d('cake_console', 'Update removed request access, and replace with $this->request.'),
'parser' => $subcommandParser
))->addSubcommand('configure', array(
'help' => __d('cake_console', "Update Configure::read() to Configure::read('debug')"),
'parser' => $subcommandParser
))->addSubcommand('constants', array(
'help' => __d('cake_console', "Replace Obsolete constants"),
'parser' => $subcommandParser
))->addSubcommand('controller_redirects', array(
'help' => __d('cake_console', 'Return early on controller redirect calls.'),
'parser' => $subcommandParser
))->addSubcommand('components', array(
'help' => __d('cake_console', 'Update components to extend Component class.'),
'parser' => $subcommandParser
))->addSubcommand('exceptions', array(
'help' => __d('cake_console', 'Replace use of cakeError with exceptions.'),
'parser' => $subcommandParser
));
return $parser;
}
}

View file

@ -299,7 +299,7 @@ class ConsoleOptionParser {
'boolean' => false,
'choices' => array()
);
$options = array_merge($defaults, $options);
$options += $defaults;
$option = new ConsoleInputOption($options);
}
$this->_options[$name] = $option;
@ -338,7 +338,7 @@ class ConsoleOptionParser {
'required' => false,
'choices' => array()
);
$options = array_merge($defaults, $params);
$options = $params + $defaults;
$index = $options['index'];
unset($options['index']);
$arg = new ConsoleInputArgument($options);
@ -403,7 +403,7 @@ class ConsoleOptionParser {
'help' => '',
'parser' => null
);
$options = array_merge($defaults, $options);
$options += $defaults;
$command = new ConsoleInputSubcommand($options);
}
$this->_subcommands[$name] = $command;

View file

@ -462,6 +462,7 @@ class Shell extends Object {
/**
* Gets the option parser instance and configures it.
*
* By overriding this method you can configure the ConsoleOptionParser before returning it.
*
* @return ConsoleOptionParser

View file

@ -311,7 +311,7 @@ class ShellDispatcher {
$params = str_replace('/', '\\', $params);
}
$this->params = array_merge($this->params, $params);
$this->params = $params + $this->params;
}
/**

View file

@ -135,7 +135,7 @@
if (!$this-><?php echo $currentModelName; ?>->exists()) {
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
}
$this->request->onlyAllow('post', 'delete');
$this->request->allowMethod('post', 'delete');
if ($this-><?php echo $currentModelName; ?>->delete()) {
<?php if ($wannaUseSession): ?>
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> has been deleted.'));

View file

@ -75,6 +75,7 @@ class <?php echo $fullClassName; ?>Test extends CakeTestCase {
* @return void
*/
public function test<?php echo Inflector::camelize($method); ?>() {
$this->markTestIncomplete('test<?php echo Inflector::camelize($method); ?> not implemented.');
}
<?php endforeach; ?>

View file

@ -47,7 +47,7 @@
echo "\t\t<td class=\"actions\">\n";
echo "\t\t\t<?php echo \$this->Html->link(__('View'), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t\t<?php echo \$this->Html->link(__('Edit'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t\t<?php echo \$this->Form->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t\t<?php echo \$this->Form->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), array(), __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
echo "\t\t</td>\n";
echo "\t</tr>\n";

View file

@ -41,12 +41,15 @@
*
* unix_socket =>
* For MySQL to connect via socket specify the `unix_socket` parameter instead of `host` and `port`
*
* settings =>
* Array of key/value pairs, on connection it executes SET statements for each pair
* For MySQL : http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
* For Postgres : http://www.postgresql.org/docs/9.2/static/sql-set.html
* For Sql Server : http://msdn.microsoft.com/en-us/library/ms190356.aspx
*
* flags =>
* A key/value array of driver specific connection options.
*/
class DATABASE_CONFIG {

View file

@ -0,0 +1,26 @@
<?php
/**
* AllTests file
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package app.Test.Case
* @since CakePHP(tm) v 2.5
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
class AllTestsTest extends CakeTestSuite {
public static function suite() {
$suite = new CakeTestSuite('All application tests');
$suite->addTestDirectoryRecursive(TESTS . 'Case');
return $suite;
}
}

View file

@ -7,7 +7,7 @@
* @since CakePHP(tm) v 0.10.0.1076
*/
?>
<h2><?php echo $name; ?></h2>
<h2><?php echo $message; ?></h2>
<p class="error">
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
<?php printf(

View file

@ -7,7 +7,7 @@
* @since CakePHP(tm) v 0.10.0.1076
*/
?>
<h2><?php echo $name; ?></h2>
<h2><?php echo $message; ?></h2>
<p class="error">
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
<?php echo __d('cake', 'An Internal Error Has Occurred.'); ?>

View file

@ -10,7 +10,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title><?php echo $title_for_layout; ?></title>
<title><?php echo $this->fetch('title'); ?></title>
</head>
<body>
<?php echo $this->fetch('content'); ?>

View file

@ -15,7 +15,7 @@ $cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework
<?php echo $this->Html->charset(); ?>
<title>
<?php echo $cakeDescription ?>:
<?php echo $title_for_layout; ?>
<?php echo $this->fetch('title'); ?>
</title>
<?php
echo $this->Html->meta('icon');

View file

@ -15,7 +15,7 @@ $cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework
<?php echo $this->Html->charset(); ?>
<title>
<?php echo $cakeDescription ?>:
<?php echo $title_for_layout; ?>
<?php echo $this->fetch('title'); ?>
</title>
<?php
echo $this->Html->meta('icon');

View file

@ -3,7 +3,7 @@ if (!isset($channel)):
$channel = array();
endif;
if (!isset($channel['title'])):
$channel['title'] = $title_for_layout;
$channel['title'] = $this->fetch('title');
endif;
echo $this->Rss->document(

View file

@ -92,7 +92,7 @@ class Component extends Object {
*/
public function __get($name) {
if (isset($this->_componentMap[$name]) && !isset($this->{$name})) {
$settings = array_merge((array)$this->_componentMap[$name]['settings'], array('enabled' => false));
$settings = array('enabled' => false) + (array)$this->_componentMap[$name]['settings'];
$this->{$name} = $this->_Collection->load($this->_componentMap[$name]['class'], $settings);
}
if (isset($this->{$name})) {

View file

@ -81,7 +81,7 @@ class PhpAcl extends Object implements AclInterface {
*/
public function initialize(Component $Component) {
if (!empty($Component->settings['adapter'])) {
$this->options = array_merge($this->options, $Component->settings['adapter']);
$this->options = $Component->settings['adapter'] + $this->options;
}
App::uses('PhpReader', 'Configure');
@ -546,7 +546,7 @@ class PhpAro {
* @return void
*/
public function addAlias(array $alias) {
$this->aliases = array_merge($this->aliases, $alias);
$this->aliases = $alias + $this->aliases;
}
/**

View file

@ -365,6 +365,7 @@ class AuthComponent extends Component {
return false;
}
if (!empty($this->ajaxLogin)) {
$controller->response->statusCode(403);
$controller->viewPath = 'Elements';
echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
$this->_stop();
@ -775,6 +776,10 @@ class AuthComponent extends Component {
unset($config[AuthComponent::ALL]);
}
foreach ($config as $class => $settings) {
if (!empty($settings['className'])) {
$class = $settings['className'];
unset($settings['className']);
}
list($plugin, $class) = pluginSplit($class, true);
$className = $class . 'Authenticate';
App::uses($className, $plugin . 'Controller/Component/Auth');
@ -808,6 +813,7 @@ class AuthComponent extends Component {
* Check whether or not the current user has data in the session, and is considered logged in.
*
* @return boolean true if the user is logged in, false otherwise
* @deprecated Since 2.5. Use AuthComponent::user() directly.
*/
public function loggedIn() {
return (bool)$this->user();

View file

@ -130,7 +130,9 @@ class CookieComponent extends Component {
* Type of encryption to use.
*
* Currently two methods are available: cipher and rijndael
* Defaults to Security::cipher();
* Defaults to Security::cipher(). Cipher is horribly insecure and only
* the default because of backwards compatibility. In new applications you should
* always change this to 'aes' or 'rijndael'.
*
* @var string
*/
@ -378,10 +380,11 @@ class CookieComponent extends Component {
public function type($type = 'cipher') {
$availableTypes = array(
'cipher',
'rijndael'
'rijndael',
'aes'
);
if (!in_array($type, $availableTypes)) {
trigger_error(__d('cake_dev', 'You must use cipher or rijndael for cookie encryption type'), E_USER_WARNING);
trigger_error(__d('cake_dev', 'You must use cipher, rijndael or aes for cookie encryption type'), E_USER_WARNING);
$type = 'cipher';
}
$this->_type = $type;
@ -469,12 +472,20 @@ class CookieComponent extends Component {
if (is_array($value)) {
$value = $this->_implode($value);
}
if ($this->_encrypted === true) {
$type = $this->_type;
$value = "Q2FrZQ==." . base64_encode(Security::$type($value, $this->key, 'encrypt'));
if (!$this->_encrypted) {
return $value;
}
return $value;
$prefix = "Q2FrZQ==.";
if ($this->_type === 'rijndael') {
$cipher = Security::rijndael($value, $this->key, 'encrypt');
}
if ($this->_type === 'cipher') {
$cipher = Security::cipher($value, $this->key);
}
if ($this->_type === 'aes') {
$cipher = Security::encrypt($value, $this->key);
}
return $prefix . base64_encode($cipher);
}
/**
@ -490,27 +501,40 @@ class CookieComponent extends Component {
foreach ((array)$values as $name => $value) {
if (is_array($value)) {
foreach ($value as $key => $val) {
$pos = strpos($val, 'Q2FrZQ==.');
$decrypted[$name][$key] = $this->_explode($val);
if ($pos !== false) {
$val = substr($val, 8);
$decrypted[$name][$key] = $this->_explode(Security::$type(base64_decode($val), $this->key, 'decrypt'));
}
$decrypted[$name][$key] = $this->_decode($val);
}
} else {
$pos = strpos($value, 'Q2FrZQ==.');
$decrypted[$name] = $this->_explode($value);
if ($pos !== false) {
$value = substr($value, 8);
$decrypted[$name] = $this->_explode(Security::$type(base64_decode($value), $this->key, 'decrypt'));
}
$decrypted[$name] = $this->_decode($value);
}
}
return $decrypted;
}
/**
* Decodes and decrypts a single value.
*
* @param string $value The value to decode & decrypt.
* @return string Decoded value.
*/
protected function _decode($value) {
$prefix = 'Q2FrZQ==.';
$pos = strpos($value, $prefix);
if ($pos === false) {
return $this->_explode($value);
}
$value = base64_decode(substr($value, strlen($prefix)));
if ($this->_type === 'rijndael') {
$plain = Security::rijndael($value, $this->key, 'decrypt');
}
if ($this->_type === 'cipher') {
$plain = Security::cipher($value, $this->key);
}
if ($this->_type === 'aes') {
$plain = Security::decrypt($value, $this->key);
}
return $this->_explode($plain);
}
/**
* Implode method to keep keys are multidimensional arrays
*

View file

@ -202,6 +202,8 @@ class PaginatorComponent extends Component {
$count = 0;
} elseif ($object->hasMethod('paginateCount')) {
$count = $object->paginateCount($conditions, $recursive, $extra);
} elseif ($page === 1 && count($results) < $limit) {
$count = count($results);
} else {
$parameters = compact('conditions');
if ($recursive != $object->recursive) {

View file

@ -603,13 +603,12 @@ class RequestHandlerComponent extends Component {
if (Configure::read('App.encoding') !== null) {
$defaults['charset'] = Configure::read('App.encoding');
}
$options = array_merge($defaults, $options);
$options += $defaults;
if ($type === 'ajax') {
$controller->layout = $this->ajaxLayout;
return $this->respondAs('html', $options);
}
$controller->ext = '.ctp';
$pluginDot = null;
$viewClassMap = $this->viewClassMap();

View file

@ -28,7 +28,8 @@ App::uses('Scaffold', 'View');
* and afford the web developer an early look at the data, and the possibility to over-ride
* scaffolded actions with custom-made ones.
*
* @package Cake.Controller
* @package Cake.Controller
* @deprecated Dynamic scaffolding will be removed and replaced in 3.0
*/
class Scaffold {

View file

@ -108,12 +108,12 @@ class CakePlugin {
* {{{
* CakePlugin::loadAll(array(
* array('bootstrap' => true),
* 'DebugKit' => array('routes' => true),
* 'DebugKit' => array('routes' => true, 'bootstrap' => false),
* ))
* }}}
*
* The above example will load the bootstrap file for all plugins, but for DebugKit it will only load the routes file
* and will not look for any bootstrap script.
* The above example will load the bootstrap file for all plugins, but for DebugKit it will only load
* the routes file and will not look for any bootstrap script.
*
* @param array $options
* @return void
@ -121,11 +121,11 @@ class CakePlugin {
public static function loadAll($options = array()) {
$plugins = App::objects('plugins');
foreach ($plugins as $p) {
$opts = isset($options[$p]) ? $options[$p] : null;
if ($opts === null && isset($options[0])) {
$opts = $options[0];
$opts = isset($options[$p]) ? (array)$options[$p] : array();
if (isset($options[0])) {
$opts += $options[0];
}
self::load($p, (array)$opts);
self::load($p, $opts);
}
}

View file

@ -287,7 +287,7 @@ class Configure {
* @param string $key name of configuration resource to load.
* @param string $config Name of the configured reader to use to read the resource identified by $key.
* @param boolean $merge if config files should be merged instead of simply overridden
* @return mixed false if file not found, void if load successful.
* @return boolean False if file not found, true if load successful.
* @throws ConfigureException Will throw any exceptions the reader raises.
*/
public static function load($key, $config = 'default', $merge = true) {
@ -424,6 +424,7 @@ class Configure {
self::$_values = array();
return true;
}
/**
* Set the error and exception handlers.
*
@ -444,4 +445,5 @@ class Configure {
set_exception_handler($exception['handler']);
}
}
}

View file

@ -84,7 +84,7 @@ class Object {
if ($arrayUrl && !isset($extra['data'])) {
$extra['data'] = array();
}
$extra = array_merge(array('autoRender' => 0, 'return' => 1, 'bare' => 1, 'requested' => 1), $extra);
$extra += array('autoRender' => 0, 'return' => 1, 'bare' => 1, 'requested' => 1);
$data = isset($extra['data']) ? $extra['data'] : null;
unset($extra['data']);
@ -95,7 +95,7 @@ class Object {
$request = new CakeRequest($url);
} elseif (is_array($url)) {
$params = $url + array('pass' => array(), 'named' => array(), 'base' => false);
$params = array_merge($params, $extra);
$params = $extra + $params;
$request = new CakeRequest(Router::reverse($params));
}
if (isset($data)) {

View file

@ -189,10 +189,11 @@ class ExceptionRenderer {
$this->controller->response->statusCode($code);
$this->controller->set(array(
'code' => $code,
'url' => h($url),
'name' => h($error->getMessage()),
'message' => h($error->getMessage()),
'url' => h($url),
'error' => $error,
'_serialize' => array('code', 'url', 'name')
'_serialize' => array('code', 'name', 'message', 'url')
));
$this->controller->set($error->getAttributes());
$this->_outputMessage($this->template);
@ -213,9 +214,10 @@ class ExceptionRenderer {
$this->controller->response->statusCode($error->getCode());
$this->controller->set(array(
'name' => h($message),
'message' => h($message),
'url' => h($url),
'error' => $error,
'_serialize' => array('name', 'url')
'_serialize' => array('name', 'message', 'url')
));
$this->_outputMessage('error400');
}
@ -236,9 +238,10 @@ class ExceptionRenderer {
$this->controller->response->statusCode($code);
$this->controller->set(array(
'name' => h($message),
'message' => h($url),
'message' => h($message),
'url' => h($url),
'error' => $error,
'_serialize' => array('name', 'message')
'_serialize' => array('name', 'message', 'url')
));
$this->_outputMessage('error500');
}
@ -255,10 +258,11 @@ class ExceptionRenderer {
$this->controller->response->statusCode($code);
$this->controller->set(array(
'code' => $code,
'url' => h($url),
'name' => h($error->getMessage()),
'message' => h($error->getMessage()),
'url' => h($url),
'error' => $error,
'_serialize' => array('code', 'url', 'name', 'error')
'_serialize' => array('code', 'name', 'message', 'url', 'error')
));
$this->_outputMessage($this->template);
}

View file

@ -222,22 +222,19 @@ class CakeEventManager {
* Dispatches a new event to all configured listeners
*
* @param string|CakeEvent $event the event key name or instance of CakeEvent
* @return void
* @return CakeEvent
*/
public function dispatch($event) {
if (is_string($event)) {
$event = new CakeEvent($event);
}
if (!$this->_isGlobal) {
self::instance()->dispatch($event);
$listeners = $this->listeners($event->name());
if (empty($listeners)) {
return $event;
}
if (empty($this->_listeners[$event->name()])) {
return;
}
foreach ($this->listeners($event->name()) as $listener) {
foreach ($listeners as $listener) {
if ($event->isStopped()) {
break;
}
@ -253,6 +250,7 @@ class CakeEventManager {
$event->result = $result;
}
}
return $event;
}
/**
@ -262,15 +260,41 @@ class CakeEventManager {
* @return array
*/
public function listeners($eventKey) {
if (empty($this->_listeners[$eventKey])) {
return array();
$localListeners = array();
$priorities = array();
if (!$this->_isGlobal) {
$localListeners = $this->prioritisedListeners($eventKey);
$localListeners = empty($localListeners) ? array() : $localListeners;
}
ksort($this->_listeners[$eventKey]);
$globalListeners = self::instance()->prioritisedListeners($eventKey);
$globalListeners = empty($globalListeners) ? array() : $globalListeners;
$priorities = array_merge(array_keys($globalListeners), array_keys($localListeners));
$priorities = array_unique($priorities);
asort($priorities);
$result = array();
foreach ($this->_listeners[$eventKey] as $priorityQ) {
$result = array_merge($result, $priorityQ);
foreach ($priorities as $priority) {
if (isset($globalListeners[$priority])) {
$result = array_merge($result, $globalListeners[$priority]);
}
if (isset($localListeners[$priority])) {
$result = array_merge($result, $localListeners[$priority]);
}
}
return $result;
}
/**
* Returns the listeners for the specified event key indexed by priority
*
* @param string $eventKey
* @return array
*/
public function prioritisedListeners($eventKey) {
if (empty($this->_listeners[$eventKey])) {
return array();
}
return $this->_listeners[$eventKey];
}
}

View file

@ -87,6 +87,68 @@ class I18n {
'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME', 'LC_MESSAGES'
);
/**
* Constants for the translation categories.
*
* The constants may be used in translation fetching
* instead of hardcoded integers.
* Example:
* {{{
* I18n::translate('CakePHP is awesome.', null, null, I18n::LC_MESSAGES)
* }}}
*
* To keep the code more readable, I18n constants are preferred over
* hardcoded integers.
*/
/**
* Constant for LC_ALL.
*
* @var int
*/
const LC_ALL = 0;
/**
* Constant for LC_COLLATE.
*
* @var int
*/
const LC_COLLATE = 1;
/**
* Constant for LC_CTYPE.
*
* @var int
*/
const LC_CTYPE = 2;
/**
* Constant for LC_MONETARY.
*
* @var int
*/
const LC_MONETARY = 3;
/**
* Constant for LC_NUMERIC.
*
* @var int
*/
const LC_NUMERIC = 4;
/**
* Constant for LC_TIME.
*
* @var int
*/
const LC_TIME = 5;
/**
* Constant for LC_MESSAGES.
*
* @var int
*/
const LC_MESSAGES = 6;
/**
* Escape string
*
@ -129,7 +191,7 @@ class I18n {
* @return string translated string.
* @throws CakeException When '' is provided as a domain.
*/
public static function translate($singular, $plural = null, $domain = null, $category = 6, $count = null, $language = null) {
public static function translate($singular, $plural = null, $domain = null, $category = self::LC_MESSAGES, $count = null, $language = null) {
$_this = I18n::getInstance();
if (strpos($singular, "\r\n") !== false) {

View file

@ -370,18 +370,6 @@ class CakeLog {
return false;
}
/**
* Configures the automatic/default stream a FileLog.
*
* @return void
*/
protected static function _autoConfig() {
self::$_Collection->load('default', array(
'engine' => 'File',
'path' => LOGS,
));
}
/**
* Writes the given message and type to all of the configured log adapters.
* Configured adapters are passed both the $type and $message variables. $type
@ -453,11 +441,7 @@ class CakeLog {
$logged = true;
}
}
if (!$logged) {
self::_autoConfig();
self::stream('default')->write($type, $message);
}
return true;
return $logged;
}
/**

View file

@ -67,7 +67,7 @@ class TreeBehavior extends ModelBehavior {
$config['type'] = $config[0];
unset($config[0]);
}
$settings = array_merge($this->_defaults, $config);
$settings = $config + $this->_defaults;
if (in_array($settings['scope'], $Model->getAssociated('belongsTo'))) {
$data = $Model->getAssociated($settings['scope']);
@ -744,7 +744,7 @@ class TreeBehavior extends ModelBehavior {
* @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::reorder
*/
public function reorder(Model $Model, $options = array()) {
$options = array_merge(array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify' => true), $options);
$options += array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify' => true);
extract($options);
if ($verify && !$this->verify($Model)) {
return false;

View file

@ -127,6 +127,13 @@ class CakeSession {
*/
protected static $_initialized = false;
/**
* Session cookie name
*
* @var string
*/
protected static $_cookieName = null;
/**
* Pseudo constructor.
*
@ -221,12 +228,10 @@ class CakeSession {
* @return boolean True if variable is there
*/
public static function check($name = null) {
if (!self::start()) {
return false;
}
if (empty($name)) {
if (empty($name) || !self::_hasSession() || !self::start()) {
return false;
}
return Hash::get($_SESSION, $name) !== null;
}
@ -320,7 +325,7 @@ class CakeSession {
* @return boolean Success
*/
public static function valid() {
if (self::read('Config')) {
if (self::start() && self::read('Config')) {
if (self::_validAgentAndTime() && self::$error === false) {
self::$valid = true;
} else {
@ -368,18 +373,19 @@ class CakeSession {
* Returns given session variable, or all of them, if no parameters given.
*
* @param string|array $name The name of the session variable (or a path as sent to Set.extract)
* @return mixed The value of the session variable
* @return mixed The value of the session variable, null if session not available,
* session not started, or provided name not found in the session.
*/
public static function read($name = null) {
if (!self::start()) {
if (empty($name) && $name !== null) {
return false;
}
if (!self::_hasSession() || !self::start()) {
return null;
}
if ($name === null) {
return self::_returnSessionVars();
}
if (empty($name)) {
return false;
}
$result = Hash::get($_SESSION, $name);
if (isset($result)) {
@ -409,12 +415,10 @@ class CakeSession {
* @return boolean True if the write was successful, false if the write failed
*/
public static function write($name, $value = null) {
if (!self::start()) {
return false;
}
if (empty($name)) {
if (empty($name) || !self::start()) {
return false;
}
$write = $name;
if (!is_array($name)) {
$write = array($name => $value);
@ -442,6 +446,7 @@ class CakeSession {
$_SESSION = null;
self::$id = null;
self::$_cookieName = null;
}
/**
@ -481,9 +486,12 @@ class CakeSession {
if (!isset($sessionConfig['ini']['session.cookie_lifetime'])) {
$sessionConfig['ini']['session.cookie_lifetime'] = $sessionConfig['cookieTimeout'] * 60;
}
if (!isset($sessionConfig['ini']['session.name'])) {
$sessionConfig['ini']['session.name'] = $sessionConfig['cookie'];
}
self::$_cookieName = $sessionConfig['ini']['session.name'];
if (!empty($sessionConfig['handler'])) {
$sessionConfig['ini']['session.save_handler'] = 'user';
}
@ -521,6 +529,30 @@ class CakeSession {
self::$sessionTime = self::$time + ($sessionConfig['timeout'] * 60);
}
/**
* Get session cookie name.
*
* @return string
*/
protected static function _cookieName() {
if (self::$_cookieName !== null) {
return self::$_cookieName;
}
self::init();
self::_configureSession();
return self::$_cookieName = session_name();
}
/**
* Returns whether a session exists
* @return boolean
*/
protected static function _hasSession() {
return self::started() || isset($_COOKIE[self::_cookieName()]);
}
/**
* Find the handler class and make sure it implements the correct interface.
*

View file

@ -183,12 +183,12 @@ class DataSource extends Object {
*
* To-be-overridden in subclasses.
*
* @param Model $model The Model to be created.
* @param Model $Model The Model to be created.
* @param array $fields An Array of fields to be saved.
* @param array $values An Array of values to save.
* @return boolean success
*/
public function create(Model $model, $fields = null, $values = null) {
public function create(Model $Model, $fields = null, $values = null) {
return false;
}
@ -197,12 +197,12 @@ class DataSource extends Object {
*
* To-be-overridden in subclasses.
*
* @param Model $model The model being read.
* @param Model $Model The model being read.
* @param array $queryData An array of query data used to find the data you want
* @param integer $recursive Number of levels of association
* @return mixed
*/
public function read(Model $model, $queryData = array(), $recursive = null) {
public function read(Model $Model, $queryData = array(), $recursive = null) {
return false;
}
@ -211,13 +211,13 @@ class DataSource extends Object {
*
* To-be-overridden in subclasses.
*
* @param Model $model Instance of the model class being updated
* @param Model $Model Instance of the model class being updated
* @param array $fields Array of fields to be updated
* @param array $values Array of values to be update $fields to.
* @param mixed $conditions
* @return boolean Success
*/
public function update(Model $model, $fields = null, $values = null, $conditions = null) {
public function update(Model $Model, $fields = null, $values = null, $conditions = null) {
return false;
}
@ -226,11 +226,11 @@ class DataSource extends Object {
*
* To-be-overridden in subclasses.
*
* @param Model $model The model class having record(s) deleted
* @param Model $Model The model class having record(s) deleted
* @param mixed $conditions The conditions to use for deleting.
* @return boolean Success
*/
public function delete(Model $model, $conditions = null) {
public function delete(Model $Model, $conditions = null) {
return false;
}
@ -318,95 +318,90 @@ class DataSource extends Object {
*
* @param string $query Query string needing replacements done.
* @param array $data Array of data with values that will be inserted in placeholders.
* @param string $association Name of association model being replaced
* @param array $assocData
* @param Model $model Instance of the model to replace $__cakeID__$
* @param Model $linkModel Instance of model to replace $__cakeForeignKey__$
* @param string $association Name of association model being replaced.
* @param Model $Model Model instance.
* @param array $stack
* @return string String of query data with placeholders replaced.
* @return mixed String of query data with placeholders replaced, or false on failure.
*/
public function insertQueryData($query, $data, $association, $assocData, Model $model, Model $linkModel, $stack) {
public function insertQueryData($query, $data, $association, Model $Model, $stack) {
$keys = array('{$__cakeID__$}', '{$__cakeForeignKey__$}');
$modelAlias = $Model->alias;
foreach ($keys as $key) {
$val = null;
$type = null;
if (strpos($query, $key) !== false) {
switch ($key) {
case '{$__cakeID__$}':
if (isset($data[$model->alias]) || isset($data[$association])) {
if (isset($data[$model->alias][$model->primaryKey])) {
$val = $data[$model->alias][$model->primaryKey];
} elseif (isset($data[$association][$model->primaryKey])) {
$val = $data[$association][$model->primaryKey];
}
} else {
$found = false;
foreach (array_reverse($stack) as $assoc) {
if (isset($data[$assoc]) && isset($data[$assoc][$model->primaryKey])) {
$val = $data[$assoc][$model->primaryKey];
$found = true;
break;
}
}
if (!$found) {
$val = '';
}
}
$type = $model->getColumnType($model->primaryKey);
break;
case '{$__cakeForeignKey__$}':
foreach ($model->associations() as $name) {
foreach ($model->$name as $assocName => $assoc) {
if ($assocName === $association) {
if (isset($assoc['foreignKey'])) {
$foreignKey = $assoc['foreignKey'];
$assocModel = $model->$assocName;
$type = $assocModel->getColumnType($assocModel->primaryKey);
if (isset($data[$model->alias][$foreignKey])) {
$val = $data[$model->alias][$foreignKey];
} elseif (isset($data[$association][$foreignKey])) {
$val = $data[$association][$foreignKey];
} else {
$found = false;
foreach (array_reverse($stack) as $assoc) {
if (isset($data[$assoc]) && isset($data[$assoc][$foreignKey])) {
$val = $data[$assoc][$foreignKey];
$found = true;
break;
}
}
if (!$found) {
$val = '';
}
}
}
break 3;
}
}
}
break;
}
if (empty($val) && $val !== '0') {
return false;
}
$query = str_replace($key, $this->value($val, $type), $query);
if (strpos($query, $key) === false) {
continue;
}
$insertKey = $InsertModel = null;
switch ($key) {
case '{$__cakeID__$}':
$InsertModel = $Model;
$insertKey = $Model->primaryKey;
break;
case '{$__cakeForeignKey__$}':
foreach ($Model->associations() as $type) {
foreach ($Model->{$type} as $assoc => $assocData) {
if ($assoc !== $association) {
continue;
}
if (isset($assocData['foreignKey'])) {
$InsertModel = $Model->{$assoc};
$insertKey = $assocData['foreignKey'];
}
break 3;
}
}
break;
}
$val = $dataType = null;
if (!empty($insertKey) && !empty($InsertModel)) {
if (isset($data[$modelAlias][$insertKey])) {
$val = $data[$modelAlias][$insertKey];
} elseif (isset($data[$association][$insertKey])) {
$val = $data[$association][$insertKey];
} else {
$found = false;
foreach (array_reverse($stack) as $assocData) {
if (isset($data[$assocData]) && isset($data[$assocData][$insertKey])) {
$val = $data[$assocData][$insertKey];
$found = true;
break;
}
}
if (!$found) {
$val = '';
}
}
$dataType = $InsertModel->getColumnType($InsertModel->primaryKey);
}
if (empty($val) && $val !== '0') {
return false;
}
$query = str_replace($key, $this->value($val, $dataType), $query);
}
return $query;
}
/**
* To-be-overridden in subclasses.
*
* @param Model $model Model instance
* @param Model $Model Model instance
* @param string $key Key name to make
* @return string Key name for model.
*/
public function resolveKey(Model $model, $key) {
return $model->alias . $key;
public function resolveKey(Model $Model, $key) {
return $Model->alias . $key;
}
/**

View file

@ -45,7 +45,8 @@ class Mysql extends DboSource {
'login' => 'root',
'password' => '',
'database' => 'cake',
'port' => '3306'
'port' => '3306',
'flags' => array()
);
/**
@ -84,7 +85,13 @@ class Mysql extends DboSource {
public $fieldParameters = array(
'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault'),
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => ' ', 'column' => 'Collation', 'position' => 'beforeDefault'),
'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault')
'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault'),
'unsigned' => array(
'value' => 'UNSIGNED', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault',
'noVal' => true,
'options' => array(true),
'types' => array('integer', 'float', 'decimal', 'biginteger')
)
);
/**
@ -110,6 +117,7 @@ class Mysql extends DboSource {
'biginteger' => array('name' => 'bigint', 'limit' => '20'),
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'decimal' => array('name' => 'decimal', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
@ -144,7 +152,7 @@ class Mysql extends DboSource {
$config = $this->config;
$this->connected = false;
$flags = array(
$flags = $config['flags'] + array(
PDO::ATTR_PERSISTENT => $config['persistent'],
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
@ -338,8 +346,11 @@ class Mysql extends DboSource {
'type' => $this->column($column->Type),
'null' => ($column->Null === 'YES' ? true : false),
'default' => $column->Default,
'length' => $this->length($column->Type),
'length' => $this->length($column->Type)
);
if (in_array($fields[$column->Field]['type'], $this->fieldParameters['unsigned']['types'], true)) {
$fields[$column->Field]['unsigned'] = $this->_unsigned($column->Type);
}
if (!empty($column->Key) && isset($this->index[$column->Key])) {
$fields[$column->Field]['key'] = $this->index[$column->Key];
}
@ -761,9 +772,12 @@ class Mysql extends DboSource {
if (strpos($col, 'blob') !== false || $col === 'binary') {
return 'binary';
}
if (strpos($col, 'float') !== false || strpos($col, 'double') !== false || strpos($col, 'decimal') !== false) {
if (strpos($col, 'float') !== false || strpos($col, 'double') !== false) {
return 'float';
}
if (strpos($col, 'decimal') !== false || strpos($col, 'numeric') !== false) {
return 'decimal';
}
if (strpos($col, 'enum') !== false) {
return "enum($vals)";
}
@ -788,4 +802,14 @@ class Mysql extends DboSource {
return $this->useNestedTransactions && version_compare($this->getVersion(), '4.1', '>=');
}
/**
* Check if column type is unsigned
*
* @param string $real Real database-layer column type (i.e. "varchar(255)")
* @return bool True if column is unsigned, false otherwise
*/
protected function _unsigned($real) {
return strpos(strtolower($real), 'unsigned') !== false;
}
}

View file

@ -45,7 +45,8 @@ class Postgres extends DboSource {
'database' => 'cake',
'schema' => 'public',
'port' => 5432,
'encoding' => ''
'encoding' => '',
'flags' => array()
);
/**
@ -60,6 +61,7 @@ class Postgres extends DboSource {
'integer' => array('name' => 'integer', 'formatter' => 'intval'),
'biginteger' => array('name' => 'bigint', 'limit' => '20'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'decimal' => array('name' => 'decimal', 'formatter' => 'floatval'),
'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
@ -109,7 +111,7 @@ class Postgres extends DboSource {
$config = $this->config;
$this->connected = false;
$flags = array(
$flags = $config['flags'] + array(
PDO::ATTR_PERSISTENT => $config['persistent'],
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
@ -675,7 +677,7 @@ class Postgres extends DboSource {
}
$floats = array(
'float', 'float4', 'float8', 'double', 'double precision', 'decimal', 'real', 'numeric'
'float', 'float4', 'float8', 'double', 'double precision', 'real'
);
switch (true) {
@ -695,6 +697,8 @@ class Postgres extends DboSource {
return 'text';
case (strpos($col, 'bytea') !== false):
return 'binary';
case ($col === 'decimal' || $col === 'numeric'):
return 'decimal';
case (in_array($col, $floats)):
return 'float';
default:

View file

@ -56,7 +56,8 @@ class Sqlite extends DboSource {
*/
protected $_baseConfig = array(
'persistent' => false,
'database' => null
'database' => null,
'flags' => array()
);
/**
@ -71,6 +72,7 @@ class Sqlite extends DboSource {
'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'),
'biginteger' => array('name' => 'bigint', 'limit' => 20),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'decimal' => array('name' => 'decimal', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
@ -105,7 +107,7 @@ class Sqlite extends DboSource {
*/
public function connect() {
$config = $this->config;
$flags = array(
$flags = $config['flags'] + array(
PDO::ATTR_PERSISTENT => $config['persistent'],
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
@ -277,7 +279,7 @@ class Sqlite extends DboSource {
return 'binary';
}
if (strpos($col, 'numeric') !== false || strpos($col, 'decimal') !== false) {
return 'float';
return 'decimal';
}
return 'text';
}
@ -393,7 +395,7 @@ class Sqlite extends DboSource {
*/
public function buildColumn($column) {
$name = $type = null;
$column = array_merge(array('null' => true), $column);
$column += array('null' => true);
extract($column);
if (empty($name) || empty($type)) {

View file

@ -78,6 +78,7 @@ class Sqlserver extends DboSource {
'password' => '',
'database' => 'cake',
'schema' => '',
'flags' => array()
);
/**
@ -91,7 +92,10 @@ class Sqlserver extends DboSource {
'text' => array('name' => 'nvarchar', 'limit' => 'MAX'),
'integer' => array('name' => 'int', 'formatter' => 'intval'),
'biginteger' => array('name' => 'bigint'),
'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
'numeric' => array('name' => 'decimal', 'formatter' => 'floatval'),
'decimal' => array('name' => 'decimal', 'formatter' => 'floatval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'real' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
@ -118,7 +122,7 @@ class Sqlserver extends DboSource {
$config = $this->config;
$this->connected = false;
$flags = array(
$flags = $config['flags'] + array(
PDO::ATTR_PERSISTENT => $config['persistent'],
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
@ -204,7 +208,7 @@ class Sqlserver extends DboSource {
}
$fields = array();
$schema = $model->schemaName;
$schema = is_object($model) ? $model->schemaName : false;
$cols = $this->_execute(
"SELECT
@ -446,9 +450,12 @@ class Sqlserver extends DboSource {
if (strpos($col, 'binary') !== false || $col === 'image') {
return 'binary';
}
if (in_array($col, array('float', 'real', 'decimal', 'numeric'))) {
if (in_array($col, array('float', 'real'))) {
return 'float';
}
if (in_array($col, array('decimal', 'numeric'))) {
return 'decimal';
}
return 'text';
}

File diff suppressed because it is too large Load diff

View file

@ -952,9 +952,11 @@ class Model extends Object implements CakeEventListener {
* Example: Turn off the associated Model Support request,
* to temporarily lighten the User model:
*
* `$this->User->unbindModel(array('hasMany' => array('Supportrequest')));`
* `$this->User->unbindModel(array('hasMany' => array('SupportRequest')));`
* Or alternatively:
* `$this->User->unbindModel(array('hasMany' => 'SupportRequest'));`
*
* unbound models that are not made permanent will reset with the next call to Model::find()
* Unbound models that are not made permanent will reset with the next call to Model::find()
*
* @param array $params Set of bindings to unbind (indexed by binding type)
* @param boolean $reset Set to false to make the unbinding permanent
@ -966,7 +968,7 @@ class Model extends Object implements CakeEventListener {
if ($reset === true && !isset($this->__backAssociation[$assoc])) {
$this->__backAssociation[$assoc] = $this->{$assoc};
}
$models = Hash::normalize((array)$models, false);
foreach ($models as $model) {
if ($reset === false && isset($this->__backAssociation[$assoc][$model])) {
unset($this->__backAssociation[$assoc][$model]);
@ -1661,7 +1663,7 @@ class Model extends Object implements CakeEventListener {
$options = array('validate' => $validate, 'fieldList' => array($name));
if (is_array($validate)) {
$options = array_merge(array('validate' => false, 'fieldList' => array($name)), $validate);
$options = $validate + array('validate' => false, 'fieldList' => array($name));
}
return $this->save(array($this->alias => array($this->primaryKey => $id, $name => $value)), $options);
@ -1695,9 +1697,9 @@ class Model extends Object implements CakeEventListener {
$fields = array();
if (!is_array($validate)) {
$options = array_merge($defaults, compact('validate', 'fieldList'));
$options = compact('validate', 'fieldList') + $defaults;
} else {
$options = array_merge($defaults, $validate);
$options = $validate + $defaults;
}
if (!empty($options['fieldList'])) {
@ -2162,7 +2164,7 @@ class Model extends Object implements CakeEventListener {
* @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveall-array-data-null-array-options-array
*/
public function saveAll($data = array(), $options = array()) {
$options = array_merge(array('validate' => 'first'), $options);
$options += array('validate' => 'first');
if (Hash::numeric(array_keys($data))) {
if ($options['validate'] === 'only') {
return $this->validateMany($data, $options);
@ -2204,7 +2206,7 @@ class Model extends Object implements CakeEventListener {
$data = $this->data;
}
$options = array_merge(array('validate' => 'first', 'atomic' => true, 'deep' => false), $options);
$options += array('validate' => 'first', 'atomic' => true, 'deep' => false);
$this->validationErrors = $validationErrors = array();
if (empty($data) && $options['validate'] !== false) {
@ -2326,7 +2328,7 @@ class Model extends Object implements CakeEventListener {
$data = $this->data;
}
$options = array_merge(array('validate' => 'first', 'atomic' => true, 'deep' => false), $options);
$options += array('validate' => 'first', 'atomic' => true, 'deep' => false);
$this->validationErrors = $validationErrors = array();
if (empty($data) && $options['validate'] !== false) {
@ -2367,9 +2369,9 @@ class Model extends Object implements CakeEventListener {
$saved = false;
if ($validates) {
if ($options['deep']) {
$saved = $Model->saveAssociated($values, array_merge($options, array('atomic' => false)));
$saved = $Model->saveAssociated($values, array('atomic' => false) + $options);
} else {
$saved = $Model->save($values, array_merge($options, array('atomic' => false)));
$saved = $Model->save($values, array('atomic' => false) + $options);
}
$validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
}
@ -2423,7 +2425,7 @@ class Model extends Object implements CakeEventListener {
if ($validates) {
$options = $Model->_addToWhiteList($key, $options);
if ($options['deep']) {
$saved = $Model->saveAssociated($values, array_merge($options, array('atomic' => false)));
$saved = $Model->saveAssociated($values, array('atomic' => false) + $options);
} else {
$saved = $Model->save($values, $options);
}
@ -2446,7 +2448,7 @@ class Model extends Object implements CakeEventListener {
}
$options = $Model->_addToWhiteList($key, $options);
$_return = $Model->saveMany($values, array_merge($options, array('atomic' => false)));
$_return = $Model->saveMany($values, array('atomic' => false) + $options);
if (in_array(false, $_return, true)) {
$validationErrors[$association] = $Model->validationErrors;
$validates = false;

View file

@ -127,7 +127,7 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable {
*/
public function validateAssociated(&$data, $options = array()) {
$model = $this->getModel();
$options = array_merge(array('atomic' => true, 'deep' => false), $options);
$options += array('atomic' => true, 'deep' => false);
$model->validationErrors = $validationErrors = $return = array();
$model->create(null);
$return[$model->alias] = true;
@ -204,7 +204,7 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable {
*/
public function validateMany(&$data, $options = array()) {
$model = $this->getModel();
$options = array_merge(array('atomic' => true, 'deep' => false), $options);
$options += array('atomic' => true, 'deep' => false);
$model->validationErrors = $validationErrors = $return = array();
foreach ($data as $key => &$record) {
if ($options['deep']) {
@ -247,7 +247,15 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable {
return $model->validationErrors;
}
$fieldList = isset($options['fieldList']) ? $options['fieldList'] : array();
$fieldList = $model->whitelist;
if (empty($fieldList) && !empty($options['fieldList'])) {
if (!empty($options['fieldList'][$model->alias]) && is_array($options['fieldList'][$model->alias])) {
$fieldList = $options['fieldList'][$model->alias];
} else {
$fieldList = $options['fieldList'];
}
}
$exists = $model->exists();
$methods = $this->getMethods();
$fields = $this->_validationList($fieldList);
@ -374,32 +382,19 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable {
}
/**
* Processes the Model's whitelist or passed fieldList and returns the list of fields
* to be validated
* Processes the passed fieldList and returns the list of fields to be validated
*
* @param array $fieldList list of fields to be used for validation
* @return array List of validation rules to be applied
*/
protected function _validationList($fieldList = array()) {
$model = $this->getModel();
$whitelist = $model->whitelist;
if (!empty($fieldList)) {
if (!empty($fieldList[$model->alias]) && is_array($fieldList[$model->alias])) {
$whitelist = $fieldList[$model->alias];
} else {
$whitelist = $fieldList;
}
}
unset($fieldList);
if (empty($whitelist) || Hash::dimensions($whitelist) > 1) {
if (empty($fieldList) || Hash::dimensions($fieldList) > 1) {
return $this->_fields;
}
$validateList = array();
$this->validationErrors = array();
foreach ((array)$whitelist as $f) {
foreach ((array)$fieldList as $f) {
if (!empty($this->_fields[$f])) {
$validateList[$f] = $this->_fields[$f];
}

View file

@ -83,7 +83,7 @@ class Permission extends AppModel {
$acoPath = $this->Aco->node($aco);
if (!$aroPath) {
trigger_error(__d('cake_dev',
$this->log(__d('cake_dev',
"%s - Failed ARO node lookup in permissions check. Node references:\nAro: %s\nAco: %s",
'DbAcl::check()',
print_r($aro, true),
@ -94,7 +94,7 @@ class Permission extends AppModel {
}
if (!$acoPath) {
trigger_error(__d('cake_dev',
$this->log(__d('cake_dev',
"%s - Failed ACO node lookup in permissions check. Node references:\nAro: %s\nAco: %s",
'DbAcl::check()',
print_r($aro, true),
@ -105,7 +105,7 @@ class Permission extends AppModel {
}
if ($action !== '*' && !in_array('_' . $action, $permKeys)) {
trigger_error(__d('cake_dev', "ACO permissions key %s does not exist in %s", $action, 'DbAcl::check()'), E_USER_NOTICE);
$this->log(__d('cake_dev', "ACO permissions key %s does not exist in %s", $action, 'DbAcl::check()'), E_USER_NOTICE);
return false;
}
@ -176,7 +176,7 @@ class Permission extends AppModel {
$save = array();
if (!$perms) {
trigger_error(__d('cake_dev', '%s - Invalid node', 'DbAcl::allow()'), E_USER_WARNING);
$this->log(__d('cake_dev', '%s - Invalid node', 'DbAcl::allow()'), E_USER_WARNING);
return false;
}
if (isset($perms[0])) {

View file

@ -325,7 +325,12 @@ class CakeValidationSet implements ArrayAccess, IteratorAggregate, Countable {
}
/**
* Sets or replace a validation rule
* Sets or replace a validation rule.
*
* This is a wrapper for ArrayAccess. Use setRule() directly for
* chainable access.
*
* @see http://www.php.net/manual/en/arrayobject.offsetset.php
*
* @param string $index name of the rule
* @param CakeValidationRule|array rule to add to $index

View file

@ -512,8 +512,13 @@ class CakeRequest implements ArrayAccess {
}
if (isset($detect['param'])) {
$key = $detect['param'];
$value = $detect['value'];
return isset($this->params[$key]) ? $this->params[$key] == $value : false;
if (isset($detect['value'])) {
$value = $detect['value'];
return isset($this->params[$key]) ? $this->params[$key] == $value : false;
}
if (isset($detect['options'])) {
return isset($this->params[$key]) ? in_array($this->params[$key], $detect['options']) : false;
}
}
if (isset($detect['callback']) && is_callable($detect['callback'])) {
return call_user_func($detect['callback'], $this);
@ -572,7 +577,13 @@ class CakeRequest implements ArrayAccess {
*
* Allows for custom detectors on the request parameters.
*
* e.g `addDetector('post', array('param' => 'requested', 'value' => 1)`
* e.g `addDetector('requested', array('param' => 'requested', 'value' => 1)`
*
* You can also make parameter detectors that accept multiple values
* using the `options` key. This is useful when you want to check
* if a request parameter is in a list of options.
*
* `addDetector('extension', array('param' => 'ext', 'options' => array('pdf', 'csv'))`
*
* @param string $name The name of the detector.
* @param array $options The options for the detector definition. See above.
@ -900,23 +911,23 @@ class CakeRequest implements ArrayAccess {
}
/**
* Only allow certain HTTP request methods, if the request method does not match
* Allow only certain HTTP request methods. If the request method does not match
* a 405 error will be shown and the required "Allow" response header will be set.
*
* Example:
*
* $this->request->onlyAllow('post', 'delete');
* $this->request->allowMethod('post', 'delete');
* or
* $this->request->onlyAllow(array('post', 'delete'));
* $this->request->allowMethod(array('post', 'delete'));
*
* If the request would be GET, response header "Allow: POST, DELETE" will be set
* and a 405 error will be returned
* and a 405 error will be returned.
*
* @param string|array $methods Allowed HTTP request methods
* @param string|array $methods Allowed HTTP request methods.
* @return boolean true
* @throws MethodNotAllowedException
*/
public function onlyAllow($methods) {
public function allowMethod($methods) {
if (!is_array($methods)) {
$methods = func_get_args();
}
@ -931,6 +942,22 @@ class CakeRequest implements ArrayAccess {
throw $e;
}
/**
* Alias of CakeRequest::allowMethod() for backwards compatibility.
*
* @see CakeRequest::allowMethod()
* @deprecated 2.5 Use CakeRequest::allowMethod() instead.
* @param string|array $methods Allowed HTTP request methods.
* @return boolean true
* @throws MethodNotAllowedException
*/
public function onlyAllow($methods) {
if (!is_array($methods)) {
$methods = func_get_args();
}
return $this->allowMethod($methods);
}
/**
* Read data from php://input, mocked in tests.
*

View file

@ -379,6 +379,7 @@ class CakeResponse {
*
* @param array $options list of parameters to setup the response. Possible values are:
* - body: the response text that should be sent to the client
* - statusCodes: additional allowable response codes
* - status: the HTTP status code to respond with
* - type: a complete mime-type string or an extension mapped in this class
* - charset: the charset for the response body
@ -387,6 +388,9 @@ class CakeResponse {
if (isset($options['body'])) {
$this->body($options['body']);
}
if (isset($options['statusCodes'])) {
$this->httpCodes($options['statusCodes']);
}
if (isset($options['status'])) {
$this->statusCode($options['status']);
}
@ -1236,6 +1240,75 @@ class CakeResponse {
$this->_cookies[$options['name']] = $options;
}
/**
* Setup access for origin and methods on cross origin requests
*
* This method allow multiple ways to setup the domains, see the examples
*
* ### Full URI
* e.g `cors($request, 'http://www.cakephp.org');`
*
* ### URI with wildcard
* e.g `cors($request, 'http://*.cakephp.org');`
*
* ### Ignoring the requested protocol
* e.g `cors($request, 'www.cakephp.org');`
*
* ### Any URI
* e.g `cors($request, '*');`
*
* ### Whitelist of URIs
* e.g `cors($request, array('http://www.cakephp.org', '*.google.com', 'https://myproject.github.io'));`
*
* @param CakeRequest $request Request object
* @param string|array $allowedDomains List of allowed domains, see method description for more details
* @param string|array $allowedMethods List of HTTP verbs allowed
* @param string|array $allowedHeaders List of HTTP headers allowed
* @return void
*/
public function cors(CakeRequest $request, $allowedDomains, $allowedMethods = array(), $allowedHeaders = array()) {
$origin = $request->header('Origin');
if (!$origin) {
return;
}
$allowedDomains = $this->_normalizeCorsDomains((array)$allowedDomains, $request->is('ssl'));
foreach ($allowedDomains as $domain) {
if (!preg_match($domain['preg'], $origin)) {
continue;
}
$this->header('Access-Control-Allow-Origin', $domain['original'] === '*' ? '*' : $origin);
$allowedMethods && $this->header('Access-Control-Allow-Methods', implode(', ', (array)$allowedMethods));
$allowedHeaders && $this->header('Access-Control-Allow-Headers', implode(', ', (array)$allowedHeaders));
break;
}
}
/**
* Normalize the origin to regular expressions and put in an array format
*
* @param array $domains
* @param boolean $requestIsSSL
* @return array
*/
protected function _normalizeCorsDomains($domains, $requestIsSSL = false) {
$result = array();
foreach ($domains as $domain) {
if ($domain === '*') {
$result[] = array('preg' => '@.@', 'original' => '*');
continue;
}
$original = $preg = $domain;
if (strpos($domain, '://') === false) {
$preg = ($requestIsSSL ? 'https://' : 'http://') . $domain;
}
$preg = '@' . str_replace('*', '.*', $domain) . '@';
$result[] = compact('original', 'preg');
}
return $result;
}
/**
* Setup for display or download the given file.
*

View file

@ -14,7 +14,6 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Validation', 'Utility');
App::uses('Multibyte', 'I18n');
App::uses('AbstractTransport', 'Network/Email');
App::uses('File', 'Utility');
@ -315,7 +314,7 @@ class CakeEmail {
/**
* Regex for email validation
* If null, it will use built in regex
* If null, filter_var() will be used.
*
* @var string
*/
@ -552,13 +551,10 @@ class CakeEmail {
* @param string|array $email
* @param string $name
* @return CakeEmail $this
* @throws SocketException
*/
protected function _setEmail($varName, $email, $name) {
if (!is_array($email)) {
if (!Validation::email($email, false, $this->_emailPattern)) {
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
}
$this->_validateEmail($email);
if ($name === null) {
$name = $email;
}
@ -570,15 +566,30 @@ class CakeEmail {
if (is_int($key)) {
$key = $value;
}
if (!Validation::email($key, false, $this->_emailPattern)) {
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $key));
}
$this->_validateEmail($key);
$list[$key] = $value;
}
$this->{$varName} = $list;
return $this;
}
/**
* Validate email address
*
* @param string $email
* @return void
* @throws SocketException If email address does not validate
*/
protected function _validateEmail($email) {
$valid = (($this->_emailPattern !== null &&
preg_match($this->_emailPattern, $email)) ||
filter_var($email, FILTER_VALIDATE_EMAIL)
);
if (!$valid) {
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
}
}
/**
* Set only 1 email
*
@ -610,9 +621,7 @@ class CakeEmail {
*/
protected function _addEmail($varName, $email, $name) {
if (!is_array($email)) {
if (!Validation::email($email, false, $this->_emailPattern)) {
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
}
$this->_validateEmail($email);
if ($name === null) {
$name = $email;
}
@ -624,9 +633,7 @@ class CakeEmail {
if (is_int($key)) {
$key = $value;
}
if (!Validation::email($key, false, $this->_emailPattern)) {
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $key));
}
$this->_validateEmail($key);
$list[$key] = $value;
}
$this->{$varName} = array_merge($this->{$varName}, $list);
@ -1128,7 +1135,7 @@ class CakeEmail {
if (!is_array($this->_config['log'])) {
$this->_config['log'] = array('level' => $this->_config['log']);
}
$config = array_merge($config, $this->_config['log']);
$config = $this->_config['log'] + $config;
}
CakeLog::write(
$config['level'],
@ -1192,7 +1199,7 @@ class CakeEmail {
}
$config = $configs->{$config};
}
$this->_config = array_merge($this->_config, $config);
$this->_config = $config + $this->_config;
if (!empty($config['charset'])) {
$this->charset = $config['charset'];
}
@ -1217,15 +1224,14 @@ class CakeEmail {
$this->setHeaders($config['headers']);
unset($config['headers']);
}
if (array_key_exists('template', $config)) {
$layout = false;
if (array_key_exists('layout', $config)) {
$layout = $config['layout'];
unset($config['layout']);
}
$this->template($config['template'], $layout);
unset($config['template']);
$this->_template = $config['template'];
}
if (array_key_exists('layout', $config)) {
$this->_layout = $config['layout'];
}
$this->transportClass()->config($config);
}

View file

@ -46,6 +46,42 @@ class SmtpTransport extends AbstractTransport {
*/
protected $_content;
/**
* The response of the last sent SMTP command.
*
* @var array
*/
protected $_lastResponse = array();
/**
* Returns the response of the last sent SMTP command.
*
* A response consists of one or more lines containing a response
* code and an optional response message text:
* {{{
* array(
* array(
* 'code' => '250',
* 'message' => 'mail.example.com'
* ),
* array(
* 'code' => '250',
* 'message' => 'PIPELINING'
* ),
* array(
* 'code' => '250',
* 'message' => '8BITMIME'
* ),
* // etc...
* )
* }}}
*
* @return array
*/
public function getLastResponse() {
return $this->_lastResponse;
}
/**
* Send mail
*
@ -88,6 +124,25 @@ class SmtpTransport extends AbstractTransport {
return $this->_config;
}
/**
* Parses and stores the reponse lines in `'code' => 'message'` format.
*
* @param array $responseLines
* @return void
*/
protected function _bufferResponseLines(array $responseLines) {
$response = array();
foreach ($responseLines as $responseLine) {
if (preg_match('/^(\d{3})(?:[ -]+(.*))?$/', $responseLine, $match)) {
$response[] = array(
'code' => $match[1],
'message' => isset($match[2]) ? $match[2] : null
);
}
}
$this->_lastResponse = array_merge($this->_lastResponse, $response);
}
/**
* Connect to SMTP Server
*
@ -152,6 +207,78 @@ class SmtpTransport extends AbstractTransport {
}
}
/**
* Prepares the `MAIL FROM` SMTP command.
*
* @param string $email The email address to send with the command.
* @return string
*/
protected function _prepareFromCmd($email) {
return 'MAIL FROM:<' . $email . '>';
}
/**
* Prepares the `RCPT TO` SMTP command.
*
* @param string $email The email address to send with the command.
* @return string
*/
protected function _prepareRcptCmd($email) {
return 'RCPT TO:<' . $email . '>';
}
/**
* Prepares the `from` email address.
*
* @return array
*/
protected function _prepareFromAddress() {
$from = $this->_cakeEmail->returnPath();
if (empty($from)) {
$from = $this->_cakeEmail->from();
}
return $from;
}
/**
* Prepares the recipient email addresses.
*
* @return array
*/
protected function _prepareRecipientAddresses() {
$to = $this->_cakeEmail->to();
$cc = $this->_cakeEmail->cc();
$bcc = $this->_cakeEmail->bcc();
return array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
}
/**
* Prepares the message headers.
*
* @return array
*/
protected function _prepareMessageHeaders() {
return $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
}
/**
* Prepares the message body.
*
* @return string
*/
protected function _prepareMessage() {
$lines = $this->_cakeEmail->message();
$messages = array();
foreach ($lines as $line) {
if ((!empty($line)) && ($line[0] === '.')) {
$messages[] = '.' . $line;
} else {
$messages[] = $line;
}
}
return implode("\r\n", $messages);
}
/**
* Send emails
*
@ -159,18 +286,12 @@ class SmtpTransport extends AbstractTransport {
* @throws SocketException
*/
protected function _sendRcpt() {
$from = $this->_cakeEmail->returnPath();
if (empty($from)) {
$from = $this->_cakeEmail->from();
}
$this->_smtpSend('MAIL FROM:<' . key($from) . '>');
$from = $this->_prepareFromAddress();
$this->_smtpSend($this->_prepareFromCmd(key($from)));
$to = $this->_cakeEmail->to();
$cc = $this->_cakeEmail->cc();
$bcc = $this->_cakeEmail->bcc();
$emails = array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
$emails = $this->_prepareRecipientAddresses();
foreach ($emails as $email) {
$this->_smtpSend('RCPT TO:<' . $email . '>');
$this->_smtpSend($this->_prepareRcptCmd($email));
}
}
@ -183,18 +304,9 @@ class SmtpTransport extends AbstractTransport {
protected function _sendData() {
$this->_smtpSend('DATA', '354');
$headers = $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
$headers = $this->_headersToString($headers);
$lines = $this->_cakeEmail->message();
$messages = array();
foreach ($lines as $line) {
if ((!empty($line)) && ($line[0] === '.')) {
$messages[] = '.' . $line;
} else {
$messages[] = $line;
}
}
$message = implode("\r\n", $messages);
$headers = $this->_headersToString($this->_prepareMessageHeaders());
$message = $this->_prepareMessage();
$this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
$this->_content = array('headers' => $headers, 'message' => $message);
}
@ -229,6 +341,8 @@ class SmtpTransport extends AbstractTransport {
* @throws SocketException
*/
protected function _smtpSend($data, $checkCode = '250') {
$this->_lastResponse = array();
if ($data !== null) {
$this->_socket->write($data . "\r\n");
}
@ -244,6 +358,8 @@ class SmtpTransport extends AbstractTransport {
$responseLines = explode("\r\n", rtrim($response, "\r\n"));
$response = end($responseLines);
$this->_bufferResponseLines($responseLines);
if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
if ($code[2] === '-') {
continue;

View file

@ -893,7 +893,7 @@ class HttpSocket extends CakeSocket {
}
$request['uri'] = $this->_parseUri($request['uri']);
$request = array_merge(array('method' => 'GET'), $request);
$request += array('method' => 'GET');
if (!empty($this->_proxy['host'])) {
$request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query');
} else {

View file

@ -95,7 +95,12 @@ class Dispatcher implements CakeEventListener {
return;
}
foreach ($filters as $filter) {
foreach ($filters as $index => $filter) {
$settings = array();
if (is_array($filter) && !is_int($index)) {
$settings = $filter;
$filter = $index;
}
if (is_string($filter)) {
$filter = array('callable' => $filter);
}
@ -105,7 +110,7 @@ class Dispatcher implements CakeEventListener {
if (!class_exists($callable)) {
throw new MissingDispatcherFilterException($callable);
}
$manager->attach(new $callable);
$manager->attach(new $callable($settings));
} else {
$on = strtolower($filter['on']);
$options = array();
@ -157,7 +162,7 @@ class Dispatcher implements CakeEventListener {
));
}
$response = $this->_invoke($controller, $request, $response);
$response = $this->_invoke($controller, $request);
if (isset($request->params['return'])) {
return $response->body();
}
@ -169,18 +174,19 @@ class Dispatcher implements CakeEventListener {
/**
* Initializes the components and models a controller will be using.
* Triggers the controller action, and invokes the rendering if Controller::$autoRender is true and echo's the output.
* Otherwise the return value of the controller action are returned.
* Triggers the controller action, and invokes the rendering if Controller::$autoRender
* is true and echo's the output. Otherwise the return value of the controller
* action are returned.
*
* @param Controller $controller Controller to invoke
* @param CakeRequest $request The request object to invoke the controller for.
* @param CakeResponse $response The response object to receive the output
* @return CakeResponse the resulting response object
*/
protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) {
protected function _invoke(Controller $controller, CakeRequest $request) {
$controller->constructClasses();
$controller->startupProcess();
$response = $controller->response;
$render = true;
$result = $controller->invokeAction($request);
if ($result instanceof CakeResponse) {

View file

@ -34,6 +34,22 @@ abstract class DispatcherFilter implements CakeEventListener {
*/
public $priority = 10;
/**
* Settings for this filter
*
* @var array
*/
public $settings = array();
/**
* Constructor.
*
* @param string $setting Configuration settings for the filter.
*/
public function __construct($settings = array()) {
$this->settings = Hash::merge($this->settings, $settings);
}
/**
* Returns the list of events this filter listens to.
* Dispatcher notifies 2 different events `Dispatcher.before` and `Dispatcher.after`.

View file

@ -1,7 +1,5 @@
<?php
/**
*
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
@ -38,7 +36,8 @@ class AssetDispatcher extends DispatcherFilter {
* Checks if a requested asset exists and sends it to the browser
*
* @param CakeEvent $event containing the request and response object
* @return CakeResponse if the client is requesting a recognized asset, null otherwise
* @return mixed The resulting response.
* @throws NotFoundException When asset not found
*/
public function beforeDispatch(CakeEvent $event) {
$url = urldecode($event->data['request']->url);
@ -55,7 +54,6 @@ class AssetDispatcher extends DispatcherFilter {
if ($assetFile === null || !file_exists($assetFile)) {
return null;
}
$response = $event->data['response'];
$event->stopPropagation();
@ -66,6 +64,7 @@ class AssetDispatcher extends DispatcherFilter {
$pathSegments = explode('.', $url);
$ext = array_pop($pathSegments);
$this->_deliverAsset($response, $assetFile, $ext);
return $response;
}

View file

@ -480,10 +480,10 @@ class Router {
}
if ($named === true || $named === false) {
$options = array_merge(array('default' => $named, 'reset' => true, 'greedy' => $named), $options);
$options += array('default' => $named, 'reset' => true, 'greedy' => $named);
$named = array();
} else {
$options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options);
$options += array('default' => false, 'reset' => false, 'greedy' => true);
}
if ($options['reset'] || self::$_namedConfig['rules'] === false) {
@ -532,12 +532,15 @@ class Router {
*/
public static function mapResources($controller, $options = array()) {
$hasPrefix = isset($options['prefix']);
$options = array_merge(array(
$options += array(
'connectOptions' => array(),
'prefix' => '/',
'id' => self::ID . '|' . self::UUID
), $options);
);
$prefix = $options['prefix'];
$connectOptions = $options['connectOptions'];
unset($options['connectOptions']);
if (strpos($prefix, '/') !== 0) {
$prefix = '/' . $prefix;
}
@ -563,7 +566,10 @@ class Router {
'action' => $params['action'],
'[method]' => $params['method']
),
array('id' => $options['id'], 'pass' => array('id'))
array_merge(
array('id' => $options['id'], 'pass' => array('id')),
$connectOptions
)
);
}
self::$_resourceMapped[] = $urlName;
@ -1074,7 +1080,7 @@ class Router {
}
$addition = http_build_query($q, null, $join);
if ($out && $addition && substr($out, strlen($join) * -1, strlen($join)) != $join) {
if ($out && $addition && substr($out, strlen($join) * -1, strlen($join)) !== $join) {
$out .= $join;
}

View file

@ -397,6 +397,181 @@ class BasicsTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
/**
* testTranslatePercent
*
* @return void
*/
public function testTranslatePercent() {
$result = __('%s are 100% real fruit', 'Apples');
$expected = 'Apples are 100% real fruit';
$this->assertEquals($expected, $result, 'Percent sign at end of word should be considered literal');
$result = __('%s are %d% real fruit', 'Apples', 100);
$expected = 'Apples are 100% real fruit';
$this->assertEquals($expected, $result, 'A digit marker should not be misinterpreted');
$result = __('%s are %s% real fruit', 'Apples', 100);
$expected = 'Apples are 100% real fruit';
$this->assertEquals($expected, $result, 'A string marker should not be misinterpreted');
$result = __('%nonsense %s', 'Apples');
$expected = '%nonsense Apples';
$this->assertEquals($expected, $result, 'A percent sign at the start of the string should be considered literal');
$result = __('%s are awesome%', 'Apples');
$expected = 'Apples are awesome%';
$this->assertEquals($expected, $result, 'A percent sign at the end of the string should be considered literal');
$result = __('%2$d %1$s entered the bowl', 'Apples', 2);
$expected = '2 Apples entered the bowl';
$this->assertEquals($expected, $result, 'Positional replacement markers should not be misinterpreted');
$result = __('%.2f% of all %s agree', 99.44444, 'Cats');
$expected = '99.44% of all Cats agree';
$this->assertEquals($expected, $result, 'significant-digit placeholder should not be misinterpreted');
}
/**
* testTranslateWithFormatSpecifiers
*
* @return void
*/
public function testTranslateWithFormatSpecifiers() {
$expected = 'Check, one, two, three';
$result = __('Check, %+10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, +1, two, three';
$result = __('Check, %+5d, two, three', 1);
$this->assertEquals($expected, $result);
$expected = 'Check, @@one, two, three';
$result = __('Check, %\'@+10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, one, two , three';
$result = __('Check, %-10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, one, two##, three';
$result = __('Check, %\'#-10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, one, two, three';
$result = __d('default', 'Check, %+10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, @@one, two, three';
$result = __d('default', 'Check, %\'@+10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, one, two , three';
$result = __d('default', 'Check, %-10s, three', 'one, two');
$this->assertEquals($expected, $result);
$expected = 'Check, one, two##, three';
$result = __d('default', 'Check, %\'#-10s, three', 'one, two');
$this->assertEquals($expected, $result);
}
/**
* testTranslateDomainPluralWithFormatSpecifiers
*
* @return void
*/
public function testTranslateDomainPluralWithFormatSpecifiers() {
$result = __dn('core', '%+5d item.', '%+5d items.', 1, 1);
$expected = ' +1 item.';
$this->assertEquals($expected, $result);
$result = __dn('core', '%-5d item.', '%-5d items.', 10, 10);
$expected = '10 items.';
$this->assertEquals($expected, $result);
$result = __dn('core', '%\'#+5d item.', '%\'*+5d items.', 1, 1);
$expected = '###+1 item.';
$this->assertEquals($expected, $result);
$result = __dn('core', '%\'#+5d item.', '%\'*+5d items.', 90, 90);
$expected = '**+90 items.';
$this->assertEquals($expected, $result);
$result = __dn('core', '%\'#+5d item.', '%\'*+5d items.', 9000, 9000);
$expected = '+9000 items.';
$this->assertEquals($expected, $result);
}
/**
* test testTranslatePluralWithFormatSpecifiers
*
* @return void
*/
public function testTranslatePluralWithFormatSpecifiers() {
Configure::write('Config.language', 'rule_1_po');
$result = __n('%-5d = 1', '%-5d = 0 or > 1', 10);
$expected = '%-5d = 0 or > 1 (translated)';
$this->assertEquals($expected, $result);
}
/**
* test testTranslateDomainCategoryWithFormatSpecifiers
*
* @return void
*/
public function testTranslateDomainCategoryWithFormatSpecifiers() {
Configure::write('Config.language', 'rule_1_po');
$result = __dc('default', '%+10s world', 6, 'hello');
$expected = ' hello world';
$this->assertEquals($expected, $result);
$result = __dc('default', '%-10s world', 6, 'hello');
$expected = 'hello world';
$this->assertEquals($expected, $result);
$result = __dc('default', '%\'@-10s world', 6, 'hello');
$expected = 'hello@@@@@ world';
$this->assertEquals($expected, $result);
}
/**
* test testTranslateDomainCategoryPluralWithFormatSpecifiers
*
* @return void
*/
public function testTranslateDomainCategoryPluralWithFormatSpecifiers() {
Configure::write('Config.language', 'rule_1_po');
$result = __dcn('default', '%-5d = 1', '%-5d = 0 or > 1', 0, 6);
$expected = '%-5d = 0 or > 1 (translated)';
$this->assertEquals($expected, $result);
$result = __dcn('default', '%-5d = 1', '%-5d = 0 or > 1', 1, 6);
$expected = '%-5d = 1 (translated)';
$this->assertEquals($expected, $result);
}
/**
* test testTranslateCategoryWithFormatSpecifiers
*
* @return void
*/
public function testTranslateCategoryWithFormatSpecifiers() {
$result = __c('Some string with %+10s', 6, 'arguments');
$expected = 'Some string with arguments';
$this->assertEquals($expected, $result);
$result = __c('Some string with %-10s: args', 6, 'arguments');
$expected = 'Some string with arguments : args';
$this->assertEquals($expected, $result);
$result = __c('Some string with %\'*-10s: args', 6, 'arguments');
$expected = 'Some string with arguments*: args';
$this->assertEquals($expected, $result);
}
/**
* test __n()
*

View file

@ -25,6 +25,8 @@ App::uses('Cache', 'Cache');
*/
class CacheTest extends CakeTestCase {
protected $_count = 0;
/**
* setUp method
*
@ -493,4 +495,28 @@ class CacheTest extends CakeTestCase {
$this->assertEquals('test_file_', $settings['prefix']);
$this->assertEquals(strtotime('+1 year') - time(), $settings['duration']);
}
/**
* test remember method.
*
* @return void
*/
public function testRemember() {
$expected = 'This is some data 0';
$result = Cache::remember('test_key', array($this, 'cacher'), 'default');
$this->assertEquals($expected, $result);
$this->_count = 1;
$result = Cache::remember('test_key', array($this, 'cacher'), 'default');
$this->assertEquals($expected, $result);
}
/**
* Method for testing Cache::remember()
*
* @return string
*/
public function cacher() {
return 'This is some data ' . $this->_count;
}
}

View file

@ -0,0 +1,776 @@
<?php
/**
* MemcachedEngineTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
* @package Cake.Test.Case.Cache.Engine
* @since CakePHP(tm) v 2.5.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Cache', 'Cache');
App::uses('MemcachedEngine', 'Cache/Engine');
/**
* Class TestMemcachedEngine
*
* @package Cake.Test.Case.Cache.Engine
*/
class TestMemcachedEngine extends MemcachedEngine {
/**
* public accessor to _parseServerString
*
* @param string $server
* @return array
*/
public function parseServerString($server) {
return $this->_parseServerString($server);
}
public function setMemcached($memcached) {
$this->_Memcached = $memcached;
}
public function getMemcached() {
return $this->_Memcached;
}
}
/**
* MemcachedEngineTest class
*
* @package Cake.Test.Case.Cache.Engine
*/
class MemcachedEngineTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->skipIf(!class_exists('Memcached'), 'Memcached is not installed or configured properly.');
Cache::config('memcached', array(
'engine' => 'Memcached',
'prefix' => 'cake_',
'duration' => 3600
));
}
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
parent::tearDown();
Cache::drop('memcached');
Cache::drop('memcached_groups');
Cache::drop('memcached_helper');
Cache::config('default');
}
/**
* testSettings method
*
* @return void
*/
public function testSettings() {
$settings = Cache::settings('memcached');
unset($settings['path']);
$expecting = array(
'prefix' => 'cake_',
'duration' => 3600,
'probability' => 100,
'servers' => array('127.0.0.1'),
'persistent' => false,
'compress' => false,
'engine' => 'Memcached',
'login' => null,
'password' => null,
'groups' => array(),
'serialize' => 'php'
);
$this->assertEquals($expecting, $settings);
}
/**
* testCompressionSetting method
*
* @return void
*/
public function testCompressionSetting() {
$Memcached = new TestMemcachedEngine();
$Memcached->init(array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'compress' => false
));
$this->assertFalse($Memcached->getMemcached()->getOption(Memcached::OPT_COMPRESSION));
$MemcachedCompressed = new TestMemcachedEngine();
$MemcachedCompressed->init(array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'compress' => true
));
$this->assertTrue($MemcachedCompressed->getMemcached()->getOption(Memcached::OPT_COMPRESSION));
}
/**
* test accepts only valid serializer engine
*
* @return void
*/
public function testInvalidSerializerSetting() {
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'invalid_serializer'
);
$this->setExpectedException(
'CacheException', 'invalid_serializer is not a valid serializer engine for Memcached'
);
$Memcached->init($settings);
}
/**
* testPhpSerializerSetting method
*
* @return void
*/
public function testPhpSerializerSetting() {
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'php'
);
$Memcached->init($settings);
$this->assertEquals(Memcached::SERIALIZER_PHP, $Memcached->getMemcached()->getOption(Memcached::OPT_SERIALIZER));
}
/**
* testJsonSerializerSetting method
*
* @return void
*/
public function testJsonSerializerSetting() {
$this->skipIf(
!Memcached::HAVE_JSON,
'Memcached extension is not compiled with json support'
);
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'json'
);
$Memcached->init($settings);
$this->assertEquals(Memcached::SERIALIZER_JSON, $Memcached->getMemcached()->getOption(Memcached::OPT_SERIALIZER));
}
/**
* testIgbinarySerializerSetting method
*
* @return void
*/
public function testIgbinarySerializerSetting() {
$this->skipIf(
!Memcached::HAVE_IGBINARY,
'Memcached extension is not compiled with igbinary support'
);
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'igbinary'
);
$Memcached->init($settings);
$this->assertEquals(Memcached::SERIALIZER_IGBINARY, $Memcached->getMemcached()->getOption(Memcached::OPT_SERIALIZER));
}
/**
* testMsgpackSerializerSetting method
*
* @return void
*/
public function testMsgpackSerializerSetting() {
$this->skipIf(
!defined('Memcached::HAVE_MSGPACK') || !Memcached::HAVE_MSGPACK,
'Memcached extension is not compiled with msgpack support'
);
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'msgpack'
);
$Memcached->init($settings);
$this->assertEquals(Memcached::SERIALIZER_MSGPACK, $Memcached->getMemcached()->getOption(Memcached::OPT_SERIALIZER));
}
/**
* testJsonSerializerThrowException method
*
* @return void
*/
public function testJsonSerializerThrowException() {
$this->skipIf(
Memcached::HAVE_JSON,
'Memcached extension is compiled with json support'
);
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'json'
);
$this->setExpectedException(
'CacheException', 'Memcached extension is not compiled with json support'
);
$Memcached->init($settings);
}
/**
* testMsgpackSerializerThrowException method
*
* @return void
*/
public function testMsgpackSerializerThrowException() {
$this->skipIf(
defined('Memcached::HAVE_MSGPACK') && Memcached::HAVE_MSGPACK,
'Memcached extension is compiled with msgpack support'
);
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'msgpack'
);
$this->setExpectedException(
'CacheException', 'msgpack is not a valid serializer engine for Memcached'
);
$Memcached->init($settings);
}
/**
* testIgbinarySerializerThrowException method
*
* @return void
*/
public function testIgbinarySerializerThrowException() {
$this->skipIf(
Memcached::HAVE_IGBINARY,
'Memcached extension is compiled with igbinary support'
);
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'serialize' => 'igbinary'
);
$this->setExpectedException(
'CacheException', 'Memcached extension is not compiled with igbinary support'
);
$Memcached->init($settings);
}
/**
* test using authentication without memcached installed with SASL support
* throw an exception
*
* @return void
*/
public function testSaslAuthException() {
$Memcached = new TestMemcachedEngine();
$settings = array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'persistent' => false,
'login' => 'test',
'password' => 'password'
);
$this->skipIf(
method_exists($Memcached->getMemcached(), 'setSaslAuthData'),
'Memcached extension is installed with SASL support'
);
$this->setExpectedException(
'CacheException', 'Memcached extension is not build with SASL support'
);
$Memcached->init($settings);
}
/**
* testSettings method
*
* @return void
*/
public function testMultipleServers() {
$servers = array('127.0.0.1:11211', '127.0.0.1:11222');
$available = true;
$Memcached = new Memcached();
foreach ($servers as $server) {
list($host, $port) = explode(':', $server);
//@codingStandardsIgnoreStart
if (!$Memcached->addServer($host, $port)) {
$available = false;
}
//@codingStandardsIgnoreEnd
}
$this->skipIf(!$available, 'Need memcached servers at ' . implode(', ', $servers) . ' to run this test.');
$Memcached = new MemcachedEngine();
$Memcached->init(array('engine' => 'Memcached', 'servers' => $servers));
$settings = $Memcached->settings();
$this->assertEquals($settings['servers'], $servers);
Cache::drop('dual_server');
}
/**
* test connecting to an ipv6 server.
*
* @return void
*/
public function testConnectIpv6() {
$Memcached = new MemcachedEngine();
$result = $Memcached->init(array(
'prefix' => 'cake_',
'duration' => 200,
'engine' => 'Memcached',
'servers' => array(
'[::1]:11211'
)
));
$this->assertTrue($result);
}
/**
* test non latin domains.
*
* @return void
*/
public function testParseServerStringNonLatin() {
$Memcached = new TestMemcachedEngine();
$result = $Memcached->parseServerString('schülervz.net:13211');
$this->assertEquals(array('schülervz.net', '13211'), $result);
$result = $Memcached->parseServerString('sülül:1111');
$this->assertEquals(array('sülül', '1111'), $result);
}
/**
* test unix sockets.
*
* @return void
*/
public function testParseServerStringUnix() {
$Memcached = new TestMemcachedEngine();
$result = $Memcached->parseServerString('unix:///path/to/memcachedd.sock');
$this->assertEquals(array('unix:///path/to/memcachedd.sock', 0), $result);
}
/**
* testReadAndWriteCache method
*
* @return void
*/
public function testReadAndWriteCache() {
Cache::set(array('duration' => 1), null, 'memcached');
$result = Cache::read('test', 'memcached');
$expecting = '';
$this->assertEquals($expecting, $result);
$data = 'this is a test of the emergency broadcasting system';
$result = Cache::write('test', $data, 'memcached');
$this->assertTrue($result);
$result = Cache::read('test', 'memcached');
$expecting = $data;
$this->assertEquals($expecting, $result);
Cache::delete('test', 'memcached');
}
/**
* testExpiry method
*
* @return void
*/
public function testExpiry() {
Cache::set(array('duration' => 1), 'memcached');
$result = Cache::read('test', 'memcached');
$this->assertFalse($result);
$data = 'this is a test of the emergency broadcasting system';
$result = Cache::write('other_test', $data, 'memcached');
$this->assertTrue($result);
sleep(2);
$result = Cache::read('other_test', 'memcached');
$this->assertFalse($result);
Cache::set(array('duration' => "+1 second"), 'memcached');
$data = 'this is a test of the emergency broadcasting system';
$result = Cache::write('other_test', $data, 'memcached');
$this->assertTrue($result);
sleep(3);
$result = Cache::read('other_test', 'memcached');
$this->assertFalse($result);
Cache::config('memcached', array('duration' => '+1 second'));
$result = Cache::read('other_test', 'memcached');
$this->assertFalse($result);
Cache::config('memcached', array('duration' => '+29 days'));
$data = 'this is a test of the emergency broadcasting system';
$result = Cache::write('long_expiry_test', $data, 'memcached');
$this->assertTrue($result);
sleep(2);
$result = Cache::read('long_expiry_test', 'memcached');
$expecting = $data;
$this->assertEquals($expecting, $result);
Cache::config('memcached', array('duration' => 3600));
}
/**
* testDeleteCache method
*
* @return void
*/
public function testDeleteCache() {
$data = 'this is a test of the emergency broadcasting system';
$result = Cache::write('delete_test', $data, 'memcached');
$this->assertTrue($result);
$result = Cache::delete('delete_test', 'memcached');
$this->assertTrue($result);
}
/**
* testDecrement method
*
* @return void
*/
public function testDecrement() {
$result = Cache::write('test_decrement', 5, 'memcached');
$this->assertTrue($result);
$result = Cache::decrement('test_decrement', 1, 'memcached');
$this->assertEquals(4, $result);
$result = Cache::read('test_decrement', 'memcached');
$this->assertEquals(4, $result);
$result = Cache::decrement('test_decrement', 2, 'memcached');
$this->assertEquals(2, $result);
$result = Cache::read('test_decrement', 'memcached');
$this->assertEquals(2, $result);
Cache::delete('test_decrement', 'memcached');
}
/**
* test decrementing compressed keys
*
* @return void
*/
public function testDecrementCompressedKeys() {
Cache::config('compressed_memcached', array(
'engine' => 'Memcached',
'duration' => '+2 seconds',
'servers' => array('127.0.0.1:11211'),
'compress' => true
));
$result = Cache::write('test_decrement', 5, 'compressed_memcached');
$this->assertTrue($result);
$result = Cache::decrement('test_decrement', 1, 'compressed_memcached');
$this->assertEquals(4, $result);
$result = Cache::read('test_decrement', 'compressed_memcached');
$this->assertEquals(4, $result);
$result = Cache::decrement('test_decrement', 2, 'compressed_memcached');
$this->assertEquals(2, $result);
$result = Cache::read('test_decrement', 'compressed_memcached');
$this->assertEquals(2, $result);
Cache::delete('test_decrement', 'compressed_memcached');
}
/**
* testIncrement method
*
* @return void
*/
public function testIncrement() {
$result = Cache::write('test_increment', 5, 'memcached');
$this->assertTrue($result);
$result = Cache::increment('test_increment', 1, 'memcached');
$this->assertEquals(6, $result);
$result = Cache::read('test_increment', 'memcached');
$this->assertEquals(6, $result);
$result = Cache::increment('test_increment', 2, 'memcached');
$this->assertEquals(8, $result);
$result = Cache::read('test_increment', 'memcached');
$this->assertEquals(8, $result);
Cache::delete('test_increment', 'memcached');
}
/**
* test incrementing compressed keys
*
* @return void
*/
public function testIncrementCompressedKeys() {
Cache::config('compressed_memcached', array(
'engine' => 'Memcached',
'duration' => '+2 seconds',
'servers' => array('127.0.0.1:11211'),
'compress' => true
));
$result = Cache::write('test_increment', 5, 'compressed_memcached');
$this->assertTrue($result);
$result = Cache::increment('test_increment', 1, 'compressed_memcached');
$this->assertEquals(6, $result);
$result = Cache::read('test_increment', 'compressed_memcached');
$this->assertEquals(6, $result);
$result = Cache::increment('test_increment', 2, 'compressed_memcached');
$this->assertEquals(8, $result);
$result = Cache::read('test_increment', 'compressed_memcached');
$this->assertEquals(8, $result);
Cache::delete('test_increment', 'compressed_memcached');
}
/**
* test that configurations don't conflict, when a file engine is declared after a memcached one.
*
* @return void
*/
public function testConfigurationConflict() {
Cache::config('long_memcached', array(
'engine' => 'Memcached',
'duration' => '+2 seconds',
'servers' => array('127.0.0.1:11211'),
));
Cache::config('short_memcached', array(
'engine' => 'Memcached',
'duration' => '+1 seconds',
'servers' => array('127.0.0.1:11211'),
));
Cache::config('some_file', array('engine' => 'File'));
$this->assertTrue(Cache::write('duration_test', 'yay', 'long_memcached'));
$this->assertTrue(Cache::write('short_duration_test', 'boo', 'short_memcached'));
$this->assertEquals('yay', Cache::read('duration_test', 'long_memcached'), 'Value was not read %s');
$this->assertEquals('boo', Cache::read('short_duration_test', 'short_memcached'), 'Value was not read %s');
sleep(1);
$this->assertEquals('yay', Cache::read('duration_test', 'long_memcached'), 'Value was not read %s');
sleep(2);
$this->assertFalse(Cache::read('short_duration_test', 'short_memcached'), 'Cache was not invalidated %s');
$this->assertFalse(Cache::read('duration_test', 'long_memcached'), 'Value did not expire %s');
Cache::delete('duration_test', 'long_memcached');
Cache::delete('short_duration_test', 'short_memcached');
}
/**
* test clearing memcached.
*
* @return void
*/
public function testClear() {
Cache::config('memcached2', array(
'engine' => 'Memcached',
'prefix' => 'cake2_',
'duration' => 3600
));
Cache::write('some_value', 'cache1', 'memcached');
$result = Cache::clear(true, 'memcached');
$this->assertTrue($result);
$this->assertEquals('cache1', Cache::read('some_value', 'memcached'));
Cache::write('some_value', 'cache2', 'memcached2');
$result = Cache::clear(false, 'memcached');
$this->assertTrue($result);
$this->assertFalse(Cache::read('some_value', 'memcached'));
$this->assertEquals('cache2', Cache::read('some_value', 'memcached2'));
Cache::clear(false, 'memcached2');
}
/**
* test that a 0 duration can successfully write.
*
* @return void
*/
public function testZeroDuration() {
Cache::config('memcached', array('duration' => 0));
$result = Cache::write('test_key', 'written!', 'memcached');
$this->assertTrue($result);
$result = Cache::read('test_key', 'memcached');
$this->assertEquals('written!', $result);
}
/**
* test that durations greater than 30 days never expire
*
* @return void
*/
public function testLongDurationEqualToZero() {
$memcached = new TestMemcachedEngine();
$memcached->settings['compress'] = false;
$mock = $this->getMock('Memcached');
$memcached->setMemcached($mock);
$mock->expects($this->once())
->method('set')
->with('key', 'value', 0);
$value = 'value';
$memcached->write('key', $value, 50 * DAY);
}
/**
* Tests that configuring groups for stored keys return the correct values when read/written
* Shows that altering the group value is equivalent to deleting all keys under the same
* group
*
* @return void
*/
public function testGroupReadWrite() {
Cache::config('memcached_groups', array(
'engine' => 'Memcached',
'duration' => 3600,
'groups' => array('group_a', 'group_b'),
'prefix' => 'test_'
));
Cache::config('memcached_helper', array(
'engine' => 'Memcached',
'duration' => 3600,
'prefix' => 'test_'
));
$this->assertTrue(Cache::write('test_groups', 'value', 'memcached_groups'));
$this->assertEquals('value', Cache::read('test_groups', 'memcached_groups'));
Cache::increment('group_a', 1, 'memcached_helper');
$this->assertFalse(Cache::read('test_groups', 'memcached_groups'));
$this->assertTrue(Cache::write('test_groups', 'value2', 'memcached_groups'));
$this->assertEquals('value2', Cache::read('test_groups', 'memcached_groups'));
Cache::increment('group_b', 1, 'memcached_helper');
$this->assertFalse(Cache::read('test_groups', 'memcached_groups'));
$this->assertTrue(Cache::write('test_groups', 'value3', 'memcached_groups'));
$this->assertEquals('value3', Cache::read('test_groups', 'memcached_groups'));
}
/**
* Tests that deleteing from a groups-enabled config is possible
*
* @return void
*/
public function testGroupDelete() {
Cache::config('memcached_groups', array(
'engine' => 'Memcached',
'duration' => 3600,
'groups' => array('group_a', 'group_b')
));
$this->assertTrue(Cache::write('test_groups', 'value', 'memcached_groups'));
$this->assertEquals('value', Cache::read('test_groups', 'memcached_groups'));
$this->assertTrue(Cache::delete('test_groups', 'memcached_groups'));
$this->assertFalse(Cache::read('test_groups', 'memcached_groups'));
}
/**
* Test clearing a cache group
*
* @return void
*/
public function testGroupClear() {
Cache::config('memcached_groups', array(
'engine' => 'Memcached',
'duration' => 3600,
'groups' => array('group_a', 'group_b')
));
$this->assertTrue(Cache::write('test_groups', 'value', 'memcached_groups'));
$this->assertTrue(Cache::clearGroup('group_a', 'memcached_groups'));
$this->assertFalse(Cache::read('test_groups', 'memcached_groups'));
$this->assertTrue(Cache::write('test_groups', 'value2', 'memcached_groups'));
$this->assertTrue(Cache::clearGroup('group_b', 'memcached_groups'));
$this->assertFalse(Cache::read('test_groups', 'memcached_groups'));
}
}

View file

@ -76,6 +76,7 @@ class RedisEngineTest extends CakeTestCase {
'timeout' => 0,
'persistent' => true,
'password' => false,
'database' => 0,
);
$this->assertEquals($expecting, $settings);
}
@ -90,6 +91,51 @@ class RedisEngineTest extends CakeTestCase {
$this->assertTrue($Redis->init(Cache::settings('redis')));
}
/**
* testMultiDatabaseOperations method
*
* @return void
*/
public function testMultiDatabaseOperations() {
Cache::config('redisdb0', array(
'engine' => 'Redis',
'prefix' => 'cake2_',
'duration' => 3600,
'persistent' => false,
));
Cache::config('redisdb1', array(
'engine' => 'Redis',
'database' => 1,
'prefix' => 'cake2_',
'duration' => 3600,
'persistent' => false,
));
$result = Cache::write('save_in_0', true, 'redisdb0');
$exist = Cache::read('save_in_0', 'redisdb0');
$this->assertTrue($result);
$this->assertTrue($exist);
$result = Cache::write('save_in_1', true, 'redisdb1');
$this->assertTrue($result);
$exist = Cache::read('save_in_0', 'redisdb1');
$this->assertFalse($exist);
$exist = Cache::read('save_in_1', 'redisdb1');
$this->assertTrue($exist);
Cache::delete('save_in_0', 'redisdb0');
$exist = Cache::read('save_in_0', 'redisdb0');
$this->assertFalse($exist);
Cache::delete('save_in_1', 'redisdb1');
$exist = Cache::read('save_in_1', 'redisdb1');
$this->assertFalse($exist);
Cache::drop('redisdb0');
Cache::drop('redisdb1');
}
/**
* testReadAndWriteCache method
*

View file

@ -20,6 +20,7 @@ App::uses('CommandListShell', 'Console/Command');
App::uses('ConsoleOutput', 'Console');
App::uses('ConsoleInput', 'Console');
App::uses('Shell', 'Console');
App::uses('CommandTask', 'Console/Command/Task');
/**
* Class TestStringOutput
@ -68,6 +69,12 @@ class CommandListShellTest extends CakeTestCase {
array('in', '_stop', 'clear'),
array($out, $out, $in)
);
$this->Shell->Command = $this->getMock(
'CommandTask',
array('in', '_stop', 'clear'),
array($out, $out, $in)
);
}
/**
@ -96,7 +103,7 @@ class CommandListShellTest extends CakeTestCase {
$expected = "/\[.*TestPluginTwo.*\] example, welcome/";
$this->assertRegExp($expected, $output);
$expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, server, test, testsuite, upgrade/";
$expected = "/\[.*CORE.*\] acl, api, bake, command_list, completion, console, i18n, schema, server, test, testsuite, upgrade/";
$this->assertRegExp($expected, $output);
$expected = "/\[.*app.*\] sample/";

View file

@ -0,0 +1,261 @@
<?php
/**
* CompletionShellTest file
*
* PHP 5
*
* CakePHP : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP Project
* @package Cake.Test.Case.Console.Command
* @since CakePHP v 2.5
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('CompletionShell', 'Console/Command');
App::uses('ConsoleOutput', 'Console');
App::uses('ConsoleInput', 'Console');
App::uses('Shell', 'Console');
App::uses('CommandTask', 'Console/Command/Task');
/**
* Class TestCompletionStringOutput
*
* @package Cake.Test.Case.Console.Command
*/
class TestCompletionStringOutput extends ConsoleOutput {
public $output = '';
protected function _write($message) {
$this->output .= $message;
}
}
/**
* Class CompletionShellTest
*
* @package Cake.Test.Case.Console.Command
*/
class CompletionShellTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
App::build(array(
'Plugin' => array(
CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
),
'Console/Command' => array(
CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Command' . DS
)
), App::RESET);
CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
$out = new TestCompletionStringOutput();
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell = $this->getMock(
'CompletionShell',
array('in', '_stop', 'clear'),
array($out, $out, $in)
);
$this->Shell->Command = $this->getMock(
'CommandTask',
array('in', '_stop', 'clear'),
array($out, $out, $in)
);
}
/**
* tearDown
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->Shell);
CakePlugin::unload();
}
/**
* test that the startup method supresses the shell header
*
* @return void
*/
public function testStartup() {
$this->Shell->runCommand('main', array());
$output = $this->Shell->stdout->output;
$needle = 'Welcome to CakePHP';
$this->assertTextNotContains($needle, $output);
}
/**
* test that main displays a warning
*
* @return void
*/
public function testMain() {
$this->Shell->runCommand('main', array());
$output = $this->Shell->stdout->output;
$expected = "/This command is not intended to be called manually/";
$this->assertRegExp($expected, $output);
}
/**
* test commands method that list all available commands
*
* @return void
*/
public function testCommands() {
$this->Shell->runCommand('commands', array());
$output = $this->Shell->stdout->output;
$expected = "TestPlugin.example TestPluginTwo.example TestPluginTwo.welcome acl api bake command_list completion console i18n schema server test testsuite upgrade sample\n";
$this->assertEquals($expected, $output);
}
/**
* test that options without argument returns the default options
*
* @return void
*/
public function testOptionsNoArguments() {
$this->Shell->runCommand('options', array());
$output = $this->Shell->stdout->output;
$expected = "--help -h --verbose -v --quiet -q\n";
$this->assertEquals($expected, $output);
}
/**
* test that options with a nonexisting command returns the default options
*
* @return void
*/
public function testOptionsNonExistingCommand() {
$this->Shell->runCommand('options', array('options', 'foo'));
$output = $this->Shell->stdout->output;
$expected = "--help -h --verbose -v --quiet -q\n";
$this->assertEquals($expected, $output);
}
/**
* test that options with a existing command returns the proper options
*
* @return void
*/
public function testOptions() {
$this->Shell->runCommand('options', array('options', 'bake'));
$output = $this->Shell->stdout->output;
$expected = "--help -h --verbose -v --quiet -q --connection -c --theme -t\n";
$this->assertEquals($expected, $output);
}
/**
* test that subCommands with a existing CORE command returns the proper sub commands
*
* @return void
*/
public function testSubCommandsCorePlugin() {
$this->Shell->runCommand('subCommands', array('subCommands', 'CORE.bake'));
$output = $this->Shell->stdout->output;
$expected = "controller db_config fixture model plugin project test view\n";
$this->assertEquals($expected, $output);
}
/**
* test that subCommands with a existing APP command returns the proper sub commands (in this case none)
*
* @return void
*/
public function testSubCommandsAppPlugin() {
$this->Shell->runCommand('subCommands', array('subCommands', 'app.sample'));
$output = $this->Shell->stdout->output;
$expected = '';
$this->assertEquals($expected, $output);
}
/**
* test that subCommands with a existing plugin command returns the proper sub commands
*
* @return void
*/
public function testSubCommandsPlugin() {
$this->Shell->runCommand('subCommands', array('subCommands', 'TestPluginTwo.welcome'));
$output = $this->Shell->stdout->output;
$expected = "say_hello\n";
$this->assertEquals($expected, $output);
}
/**
* test that subcommands without arguments returns nothing
*
* @return void
*/
public function testSubCommandsNoArguments() {
$this->Shell->runCommand('subCommands', array());
$output = $this->Shell->stdout->output;
$expected = '';
$this->assertEquals($expected, $output);
}
/**
* test that subcommands with a nonexisting command returns nothing
*
* @return void
*/
public function testSubCommandsNonExistingCommand() {
$this->Shell->runCommand('subCommands', array('subCommands', 'foo'));
$output = $this->Shell->stdout->output;
$expected = '';
$this->assertEquals($expected, $output);
}
/**
* test that subcommands returns the available subcommands for the given command
*
* @return void
*/
public function testSubCommands() {
$this->Shell->runCommand('subCommands', array('subCommands', 'bake'));
$output = $this->Shell->stdout->output;
$expected = "controller db_config fixture model plugin project test view\n";
$this->assertEquals($expected, $output);
}
/**
* test that fuzzy returns nothing
*
* @return void
*/
public function testFuzzy() {
$this->Shell->runCommand('fuzzy', array());
$output = $this->Shell->stdout->output;
$expected = '';
$this->assertEquals($expected, $output);
}
}

View file

@ -424,6 +424,29 @@ class SchemaShellTest extends CakeTestCase {
$this->assertContains('public $aros_acos = array(', $contents);
}
/**
* Test schema run create with --yes option
*
* @return void
*/
public function testCreateOptionYes() {
$this->Shell = $this->getMock(
'SchemaShell',
array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_run'),
array(&$this->Dispatcher)
);
$this->Shell->params = array(
'connection' => 'test',
'yes' => true,
);
$this->Shell->args = array('i18n');
$this->Shell->expects($this->never())->method('in');
$this->Shell->expects($this->exactly(2))->method('_run');
$this->Shell->startup();
$this->Shell->create();
}
/**
* Test schema run create with no table args.
*
@ -534,6 +557,33 @@ class SchemaShellTest extends CakeTestCase {
$this->Shell->update();
}
/**
* test run update with --yes option
*
* @return void
*/
public function testUpdateWithOptionYes() {
$this->Shell = $this->getMock(
'SchemaShell',
array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_run'),
array(&$this->Dispatcher)
);
$this->Shell->params = array(
'connection' => 'test',
'force' => true,
'yes' => true,
);
$this->Shell->args = array('SchemaShellTest', 'articles');
$this->Shell->startup();
$this->Shell->expects($this->never())->method('in');
$this->Shell->expects($this->once())
->method('_run')
->with($this->arrayHasKey('articles'), 'update', $this->isInstanceOf('CakeSchema'));
$this->Shell->update();
}
/**
* test that the plugin param creates the correct path in the schema object.
*

View file

@ -0,0 +1,240 @@
<?php
/**
* CakePHP : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP Project
* @package Cake.Test.Case.Console.Command
* @since CakePHP v 2.5
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('CommandTask', 'Console/Command/Task');
/**
* CommandTaskTest class
*
* @package Cake.Test.Case.Console.Command.Task
*/
class CommandTaskTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
App::build(array(
'Plugin' => array(
CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
),
'Console/Command' => array(
CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Command' . DS
)
), App::RESET);
CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->CommandTask = $this->getMock(
'CommandTask',
array('in', '_stop', 'clear'),
array($out, $out, $in)
);
}
/**
* tearDown
*
* @return void
*/
public function tearDown() {
parent::tearDown();
unset($this->CommandTask);
CakePlugin::unload();
}
/**
* Test the resulting list of shells
*
* @return void
*/
public function testGetShellList() {
$result = $this->CommandTask->getShellList();
$expected = array(
'CORE' => array(
'acl',
'api',
'bake',
'command_list',
'completion',
'console',
'i18n',
'schema',
'server',
'test',
'testsuite',
'upgrade'
),
'TestPlugin' => array(
'example'
),
'TestPluginTwo' => array(
'example',
'welcome'
),
'app' => array(
'sample'
),
);
$this->assertEquals($expected, $result);
}
/**
* Test the resulting list of commands
*
* @return void
*/
public function testCommands() {
$result = $this->CommandTask->commands();
$expected = array(
'TestPlugin.example',
'TestPluginTwo.example',
'TestPluginTwo.welcome',
'acl',
'api',
'bake',
'command_list',
'completion',
'console',
'i18n',
'schema',
'server',
'test',
'testsuite',
'upgrade',
'sample'
);
$this->assertEquals($expected, $result);
}
/**
* Test the resulting list of subcommands for the given command
*
* @return void
*/
public function testSubCommands() {
$result = $this->CommandTask->subCommands('acl');
$expected = array(
'check',
'create',
'db_config',
'delete',
'deny',
'getPath',
'grant',
'inherit',
'initdb',
'nodeExists',
'parseIdentifier',
'setParent',
'view'
);
$this->assertEquals($expected, $result);
}
/**
* Test that unknown commands return an empty array
*
* @return void
*/
public function testSubCommandsUnknownCommand() {
$result = $this->CommandTask->subCommands('yoghurt');
$expected = array();
$this->assertEquals($expected, $result);
}
/**
* Test that getting a existing shell returns the shell instance
*
* @return void
*/
public function testGetShell() {
$result = $this->CommandTask->getShell('acl');
$this->assertInstanceOf('AclShell', $result);
}
/**
* Test that getting a non-existing shell returns false
*
* @return void
*/
public function testGetShellNonExisting() {
$result = $this->CommandTask->getShell('strawberry');
$this->assertFalse($result);
}
/**
* Test that getting a existing core shell with 'core.' prefix returns the correct shell instance
*
* @return void
*/
public function testGetShellCore() {
$result = $this->CommandTask->getShell('core.bake');
$this->assertInstanceOf('BakeShell', $result);
}
/**
* Test the options array for a known command
*
* @return void
*/
public function testOptions() {
$result = $this->CommandTask->options('bake');
$expected = array(
'--help',
'-h',
'--verbose',
'-v',
'--quiet',
'-q',
'--connection',
'-c',
'--theme',
'-t'
);
$this->assertEquals($expected, $result);
}
/**
* Test the options array for an unknown command
*
* @return void
*/
public function testOptionsUnknownCommand() {
$result = $this->CommandTask->options('pie');
$expected = array(
'--help',
'-h',
'--verbose',
'-v',
'--quiet',
'-q'
);
$this->assertEquals($expected, $result);
}
}

View file

@ -30,6 +30,7 @@ App::uses('ModelTask', 'Console/Command/Task');
* ModelTaskTest class
*
* @package Cake.Test.Case.Console.Command.Task
* @property ModelTask $Task
*/
class ModelTaskTest extends CakeTestCase {
@ -358,6 +359,100 @@ class ModelTaskTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
/**
* Test that skipping fields during rule choice works when doing interactive field validation.
*
* @return void
*/
public function testSkippingChoiceInteractiveFieldValidation() {
$this->Task->initValidations();
$this->Task->interactive = true;
$this->Task->expects($this->any())->method('in')
->will($this->onConsecutiveCalls('24', 'y', 's'));
$result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
$expected = array('notEmpty' => 'notEmpty', '_skipFields' => true);
$this->assertEquals($expected, $result);
}
/**
* Test that skipping fields after rule choice works when doing interactive field validation.
*
* @return void
*/
public function testSkippingAnotherInteractiveFieldValidation() {
$this->Task->initValidations();
$this->Task->interactive = true;
$this->Task->expects($this->any())->method('in')
->will($this->onConsecutiveCalls('24', 's'));
$result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
$expected = array('notEmpty' => 'notEmpty', '_skipFields' => true);
$this->assertEquals($expected, $result);
}
/**
* Test the validation generation routine with skipping the rest of the fields
* when doing interactive field validation.
*
* @return void
*/
public function testInteractiveDoValidationWithSkipping() {
$this->Task->expects($this->any())
->method('in')
->will($this->onConsecutiveCalls('35', '24', 'n', '11', 's'));
$this->Task->interactive = true;
$Model = $this->getMock('Model');
$Model->primaryKey = 'id';
$Model->expects($this->any())
->method('schema')
->will($this->returnValue(array(
'id' => array(
'type' => 'integer',
'length' => 11,
'null' => false,
'key' => 'primary',
),
'name' => array(
'type' => 'string',
'length' => 20,
'null' => false,
),
'email' => array(
'type' => 'string',
'length' => 255,
'null' => false,
),
'some_date' => array(
'type' => 'date',
'length' => '',
'null' => false,
),
'some_time' => array(
'type' => 'time',
'length' => '',
'null' => false,
),
'created' => array(
'type' => 'datetime',
'length' => '',
'null' => false,
)
)
));
$result = $this->Task->doValidation($Model);
$expected = array(
'name' => array(
'notEmpty' => 'notEmpty'
),
'email' => array(
'email' => 'email',
),
);
$this->assertEquals($expected, $result);
}
/**
* test the validation Generation routine
*
@ -366,39 +461,42 @@ class ModelTaskTest extends CakeTestCase {
public function testNonInteractiveDoValidation() {
$Model = $this->getMock('Model');
$Model->primaryKey = 'id';
$Model->expects($this->any())->method('schema')->will($this->returnValue(array(
'id' => array(
'type' => 'integer',
'length' => 11,
'null' => false,
'key' => 'primary',
),
'name' => array(
'type' => 'string',
'length' => 20,
'null' => false,
),
'email' => array(
'type' => 'string',
'length' => 255,
'null' => false,
),
'some_date' => array(
'type' => 'date',
'length' => '',
'null' => false,
),
'some_time' => array(
'type' => 'time',
'length' => '',
'null' => false,
),
'created' => array(
'type' => 'datetime',
'length' => '',
'null' => false,
$Model->expects($this->any())
->method('schema')
->will($this->returnValue(array(
'id' => array(
'type' => 'integer',
'length' => 11,
'null' => false,
'key' => 'primary',
),
'name' => array(
'type' => 'string',
'length' => 20,
'null' => false,
),
'email' => array(
'type' => 'string',
'length' => 255,
'null' => false,
),
'some_date' => array(
'type' => 'date',
'length' => '',
'null' => false,
),
'some_time' => array(
'type' => 'time',
'length' => '',
'null' => false,
),
'created' => array(
'type' => 'datetime',
'length' => '',
'null' => false,
)
)
)));
));
$this->Task->interactive = false;
$result = $this->Task->doValidation($Model);

View file

@ -413,6 +413,8 @@ class TestTaskTest extends CakeTestCase {
$this->assertContains('function testDoSomething()', $result);
$this->assertContains('function testDoSomethingElse()', $result);
$this->assertContains('$this->markTestIncomplete(\'testDoSomething not implemented.\')', $result);
$this->assertContains('$this->markTestIncomplete(\'testDoSomethingElse not implemented.\')', $result);
$this->assertContains("'app.test_task_article'", $result);
$this->assertContains("'app.test_task_comment'", $result);

View file

@ -256,7 +256,6 @@ class DbAclTest extends CakeTestCase {
/**
* testDbAclAllow method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testAllow() {
@ -297,17 +296,16 @@ class DbAclTest extends CakeTestCase {
* @return void
*/
public function testAllowInvalidPermission() {
$this->Acl->allow('Micheal', 'tpsReports', 'derp');
$this->assertFalse($this->Acl->allow('Micheal', 'tpsReports', 'derp'));
}
/**
* testAllowInvalidNode method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testAllowInvalidNode() {
$this->Acl->allow('Homer', 'tpsReports', 'create');
$this->assertFalse($this->Acl->allow('Homer', 'tpsReports', 'create'));
}
/**
@ -333,7 +331,6 @@ class DbAclTest extends CakeTestCase {
/**
* testCheckInvalidNode method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testCheckInvalidNode() {
@ -343,21 +340,19 @@ class DbAclTest extends CakeTestCase {
/**
* testCheckInvalidPermission method
*
* @expectedException PHPUnit_Framework_Error_Notice
* @return void
*/
public function testCheckInvalidPermission() {
$this->Acl->check('Lumbergh', 'smash', 'foobar');
$this->assertFalse($this->Acl->check('Lumbergh', 'smash', 'foobar'));
}
/**
* testCheckMissingPermission method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testCheckMissingPermission() {
$this->Acl->check('users', 'NonExistent', 'read');
$this->assertFalse($this->Acl->check('users', 'NonExistent', 'read'));
}
/**
@ -380,7 +375,6 @@ class DbAclTest extends CakeTestCase {
/**
* testDbAclDeny method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testDeny() {
@ -450,7 +444,6 @@ class DbAclTest extends CakeTestCase {
/**
* testDbGrant method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testGrant() {
@ -471,7 +464,6 @@ class DbAclTest extends CakeTestCase {
/**
* testDbRevoke method
*
* @expectedException PHPUnit_Framework_Error_Warning
* @return void
*/
public function testRevoke() {

View file

@ -590,6 +590,27 @@ class AuthComponentTest extends CakeTestCase {
$this->assertEquals('AuthUser', $result->settings['userModel']);
}
/**
* test defining the same Authenticate object but with different password hashers
*
* @return void
*/
public function testSameAuthenticateWithDifferentHashers() {
$this->Controller->Auth->authenticate = array(
'FormSimple' => array('className' => 'Form', 'passwordHasher' => 'Simple'),
'FormBlowfish' => array('className' => 'Form', 'passwordHasher' => 'Blowfish'),
);
$objects = $this->Controller->Auth->constructAuthenticate();
$this->assertEquals(2, count($objects));
$this->assertInstanceOf('FormAuthenticate', $objects[0]);
$this->assertInstanceOf('FormAuthenticate', $objects[1]);
$this->assertInstanceOf('SimplePasswordHasher', $objects[0]->passwordHasher());
$this->assertInstanceOf('BlowfishPasswordHasher', $objects[1]->passwordHasher());
}
/**
* Tests that deny always takes precedence over allow
*
@ -1123,11 +1144,13 @@ class AuthComponentTest extends CakeTestCase {
App::uses('Dispatcher', 'Routing');
$Response = new CakeResponse();
ob_start();
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(new CakeRequest('/ajax_auth/add'), new CakeResponse(), array('return' => 1));
$Dispatcher->dispatch(new CakeRequest('/ajax_auth/add'), $Response, array('return' => 1));
$result = ob_get_clean();
$this->assertEquals(403, $Response->statusCode());
$this->assertEquals("Ajax!\nthis is the test element", str_replace("\r\n", "\n", $result));
unset($_SERVER['HTTP_X_REQUESTED_WITH']);
}

View file

@ -201,6 +201,40 @@ class CookieComponentTest extends CakeTestCase {
$this->assertEquals('value', $result);
}
/**
* test write() encrypted data with falsey value
*
* @return void
*/
public function testWriteWithFalseyValue() {
$this->Cookie->type('aes');
$this->Cookie->key = 'qSI232qs*&sXOw!adre@34SAv!@*(XSL#$%)asGb$@11~_+!@#HKis~#^';
$this->Cookie->write('Testing');
$result = $this->Cookie->read('Testing');
$this->assertNull($result);
$this->Cookie->write('Testing', '');
$result = $this->Cookie->read('Testing');
$this->assertEquals('', $result);
$this->Cookie->write('Testing', false);
$result = $this->Cookie->read('Testing');
$this->assertFalse($result);
$this->Cookie->write('Testing', 1);
$result = $this->Cookie->read('Testing');
$this->assertEquals(1, $result);
$this->Cookie->write('Testing', '0');
$result = $this->Cookie->read('Testing');
$this->assertSame('0', $result);
$this->Cookie->write('Testing', 0);
$result = $this->Cookie->read('Testing');
$this->assertSame(0, $result);
}
/**
* test that two write() calls use the expiry.
*

View file

@ -191,14 +191,14 @@ This is the body of the message
MSGBLOC;
$this->Controller->EmailTest->sendAs = 'text';
$expect = str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $message);
$expected = str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $message);
$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
$this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
$this->assertTextEquals($expected, DebugCompTransport::$lastEmail);
$this->Controller->EmailTest->sendAs = 'html';
$expect = str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $message);
$expected = str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $message);
$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
$this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
$this->assertTextEquals($expected, DebugCompTransport::$lastEmail);
}
/**
@ -262,18 +262,18 @@ TEXTBLOC;
HTMLBLOC;
$this->Controller->EmailTest->sendAs = 'text';
$expect = '<pre>' . str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $header) . $text . "\n" . '</pre>';
$expected = '<pre>' . str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $header) . $text . "\n" . '</pre>';
$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
$this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
$this->assertTextEquals($expected, DebugCompTransport::$lastEmail);
$this->Controller->EmailTest->sendAs = 'html';
$expect = '<pre>' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . "\n" . '</pre>';
$expected = '<pre>' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . "\n" . '</pre>';
$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
$this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
$this->assertTextEquals($expected, DebugCompTransport::$lastEmail);
$this->Controller->EmailTest->sendAs = 'both';
$expect = str_replace('{CONTENTTYPE}', 'multipart/mixed; boundary="{boundary}"', $header);
$expect .= "--{boundary}\n" .
$expected = str_replace('{CONTENTTYPE}', 'multipart/mixed; boundary="{boundary}"', $header);
$expected .= "--{boundary}\n" .
'Content-Type: multipart/alternative; boundary="alt-{boundary}"' . "\n\n" .
'--alt-{boundary}' . "\n" .
'Content-Type: text/plain; charset=UTF-8' . "\n" .
@ -288,11 +288,11 @@ HTMLBLOC;
'--alt-{boundary}--' . "\n\n\n" .
'--{boundary}--' . "\n";
$expect = '<pre>' . $expect . '</pre>';
$expected = '<pre>' . $expected . '</pre>';
$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
$this->assertTextEquals(
$expect,
$expected,
preg_replace('/[a-z0-9]{32}/i', '{boundary}', DebugCompTransport::$lastEmail)
);
@ -313,9 +313,9 @@ HTMLBLOC;
HTMLBLOC;
$this->Controller->EmailTest->sendAs = 'html';
$expect = '<pre>' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . '</pre>';
$expected = '<pre>' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . '</pre>';
$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message', 'default', 'thin'));
$this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
$this->assertTextEquals($expected, DebugCompTransport::$lastEmail);
}
/**

View file

@ -185,8 +185,8 @@ class PaginatorAuthor extends CakeTestModel {
* @var string
*/
public $virtualFields = array(
'joined_offset' => 'PaginatorAuthor.id + 1'
);
'joined_offset' => 'PaginatorAuthor.id + 1'
);
}
@ -358,7 +358,7 @@ class PaginatorComponentTest extends CakeTestCase {
$this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
$this->assertEquals(array(3, 2, 1), $results);
$Controller->request->params['named'] = array('sort' => 'NotExisting.field', 'direction' => 'desc');
$Controller->request->params['named'] = array('sort' => 'NotExisting.field', 'direction' => 'desc', 'limit' => 2);
$Controller->Paginator->paginate('PaginatorControllerPost');
$this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
$this->assertEquals(array(), $Controller->PaginatorControllerPost->lastQueries[1]['order'][0], 'no order should be set.');
@ -367,7 +367,7 @@ class PaginatorComponentTest extends CakeTestCase {
'sort' => 'PaginatorControllerPost.author_id', 'direction' => 'allYourBase'
);
$results = Hash::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
$this->assertEquals(array('PaginatorControllerPost.author_id' => 'asc'), $Controller->PaginatorControllerPost->lastQueries[1]['order'][0]);
$this->assertEquals(array('PaginatorControllerPost.author_id' => 'asc'), $Controller->PaginatorControllerPost->lastQueries[0]['order'][0]);
$this->assertEquals(array(1, 3, 2), $results);
$Controller->request->params['named'] = array();
@ -466,7 +466,7 @@ class PaginatorComponentTest extends CakeTestCase {
$result = $Controller->Paginator->paginate('PaginatorControllerPost');
$this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
$this->assertEquals(array(1, 2, 3), Hash::extract($result, '{n}.PaginatorControllerPost.id'));
$this->assertTrue(isset($Controller->PaginatorControllerPost->lastQueries[1]['contain']));
$this->assertTrue(isset($Controller->PaginatorControllerPost->lastQueries[0]['contain']));
$Controller->Paginator->settings = array(
'PaginatorControllerPost' => array(
@ -475,14 +475,14 @@ class PaginatorComponentTest extends CakeTestCase {
);
$result = $Controller->Paginator->paginate('PaginatorControllerPost');
$this->assertEquals(array(2, 3), Hash::extract($result, '{n}.PaginatorControllerPost.id'));
$this->assertEquals(array('PaginatorControllerPost.id > ' => '1'), $Controller->PaginatorControllerPost->lastQueries[1]['conditions']);
$this->assertEquals(array('PaginatorControllerPost.id > ' => '1'), $Controller->PaginatorControllerPost->lastQueries[0]['conditions']);
$Controller->request->params['named'] = array('limit' => 12);
$Controller->Paginator->settings = array('limit' => 30, 'maxLimit' => 100, 'paramType' => 'named');
$result = $Controller->Paginator->paginate('PaginatorControllerPost');
$paging = $Controller->params['paging']['PaginatorControllerPost'];
$this->assertEquals(12, $Controller->PaginatorControllerPost->lastQueries[1]['limit']);
$this->assertEquals(12, $Controller->PaginatorControllerPost->lastQueries[0]['limit']);
$this->assertEquals(12, $paging['options']['limit']);
$Controller = new PaginatorTestController($this->request);
@ -551,7 +551,7 @@ class PaginatorComponentTest extends CakeTestCase {
$this->assertEquals(array(2, 3), Hash::extract($result, '{n}.PaginatorControllerPost.id'));
$this->assertEquals(
$Controller->PaginatorControllerPost->lastQueries[1]['conditions'],
$Controller->PaginatorControllerPost->lastQueries[0]['conditions'],
array('PaginatorControllerPost.id > ' => '1')
);
$this->assertFalse(isset($Controller->params['paging']['PaginatorControllerPost']['options'][0]));

Some files were not shown because too many files have changed in this diff Show more