mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Merge remote-tracking branch 'origin/2.5' into k-halaburda-master
This commit is contained in:
commit
df549898ad
45 changed files with 2654 additions and 225 deletions
|
@ -11,6 +11,9 @@ env:
|
|||
- DB=pgsql
|
||||
- DB=sqlite
|
||||
|
||||
services:
|
||||
- memcached
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.4
|
||||
|
@ -29,6 +32,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
|
||||
|
|
|
@ -309,18 +309,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)
|
||||
|
|
|
@ -542,4 +542,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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,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 {
|
||||
|
||||
|
|
317
lib/Cake/Cache/Engine/MemcachedEngine.php
Executable file
317
lib/Cake/Cache/Engine/MemcachedEngine.php
Executable file
|
@ -0,0 +1,317 @@
|
|||
<?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) . '_';
|
||||
}
|
||||
$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);
|
||||
}
|
||||
}
|
|
@ -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
lib/Cake/Console/Command/CompletionShell.php
Normal file
155
lib/Cake/Console/Command/CompletionShell.php
Normal 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* getOptionParser for _this_ shell
|
||||
*
|
||||
* @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(
|
||||
array(
|
||||
__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, ' '));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -333,7 +333,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);
|
||||
}
|
||||
|
@ -341,7 +344,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);
|
||||
}
|
||||
|
@ -392,7 +398,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);
|
||||
|
@ -471,7 +480,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',
|
||||
|
@ -482,7 +493,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(
|
||||
|
@ -496,10 +509,17 @@ 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.')
|
||||
__d('cake_console',
|
||||
'The Schema Shell generates a schema object from the database and updates the database from the schema.'
|
||||
)
|
||||
)->addSubcommand('view', array(
|
||||
'help' => __d('cake_console', 'Read and output the contents of a schema file'),
|
||||
'parser' => array(
|
||||
|
@ -523,7 +543,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.')
|
||||
|
@ -536,7 +556,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.')
|
||||
|
|
183
lib/Cake/Console/Command/Task/CommandTask.php
Normal file
183
lib/Cake/Console/Command/Task/CommandTask.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -132,7 +132,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
|
||||
*/
|
||||
|
@ -364,10 +366,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;
|
||||
|
@ -455,12 +458,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -476,27 +487,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
|
||||
*
|
||||
|
|
|
@ -372,18 +372,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
|
||||
|
@ -455,11 +443,7 @@ class CakeLog {
|
|||
$logged = true;
|
||||
}
|
||||
}
|
||||
if (!$logged) {
|
||||
self::_autoConfig();
|
||||
self::stream('default')->write($type, $message);
|
||||
}
|
||||
return true;
|
||||
return $logged;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -682,7 +682,7 @@ class TreeBehavior extends ModelBehavior {
|
|||
$children = $Model->find('all', $params);
|
||||
$hasChildren = (bool)$children;
|
||||
|
||||
if (!is_null($parentId)) {
|
||||
if ($parentId !== null) {
|
||||
if ($hasChildren) {
|
||||
$Model->updateAll(
|
||||
array($this->settings[$Model->alias]['left'] => $counter),
|
||||
|
@ -713,7 +713,7 @@ class TreeBehavior extends ModelBehavior {
|
|||
$children = $Model->find('all', $params);
|
||||
}
|
||||
|
||||
if (!is_null($parentId) && $hasChildren) {
|
||||
if ($parentId !== null && $hasChildren) {
|
||||
$Model->updateAll(
|
||||
array($this->settings[$Model->alias]['right'] => $counter),
|
||||
array($Model->escapeField() => $parentId)
|
||||
|
|
|
@ -1918,7 +1918,7 @@ class Model extends Object implements CakeEventListener {
|
|||
}
|
||||
|
||||
foreach ((array)$data as $row) {
|
||||
if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) {
|
||||
if ((is_string($row) && (strlen($row) === 36 || strlen($row) === 16)) || is_numeric($row)) {
|
||||
$newJoins[] = $row;
|
||||
$values = array($id, $row);
|
||||
|
||||
|
|
|
@ -249,7 +249,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);
|
||||
|
@ -376,32 +384,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];
|
||||
}
|
||||
|
|
|
@ -516,8 +516,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);
|
||||
|
@ -576,7 +581,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.
|
||||
|
|
|
@ -570,7 +570,7 @@ class CakeResponse {
|
|||
if (is_numeric($header)) {
|
||||
list($header, $value) = array($value, null);
|
||||
}
|
||||
if (is_null($value)) {
|
||||
if ($value === null) {
|
||||
list($header, $value) = explode(':', $header, 2);
|
||||
}
|
||||
$this->_headers[$header] = is_array($value) ? array_map('trim', $value) : trim($value);
|
||||
|
|
|
@ -500,11 +500,14 @@ class Router {
|
|||
public static function mapResources($controller, $options = array()) {
|
||||
$hasPrefix = isset($options['prefix']);
|
||||
$options = array_merge(array(
|
||||
'connectOptions' => array(),
|
||||
'prefix' => '/',
|
||||
'id' => self::ID . '|' . self::UUID
|
||||
), $options);
|
||||
|
||||
$prefix = $options['prefix'];
|
||||
$connectOptions = $options['connectOptions'];
|
||||
unset($options['connectOptions']);
|
||||
|
||||
foreach ((array)$controller as $name) {
|
||||
list($plugin, $name) = pluginSplit($name);
|
||||
|
@ -524,7 +527,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;
|
||||
|
@ -1035,7 +1041,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ App::uses('Cache', 'Cache');
|
|||
*/
|
||||
class CacheTest extends CakeTestCase {
|
||||
|
||||
protected $_count = 0;
|
||||
|
||||
/**
|
||||
* setUp method
|
||||
*
|
||||
|
@ -491,4 +493,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;
|
||||
}
|
||||
}
|
||||
|
|
728
lib/Cake/Test/Case/Cache/Engine/MemcachedEngineTest.php
Executable file
728
lib/Cake/Test/Case/Cache/Engine/MemcachedEngineTest.php
Executable file
|
@ -0,0 +1,728 @@
|
|||
<?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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'));
|
||||
}
|
||||
}
|
|
@ -22,6 +22,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
|
||||
|
@ -70,6 +71,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)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,7 +105,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/";
|
||||
|
|
261
lib/Cake/Test/Case/Console/Command/CompletionShellTest.php
Normal file
261
lib/Cake/Test/Case/Console/Command/CompletionShellTest.php
Normal 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);
|
||||
}
|
||||
}
|
|
@ -426,6 +426,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.
|
||||
*
|
||||
|
@ -536,6 +559,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.
|
||||
*
|
||||
|
|
240
lib/Cake/Test/Case/Console/Command/Task/CommandTaskTest.php
Normal file
240
lib/Cake/Test/Case/Console/Command/Task/CommandTaskTest.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -605,7 +605,6 @@ class ControllerTest extends CakeTestCase {
|
|||
|
||||
$Controller->set('title', 'someTitle');
|
||||
$this->assertSame($Controller->viewVars['title'], 'someTitle');
|
||||
$this->assertTrue(empty($Controller->pageTitle));
|
||||
|
||||
$Controller->viewVars = array();
|
||||
$expected = array('ModelName' => 'name', 'ModelName2' => 'name2');
|
||||
|
|
|
@ -126,27 +126,20 @@ class CakeLogTest extends CakeTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test that CakeLog autoconfigures itself to use a FileLogger with the LOGS dir.
|
||||
* When no streams are there.
|
||||
* Test that CakeLog does not auto create logs when no streams are there to listen.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAutoConfig() {
|
||||
public function testNoStreamListenting() {
|
||||
if (file_exists(LOGS . 'error.log')) {
|
||||
unlink(LOGS . 'error.log');
|
||||
}
|
||||
CakeLog::write(LOG_WARNING, 'Test warning');
|
||||
$this->assertTrue(file_exists(LOGS . 'error.log'));
|
||||
$res = CakeLog::write(LOG_WARNING, 'Test warning');
|
||||
$this->assertFalse($res);
|
||||
$this->assertFalse(file_exists(LOGS . 'error.log'));
|
||||
|
||||
$result = CakeLog::configured();
|
||||
$this->assertEquals(array('default'), $result);
|
||||
|
||||
$testMessage = 'custom message';
|
||||
CakeLog::write('custom', $testMessage);
|
||||
$content = file_get_contents(LOGS . 'custom.log');
|
||||
$this->assertContains($testMessage, $content);
|
||||
unlink(LOGS . 'error.log');
|
||||
unlink(LOGS . 'custom.log');
|
||||
$this->assertEquals(array(), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,6 +190,10 @@ class CakeLogTest extends CakeTestCase {
|
|||
* @return void
|
||||
*/
|
||||
public function testLogFileWriting() {
|
||||
CakeLog::config('file', array(
|
||||
'engine' => 'File',
|
||||
'path' => LOGS
|
||||
));
|
||||
if (file_exists(LOGS . 'error.log')) {
|
||||
unlink(LOGS . 'error.log');
|
||||
}
|
||||
|
@ -503,6 +500,11 @@ class CakeLogTest extends CakeTestCase {
|
|||
$this->_resetLogConfig();
|
||||
$this->_deleteLogs();
|
||||
|
||||
CakeLog::config('file', array(
|
||||
'engine' => 'File',
|
||||
'path' => LOGS
|
||||
));
|
||||
|
||||
CakeLog::write('bogus', 'bogus message');
|
||||
$this->assertTrue(file_exists(LOGS . 'bogus.log'));
|
||||
$this->assertFalse(file_exists(LOGS . 'error.log'));
|
||||
|
|
|
@ -443,10 +443,10 @@ class CakeSessionTest extends CakeTestCase {
|
|||
public function testKeyExploit() {
|
||||
$key = "a'] = 1; phpinfo(); \$_SESSION['a";
|
||||
$result = TestCakeSession::write($key, 'haxored');
|
||||
$this->assertTrue($result);
|
||||
$this->assertFalse($result);
|
||||
|
||||
$result = TestCakeSession::read($key);
|
||||
$this->assertEquals('haxored', $result);
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -612,6 +612,34 @@ class ModelValidationTest extends BaseModelTest {
|
|||
$this->assertEquals(0, $joinRecords, 'Records were saved on the join table. %s');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that if a behavior modifies the model's whitelist validation gets triggered
|
||||
* properly for those fields.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidateWithFieldListAndBehavior() {
|
||||
$TestModel = new ValidationTest1();
|
||||
$TestModel->validate = array(
|
||||
'title' => array(
|
||||
'rule' => 'notEmpty',
|
||||
),
|
||||
'name' => array(
|
||||
'rule' => 'notEmpty',
|
||||
));
|
||||
$TestModel->Behaviors->attach('ValidationRule', array('fields' => array('name')));
|
||||
|
||||
$data = array(
|
||||
'title' => '',
|
||||
'name' => '',
|
||||
);
|
||||
$result = $TestModel->save($data, array('fieldList' => array('title')));
|
||||
$this->assertFalse($result);
|
||||
|
||||
$expected = array('title' => array('This field cannot be left blank'), 'name' => array('This field cannot be left blank'));
|
||||
$this->assertEquals($expected, $TestModel->validationErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* test that saveAll and with models with validation interact well
|
||||
*
|
||||
|
@ -2380,3 +2408,21 @@ class ModelValidationTest extends BaseModelTest {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Behavior for testing validation rules.
|
||||
*/
|
||||
class ValidationRuleBehavior extends ModelBehavior {
|
||||
|
||||
public function setup(Model $Model, $config = array()) {
|
||||
$this->settings[$Model->alias] = $config;
|
||||
}
|
||||
|
||||
public function beforeValidate(Model $Model, $options = array()) {
|
||||
$fields = $this->settings[$Model->alias]['fields'];
|
||||
foreach ($fields as $field) {
|
||||
$Model->whitelist[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1046,6 +1046,13 @@ class CakeRequestTest extends CakeTestCase {
|
|||
|
||||
$request->return = false;
|
||||
$this->assertFalse($request->isCallMe());
|
||||
|
||||
$request->addDetector('extension', array('param' => 'ext', 'options' => array('pdf', 'png', 'txt')));
|
||||
$request->params['ext'] = 'pdf';
|
||||
$this->assertTrue($request->is('extension'));
|
||||
|
||||
$request->params['ext'] = 'exe';
|
||||
$this->assertFalse($request->isExtension());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -191,6 +191,28 @@ class RouterTest extends CakeTestCase {
|
|||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* testMapResources with custom connectOptions
|
||||
*/
|
||||
public function testMapResourcesConnectOptions() {
|
||||
App::build(array(
|
||||
'Plugin' => array(
|
||||
CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
|
||||
)
|
||||
));
|
||||
CakePlugin::load('TestPlugin');
|
||||
App::uses('TestRoute', 'TestPlugin.Routing/Route');
|
||||
$resources = Router::mapResources('Posts', array(
|
||||
'connectOptions' => array(
|
||||
'routeClass' => 'TestPlugin.TestRoute',
|
||||
'foo' => '^(bar)$',
|
||||
),
|
||||
));
|
||||
$route = end(Router::$routes);
|
||||
$this->assertInstanceOf('TestRoute', $route);
|
||||
$this->assertEquals('^(bar)$', $route->options['foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test mapResources with a plugin and prefix.
|
||||
*
|
||||
|
|
|
@ -346,11 +346,24 @@ class FolderTest extends CakeTestCase {
|
|||
* @return void
|
||||
*/
|
||||
public function testAddPathElement() {
|
||||
$expected = DS . 'some' . DS . 'dir' . DS . 'another_path';
|
||||
|
||||
$result = Folder::addPathElement(DS . 'some' . DS . 'dir', 'another_path');
|
||||
$this->assertEquals(DS . 'some' . DS . 'dir' . DS . 'another_path', $result);
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$result = Folder::addPathElement(DS . 'some' . DS . 'dir' . DS, 'another_path');
|
||||
$this->assertEquals(DS . 'some' . DS . 'dir' . DS . 'another_path', $result);
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$result = Folder::addPathElement(DS . 'some' . DS . 'dir', array('another_path'));
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$result = Folder::addPathElement(DS . 'some' . DS . 'dir' . DS, array('another_path'));
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$expected = DS . 'some' . DS . 'dir' . DS . 'another_path' . DS . 'and' . DS . 'another';
|
||||
|
||||
$result = Folder::addPathElement(DS . 'some' . DS . 'dir', array('another_path', 'and', 'another'));
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1303,6 +1303,23 @@ class HashTest extends CakeTestCase {
|
|||
$result = Hash::insert($data, '{n}.Comment.{n}.insert', 'value');
|
||||
$this->assertEquals('value', $result[0]['Comment'][0]['insert']);
|
||||
$this->assertEquals('value', $result[0]['Comment'][1]['insert']);
|
||||
|
||||
$data = array(
|
||||
0 => array('Item' => array('id' => 1, 'title' => 'first')),
|
||||
1 => array('Item' => array('id' => 2, 'title' => 'second')),
|
||||
2 => array('Item' => array('id' => 3, 'title' => 'third')),
|
||||
3 => array('Item' => array('id' => 4, 'title' => 'fourth')),
|
||||
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
||||
);
|
||||
$result = Hash::insert($data, '{n}.Item[id=/\b2|\b4/]', array('test' => 2));
|
||||
$expected = array(
|
||||
0 => array('Item' => array('id' => 1, 'title' => 'first')),
|
||||
1 => array('Item' => array('id' => 2, 'title' => 'second', 'test' => 2)),
|
||||
2 => array('Item' => array('id' => 3, 'title' => 'third')),
|
||||
3 => array('Item' => array('id' => 4, 'title' => 'fourth', 'test' => 2)),
|
||||
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
||||
);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1366,6 +1383,23 @@ class HashTest extends CakeTestCase {
|
|||
$result = Hash::remove($a, 'pages.2.vars');
|
||||
$expected = $a;
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$a = array(
|
||||
0 => array(
|
||||
'name' => 'pages'
|
||||
),
|
||||
1 => array(
|
||||
'name' => 'files'
|
||||
)
|
||||
);
|
||||
|
||||
$result = Hash::remove($a, '{n}[name=files]');
|
||||
$expected = array(
|
||||
0 => array(
|
||||
'name' => 'pages'
|
||||
)
|
||||
);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1385,6 +1419,22 @@ class HashTest extends CakeTestCase {
|
|||
$this->assertFalse(isset($result[0]['Article']['user_id']));
|
||||
$this->assertFalse(isset($result[0]['Article']['title']));
|
||||
$this->assertFalse(isset($result[0]['Article']['body']));
|
||||
|
||||
$data = array(
|
||||
0 => array('Item' => array('id' => 1, 'title' => 'first')),
|
||||
1 => array('Item' => array('id' => 2, 'title' => 'second')),
|
||||
2 => array('Item' => array('id' => 3, 'title' => 'third')),
|
||||
3 => array('Item' => array('id' => 4, 'title' => 'fourth')),
|
||||
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
||||
);
|
||||
|
||||
$result = Hash::remove($data, '{n}.Item[id=/\b2|\b4/]');
|
||||
$expected = array(
|
||||
0 => array('Item' => array('id' => 1, 'title' => 'first')),
|
||||
2 => array('Item' => array('id' => 3, 'title' => 'third')),
|
||||
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
||||
);
|
||||
$this->assertEquals($result, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -302,4 +302,115 @@ class SecurityTest extends CakeTestCase {
|
|||
Security::rijndael($txt, $key, 'encrypt');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test encrypt/decrypt.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEncryptDecrypt() {
|
||||
$txt = 'The quick brown fox';
|
||||
$key = 'This key is longer than 32 bytes long.';
|
||||
$result = Security::encrypt($txt, $key);
|
||||
$this->assertNotEquals($txt, $result, 'Should be encrypted.');
|
||||
$this->assertNotEquals($result, Security::encrypt($txt, $key), 'Each result is unique.');
|
||||
$this->assertEquals($txt, Security::decrypt($result, $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that changing the key causes decryption to fail.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDecryptKeyFailure() {
|
||||
$txt = 'The quick brown fox';
|
||||
$key = 'This key is longer than 32 bytes long.';
|
||||
$result = Security::encrypt($txt, $key);
|
||||
|
||||
$key = 'Not the same key. This one will fail';
|
||||
$this->assertFalse(Security::decrypt($txt, $key), 'Modified key will fail.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that decrypt fails when there is an hmac error.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDecryptHmacFailure() {
|
||||
$txt = 'The quick brown fox';
|
||||
$key = 'This key is quite long and works well.';
|
||||
$salt = 'this is a delicious salt!';
|
||||
$result = Security::encrypt($txt, $key, $salt);
|
||||
|
||||
// Change one of the bytes in the hmac.
|
||||
$result[10] = 'x';
|
||||
$this->assertFalse(Security::decrypt($result, $key, $salt), 'Modified hmac causes failure.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that changing the hmac salt will cause failures.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDecryptHmacSaltFailure() {
|
||||
$txt = 'The quick brown fox';
|
||||
$key = 'This key is quite long and works well.';
|
||||
$salt = 'this is a delicious salt!';
|
||||
$result = Security::encrypt($txt, $key, $salt);
|
||||
|
||||
$salt = 'humpty dumpty had a great fall.';
|
||||
$this->assertFalse(Security::decrypt($result, $key, $salt), 'Modified salt causes failure.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that short keys cause errors
|
||||
*
|
||||
* @expectedException CakeException
|
||||
* @expectedExceptionMessage Invalid key for encrypt(), key must be at least 256 bits (32 bytes) long.
|
||||
* @return void
|
||||
*/
|
||||
public function testEncryptInvalidKey() {
|
||||
$txt = 'The quick brown fox jumped over the lazy dog.';
|
||||
$key = 'this is too short';
|
||||
Security::encrypt($txt, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that empty data cause errors
|
||||
*
|
||||
* @expectedException CakeException
|
||||
* @expectedExceptionMessage The data to encrypt cannot be empty.
|
||||
* @return void
|
||||
*/
|
||||
public function testEncryptInvalidData() {
|
||||
$txt = '';
|
||||
$key = 'This is a key that is long enough to be ok.';
|
||||
Security::encrypt($txt, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that short keys cause errors
|
||||
*
|
||||
* @expectedException CakeException
|
||||
* @expectedExceptionMessage Invalid key for decrypt(), key must be at least 256 bits (32 bytes) long.
|
||||
* @return void
|
||||
*/
|
||||
public function testDecryptInvalidKey() {
|
||||
$txt = 'The quick brown fox jumped over the lazy dog.';
|
||||
$key = 'this is too short';
|
||||
Security::decrypt($txt, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that empty data cause errors
|
||||
*
|
||||
* @expectedException CakeException
|
||||
* @expectedExceptionMessage The data to decrypt cannot be empty.
|
||||
* @return void
|
||||
*/
|
||||
public function testDecryptInvalidData() {
|
||||
$txt = '';
|
||||
$key = 'This is a key that is long enough to be ok.';
|
||||
Security::decrypt($txt, $key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1946,8 +1946,15 @@ class ValidationTest extends CakeTestCase {
|
|||
$this->assertFalse(Validation::inList('three', array('one', 'two')));
|
||||
$this->assertFalse(Validation::inList('1one', array(0, 1, 2, 3)));
|
||||
$this->assertFalse(Validation::inList('one', array(0, 1, 2, 3)));
|
||||
$this->assertFalse(Validation::inList('2', array(1, 2, 3)));
|
||||
$this->assertTrue(Validation::inList('2', array(1, 2, 3), false));
|
||||
$this->assertTrue(Validation::inList('2', array(1, 2, 3)));
|
||||
$this->assertFalse(Validation::inList('2x', array(1, 2, 3)));
|
||||
$this->assertFalse(Validation::inList(2, array('1', '2x', '3')));
|
||||
$this->assertFalse(Validation::inList('One', array('one', 'two')));
|
||||
|
||||
// case insensitive
|
||||
$this->assertTrue(Validation::inList('one', array('One', 'Two'), true));
|
||||
$this->assertTrue(Validation::inList('Two', array('one', 'two'), true));
|
||||
$this->assertFalse(Validation::inList('three', array('one', 'two'), true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2066,14 +2073,24 @@ class ValidationTest extends CakeTestCase {
|
|||
$this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz', 'squirrel'), array('min' => 10)));
|
||||
|
||||
$this->assertTrue(Validation::multiple(array(0, 5, 9), array('in' => range(0, 10), 'max' => 5)));
|
||||
$this->assertFalse(Validation::multiple(array('0', '5', '9'), array('in' => range(0, 10), 'max' => 5)));
|
||||
$this->assertTrue(Validation::multiple(array('0', '5', '9'), array('in' => range(0, 10), 'max' => 5), false));
|
||||
$this->assertTrue(Validation::multiple(array('0', '5', '9'), array('in' => range(0, 10), 'max' => 5)));
|
||||
|
||||
$this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5)));
|
||||
$this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 11), array('in' => range(0, 10), 'max' => 5)));
|
||||
|
||||
$this->assertFalse(Validation::multiple(array(0, 5, 9), array('in' => range(0, 10), 'max' => 5, 'min' => 3)));
|
||||
$this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5, 'min' => 2)));
|
||||
$this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 11), array('in' => range(0, 10), 'max' => 5, 'min' => 2)));
|
||||
|
||||
$this->assertFalse(Validation::multiple(array('2x', '3x'), array('in' => array(1, 2, 3, 4, 5))));
|
||||
$this->assertFalse(Validation::multiple(array(2, 3), array('in' => array('1x', '2x', '3x', '4x'))));
|
||||
$this->assertFalse(Validation::multiple(array('one'), array('in' => array('One', 'Two'))));
|
||||
$this->assertFalse(Validation::multiple(array('Two'), array('in' => array('one', 'two'))));
|
||||
|
||||
// case insensitive
|
||||
$this->assertTrue(Validation::multiple(array('one'), array('in' => array('One', 'Two')), true));
|
||||
$this->assertTrue(Validation::multiple(array('Two'), array('in' => array('one', 'two')), true));
|
||||
$this->assertFalse(Validation::multiple(array('three'), array('in' => array('one', 'two')), true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2334,6 +2351,7 @@ class ValidationTest extends CakeTestCase {
|
|||
$this->assertTrue(Validation::mimeType($image, array('image/gif')));
|
||||
$this->assertTrue(Validation::mimeType(array('tmp_name' => $image), array('image/gif')));
|
||||
|
||||
$this->assertFalse(Validation::mimeType($image, array('image/GIF')));
|
||||
$this->assertFalse(Validation::mimeType($image, array('image/png')));
|
||||
$this->assertFalse(Validation::mimeType(array('tmp_name' => $image), array('image/png')));
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ class RssHelperTest extends CakeTestCase {
|
|||
*/
|
||||
public function testChannel() {
|
||||
$attrib = array('a' => '1', 'b' => '2');
|
||||
$elements = array('title' => 'title');
|
||||
$elements = array('title' => 'Title');
|
||||
$content = 'content';
|
||||
|
||||
$result = $this->Rss->channel($attrib, $elements, $content);
|
||||
|
@ -103,30 +103,7 @@ class RssHelperTest extends CakeTestCase {
|
|||
'b' => '2'
|
||||
),
|
||||
'<title',
|
||||
'title',
|
||||
'/title',
|
||||
'<link',
|
||||
$this->Rss->url('/', true),
|
||||
'/link',
|
||||
'<description',
|
||||
'content',
|
||||
'/channel'
|
||||
);
|
||||
$this->assertTags($result, $expected);
|
||||
|
||||
$this->View->pageTitle = 'title';
|
||||
$attrib = array('a' => '1', 'b' => '2');
|
||||
$elements = array();
|
||||
$content = 'content';
|
||||
|
||||
$result = $this->Rss->channel($attrib, $elements, $content);
|
||||
$expected = array(
|
||||
'channel' => array(
|
||||
'a' => '1',
|
||||
'b' => '2'
|
||||
),
|
||||
'<title',
|
||||
'title',
|
||||
'Title',
|
||||
'/title',
|
||||
'<link',
|
||||
$this->Rss->url('/', true),
|
||||
|
|
|
@ -1610,19 +1610,6 @@ TEXT;
|
|||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that setting arbitrary properties still works.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPropertySetting() {
|
||||
$this->assertFalse(isset($this->View->pageTitle));
|
||||
$this->View->pageTitle = 'test';
|
||||
$this->assertTrue(isset($this->View->pageTitle));
|
||||
$this->assertTrue(!empty($this->View->pageTitle));
|
||||
$this->assertEquals('test', $this->View->pageTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that setting arbitrary properties still works.
|
||||
*
|
||||
|
@ -1660,7 +1647,7 @@ TEXT;
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests that a vew block uses default value when not assigned and uses assigned value when it is
|
||||
* Tests that a view block uses default value when not assigned and uses assigned value when it is
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
@ -1674,4 +1661,20 @@ TEXT;
|
|||
$result = $this->View->fetch('title', $default);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a view variable uses default value when not assigned and uses assigned value when it is
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testViewVarDefaultValue() {
|
||||
$default = 'Default';
|
||||
$result = $this->View->get('title', $default);
|
||||
$this->assertEquals($default, $result);
|
||||
|
||||
$expected = 'Back to the Future';
|
||||
$this->View->set('title', $expected);
|
||||
$result = $this->View->get('title', $default);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ abstract class BaseCoverageReport {
|
|||
/**
|
||||
* Gets the base path that the files we are interested in live in.
|
||||
*
|
||||
* @return void
|
||||
* @return string Path
|
||||
*/
|
||||
public function getPathFilter() {
|
||||
$path = ROOT . DS;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
/**
|
||||
* Generates code coverage reports in HTML from data obtained from PHPUnit
|
||||
*
|
||||
* PHP5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
|
@ -28,9 +26,23 @@ App::uses('BaseCoverageReport', 'TestSuite/Coverage');
|
|||
class HtmlCoverageReport extends BaseCoverageReport {
|
||||
|
||||
/**
|
||||
* Generates report html to display.
|
||||
* Holds the total number of processed rows.
|
||||
*
|
||||
* @return string compiled html report.
|
||||
* @var integer
|
||||
*/
|
||||
protected $_total = 0;
|
||||
|
||||
/**
|
||||
* Holds the total number of covered rows.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $_covered = 0;
|
||||
|
||||
/**
|
||||
* Generates report HTML to display.
|
||||
*
|
||||
* @return string Compiled HTML report.
|
||||
*/
|
||||
public function report() {
|
||||
$pathFilter = $this->getPathFilter();
|
||||
|
@ -48,6 +60,12 @@ HTML;
|
|||
$fileData = file($file);
|
||||
$output .= $this->generateDiff($file, $fileData, $coverageData);
|
||||
}
|
||||
|
||||
$percentCovered = 100;
|
||||
if ($this->_total > 0) {
|
||||
$percentCovered = round(100 * $this->_covered / $this->_total, 2);
|
||||
}
|
||||
$output .= '<div class="total">Overall coverage: <span class="coverage">' . $percentCovered . '%</span></div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
@ -69,6 +87,8 @@ HTML;
|
|||
$diff = array();
|
||||
|
||||
list($covered, $total) = $this->_calculateCoveredLines($fileLines, $coverageData);
|
||||
$this->_covered += $covered;
|
||||
$this->_total += $total;
|
||||
|
||||
//shift line numbers forward one;
|
||||
array_unshift($fileLines, ' ');
|
||||
|
@ -121,13 +141,13 @@ HTML;
|
|||
}
|
||||
|
||||
/**
|
||||
* Renders the html for a single line in the html diff.
|
||||
* Renders the HTML for a single line in the HTML diff.
|
||||
*
|
||||
* @param string $line
|
||||
* @param integer $linenumber
|
||||
* @param string $class
|
||||
* @param array $coveringTests
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
protected function _paintLine($line, $linenumber, $class, $coveringTests) {
|
||||
$coveredBy = '';
|
||||
|
@ -150,7 +170,7 @@ HTML;
|
|||
/**
|
||||
* generate some javascript for the coverage report.
|
||||
*
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function coverageScript() {
|
||||
return <<<HTML
|
||||
|
@ -177,7 +197,7 @@ HTML;
|
|||
*
|
||||
* @param string $filename
|
||||
* @param string $percent
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function coverageHeader($filename, $percent) {
|
||||
$filename = basename($filename);
|
||||
|
|
|
@ -321,12 +321,14 @@ class Folder {
|
|||
* Returns $path with $element added, with correct slash in-between.
|
||||
*
|
||||
* @param string $path Path
|
||||
* @param string $element Element to and at end of path
|
||||
* @param string|array $element Element to add at end of path
|
||||
* @return string Combined path
|
||||
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::addPathElement
|
||||
*/
|
||||
public static function addPathElement($path, $element) {
|
||||
return rtrim($path, DS) . DS . $element;
|
||||
$element = (array)$element;
|
||||
array_unshift($element, rtrim($path, DS));
|
||||
return implode(DS, $element);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -111,12 +111,7 @@ class Hash {
|
|||
foreach ($tokens as $token) {
|
||||
$next = array();
|
||||
|
||||
$conditions = false;
|
||||
$position = strpos($token, '[');
|
||||
if ($position !== false) {
|
||||
$conditions = substr($token, $position);
|
||||
$token = substr($token, 0, $position);
|
||||
}
|
||||
list($token, $conditions) = self::_splitConditions($token);
|
||||
|
||||
foreach ($context[$_key] as $item) {
|
||||
foreach ((array)$item as $k => $v) {
|
||||
|
@ -141,6 +136,22 @@ class Hash {
|
|||
}
|
||||
return $context[$_key];
|
||||
}
|
||||
/**
|
||||
* Split token conditions
|
||||
*
|
||||
* @param string $token the token being splitted.
|
||||
* @return array array(token, conditions) with token splitted
|
||||
*/
|
||||
protected static function _splitConditions($token) {
|
||||
$conditions = false;
|
||||
$position = strpos($token, '[');
|
||||
if ($position !== false) {
|
||||
$conditions = substr($token, $position);
|
||||
$token = substr($token, 0, $position);
|
||||
}
|
||||
|
||||
return array($token, $conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a key against a token.
|
||||
|
@ -225,16 +236,30 @@ class Hash {
|
|||
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::insert
|
||||
*/
|
||||
public static function insert(array $data, $path, $values = null) {
|
||||
$tokens = explode('.', $path);
|
||||
if (strpos($path, '{') === false) {
|
||||
if (strpos($path, '[') === false) {
|
||||
$tokens = explode('.', $path);
|
||||
} else {
|
||||
$tokens = String::tokenize($path, '.', '[', ']');
|
||||
}
|
||||
|
||||
if (strpos($path, '{') === false && strpos($path, '[') === false) {
|
||||
return self::_simpleOp('insert', $data, $tokens, $values);
|
||||
}
|
||||
|
||||
$token = array_shift($tokens);
|
||||
$nextPath = implode('.', $tokens);
|
||||
|
||||
list($token, $conditions) = self::_splitConditions($token);
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
if (self::_matchToken($k, $token)) {
|
||||
$data[$k] = self::insert($v, $nextPath, $values);
|
||||
if ($conditions && self::_matches($v, $conditions)) {
|
||||
$data[$k] = array_merge($v, $values);
|
||||
continue;
|
||||
}
|
||||
if (!$conditions) {
|
||||
$data[$k] = self::insert($v, $nextPath, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
|
@ -294,17 +319,32 @@ class Hash {
|
|||
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::remove
|
||||
*/
|
||||
public static function remove(array $data, $path) {
|
||||
$tokens = explode('.', $path);
|
||||
if (strpos($path, '{') === false) {
|
||||
if (strpos($path, '[') === false) {
|
||||
$tokens = explode('.', $path);
|
||||
} else {
|
||||
$tokens = String::tokenize($path, '.', '[', ']');
|
||||
}
|
||||
|
||||
if (strpos($path, '{') === false && strpos($path, '[') === false) {
|
||||
return self::_simpleOp('remove', $data, $tokens);
|
||||
}
|
||||
|
||||
$token = array_shift($tokens);
|
||||
$nextPath = implode('.', $tokens);
|
||||
|
||||
list($token, $conditions) = self::_splitConditions($token);
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
$match = self::_matchToken($k, $token);
|
||||
if ($match && is_array($v)) {
|
||||
if ($conditions && self::_matches($v, $conditions)) {
|
||||
unset($data[$k]);
|
||||
continue;
|
||||
}
|
||||
$data[$k] = self::remove($v, $nextPath);
|
||||
if (empty($data[$k])) {
|
||||
unset($data[$k]);
|
||||
}
|
||||
} elseif ($match) {
|
||||
unset($data[$k]);
|
||||
}
|
||||
|
|
|
@ -289,4 +289,94 @@ class Security {
|
|||
return crypt($password, $salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a value using AES-256.
|
||||
*
|
||||
* *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes.
|
||||
* Any trailing null bytes will be removed on decryption due to how PHP pads messages
|
||||
* with nulls prior to encryption.
|
||||
*
|
||||
* @param string $plain The value to encrypt.
|
||||
* @param string $key The 256 bit/32 byte key to use as a cipher key.
|
||||
* @param string $hmacSalt The salt to use for the HMAC process. Leave null to use Security.salt.
|
||||
* @return string Encrypted data.
|
||||
* @throws CakeException On invalid data or key.
|
||||
*/
|
||||
public static function encrypt($plain, $key, $hmacSalt = null) {
|
||||
self::_checkKey($key, 'encrypt()');
|
||||
if (empty($plain)) {
|
||||
throw new CakeException(__d('cake_dev', 'The data to encrypt cannot be empty.'));
|
||||
}
|
||||
if ($hmacSalt === null) {
|
||||
$hmacSalt = Configure::read('Security.salt');
|
||||
}
|
||||
|
||||
// Generate the encryption and hmac key.
|
||||
$key = substr(hash('sha256', $key . $hmacSalt), 0, 32);
|
||||
|
||||
$algorithm = MCRYPT_RIJNDAEL_128;
|
||||
$mode = MCRYPT_MODE_CBC;
|
||||
|
||||
$ivSize = mcrypt_get_iv_size($algorithm, $mode);
|
||||
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
|
||||
$ciphertext = $iv . mcrypt_encrypt($algorithm, $key, $plain, $mode, $iv);
|
||||
$hmac = hash_hmac('sha256', $ciphertext, $key);
|
||||
return $hmac . $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the encryption key for proper length.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $method The method the key is being checked for.
|
||||
* @return void
|
||||
* @throws CakeException When key length is not 256 bit/32 bytes
|
||||
*/
|
||||
protected static function _checkKey($key, $method) {
|
||||
if (strlen($key) < 32) {
|
||||
throw new CakeException(__d('cake_dev', 'Invalid key for %s, key must be at least 256 bits (32 bytes) long.', $method));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a value using AES-256.
|
||||
*
|
||||
* @param string $cipher The ciphertext to decrypt.
|
||||
* @param string $key The 256 bit/32 byte key to use as a cipher key.
|
||||
* @param string $hmacSalt The salt to use for the HMAC process. Leave null to use Security.salt.
|
||||
* @return string Decrypted data. Any trailing null bytes will be removed.
|
||||
* @throws CakeException On invalid data or key.
|
||||
*/
|
||||
public static function decrypt($cipher, $key, $hmacSalt = null) {
|
||||
self::_checkKey($key, 'decrypt()');
|
||||
if (empty($cipher)) {
|
||||
throw new CakeException(__d('cake_dev', 'The data to decrypt cannot be empty.'));
|
||||
}
|
||||
if ($hmacSalt === null) {
|
||||
$hmacSalt = Configure::read('Security.salt');
|
||||
}
|
||||
|
||||
// Generate the encryption and hmac key.
|
||||
$key = substr(hash('sha256', $key . $hmacSalt), 0, 32);
|
||||
|
||||
// Split out hmac for comparison
|
||||
$macSize = 64;
|
||||
$hmac = substr($cipher, 0, $macSize);
|
||||
$cipher = substr($cipher, $macSize);
|
||||
|
||||
$compareHmac = hash_hmac('sha256', $cipher, $key);
|
||||
if ($hmac !== $compareHmac) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$algorithm = MCRYPT_RIJNDAEL_128;
|
||||
$mode = MCRYPT_MODE_CBC;
|
||||
$ivSize = mcrypt_get_iv_size($algorithm, $mode);
|
||||
|
||||
$iv = substr($cipher, 0, $ivSize);
|
||||
$cipher = substr($cipher, $ivSize);
|
||||
$plain = mcrypt_decrypt($algorithm, $key, $cipher, $mode, $iv);
|
||||
return rtrim($plain, "\0");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -540,7 +540,7 @@ class Validation {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validate a multiple select.
|
||||
* Validate a multiple select. Comparison is case sensitive by default.
|
||||
*
|
||||
* Valid Options
|
||||
*
|
||||
|
@ -550,12 +550,13 @@ class Validation {
|
|||
*
|
||||
* @param array $check Value to check
|
||||
* @param array $options Options for the check.
|
||||
* @param boolean $strict Defaults to true, set to false to disable strict type check
|
||||
* @param boolean $caseInsensitive Set to true for case insensitive comparison.
|
||||
* @return boolean Success
|
||||
*/
|
||||
public static function multiple($check, $options = array(), $strict = true) {
|
||||
public static function multiple($check, $options = array(), $caseInsensitive = false) {
|
||||
$defaults = array('in' => null, 'max' => null, 'min' => null);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$check = array_filter((array)$check);
|
||||
if (empty($check)) {
|
||||
return false;
|
||||
|
@ -567,8 +568,15 @@ class Validation {
|
|||
return false;
|
||||
}
|
||||
if ($options['in'] && is_array($options['in'])) {
|
||||
if ($caseInsensitive) {
|
||||
$options['in'] = array_map('mb_strtolower', $options['in']);
|
||||
}
|
||||
foreach ($check as $val) {
|
||||
if (!in_array($val, $options['in'], $strict)) {
|
||||
$strict = !is_numeric($val);
|
||||
if ($caseInsensitive) {
|
||||
$val = mb_strtolower($val);
|
||||
}
|
||||
if (!in_array((string)$val, $options['in'], $strict)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -766,15 +774,22 @@ class Validation {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is in a given list.
|
||||
* Checks if a value is in a given list. Comparison is case sensitive by default.
|
||||
*
|
||||
* @param string $check Value to check
|
||||
* @param array $list List to check against
|
||||
* @param boolean $strict Defaults to true, set to false to disable strict type check
|
||||
* @return boolean Success
|
||||
* @param string $check Value to check.
|
||||
* @param array $list List to check against.
|
||||
* @param boolean $caseInsensitive Set to true for case insensitive comparison.
|
||||
* @return boolean Success.
|
||||
*/
|
||||
public static function inList($check, $list, $strict = true) {
|
||||
return in_array($check, $list, $strict);
|
||||
public static function inList($check, $list, $caseInsensitive = false) {
|
||||
$strict = !is_numeric($check);
|
||||
|
||||
if ($caseInsensitive) {
|
||||
$list = array_map('mb_strtolower', $list);
|
||||
$check = mb_strtolower($check);
|
||||
}
|
||||
|
||||
return in_array((string)$check, $list, $strict);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -896,7 +911,7 @@ class Validation {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks the mime type of a file
|
||||
* Checks the mime type of a file. Comparison is case sensitive.
|
||||
*
|
||||
* @param string|array $check
|
||||
* @param array $mimeTypes to check for
|
||||
|
|
|
@ -17,4 +17,4 @@
|
|||
// @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
// +--------------------------------------------------------------------------------------------+ //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
2.4.1
|
||||
2.5.0-dev
|
||||
|
|
|
@ -123,12 +123,12 @@ class RssHelper extends AppHelper {
|
|||
* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/rss.html#RssHelper::channel
|
||||
*/
|
||||
public function channel($attrib = array(), $elements = array(), $content = null) {
|
||||
if (!isset($elements['title']) && !empty($this->_View->pageTitle)) {
|
||||
$elements['title'] = $this->_View->pageTitle;
|
||||
}
|
||||
if (!isset($elements['link'])) {
|
||||
$elements['link'] = '/';
|
||||
}
|
||||
if (!isset($elements['title'])) {
|
||||
$elements['title'] = '';
|
||||
}
|
||||
if (!isset($elements['description'])) {
|
||||
$elements['description'] = '';
|
||||
}
|
||||
|
|
|
@ -584,11 +584,12 @@ class View extends Object {
|
|||
* Blocks are checked before view variables.
|
||||
*
|
||||
* @param string $var The view var you want the contents of.
|
||||
* @return mixed The content of the named var if its set, otherwise null.
|
||||
* @param mixed $default The default/fallback content of $var.
|
||||
* @return mixed The content of the named var if its set, otherwise $default.
|
||||
*/
|
||||
public function get($var) {
|
||||
public function get($var, $default = null) {
|
||||
if (!isset($this->viewVars[$var])) {
|
||||
return null;
|
||||
return $default;
|
||||
}
|
||||
return $this->viewVars[$var];
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ if (!function_exists('debug')) {
|
|||
*
|
||||
* Only runs if debug level is greater than zero.
|
||||
*
|
||||
* @param boolean $var Variable to show debug information for.
|
||||
* @param mixed $var Variable to show debug information for.
|
||||
* @param boolean $showHtml If set to true, the method prints the debug data in a browser-friendly way.
|
||||
* @param boolean $showFrom If set to true, the method prints from where the function was called.
|
||||
* @return void
|
||||
|
|
Loading…
Reference in a new issue