Merge pull request #1 from cakephp/master

Update to the new version of CakePHP
This commit is contained in:
Esteban Zeller 2014-12-23 17:17:58 -03:00
commit aaf65df266
113 changed files with 3006 additions and 625 deletions

View file

@ -70,6 +70,12 @@ Cache::config('default', array('engine' => 'File'));
*
*/
/**
* To prefer app translation over plugin translation, you can set
*
* Configure::write('I18n.preferApp', true);
*/
/**
* You can attach event listeners to the request lifecycle as Dispatcher Filter. By default CakePHP bundles two filters:
*

View file

@ -50,6 +50,10 @@
* For MySQL, Postgres specifies the character encoding to use when connecting to the
* database. Uses database default not specified.
*
* sslmode =>
* For Postgres specifies whether to 'disable', 'allow', 'prefer', or 'require' SSL for the
* connection. The default value is 'allow'.
*
* unix_socket =>
* For MySQL to connect via socket specify the `unix_socket` parameter instead of `host` and `port`
*

View file

@ -26,7 +26,7 @@ if (!defined('DS')) {
}
/**
* These defines should only be edited if you have cake installed in
* These defines should only be edited if you have CakePHP installed in
* a directory layout other than the way it is distributed.
* When using custom settings be sure to use the DS and do not add a trailing DS.
*/
@ -63,6 +63,16 @@ if (!defined('APP_DIR')) {
*/
//define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib');
/**
* This auto-detects CakePHP as a composer installed library.
* You may remove this if you are not planning to use composer (not recommended, though).
*/
$vendorPath = ROOT . DS . APP_DIR . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php';
if (!defined('CAKE_CORE_INCLUDE_PATH') && file_exists($vendorPath . DS . $dispatcher)) {
define('CAKE_CORE_INCLUDE_PATH', $vendorPath);
}
/**
* Editing below this line should NOT be necessary.
* Change at your own risk.

View file

@ -27,7 +27,7 @@ if (!defined('DS')) {
}
/**
* These defines should only be edited if you have cake installed in
* These defines should only be edited if you have CakePHP installed in
* a directory layout other than the way it is distributed.
* When using custom settings be sure to use the DS and do not add a trailing DS.
*/
@ -61,6 +61,16 @@ if (!defined('APP_DIR')) {
*/
//define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib');
/**
* This auto-detects CakePHP as a composer installed library.
* You may remove this if you are not planning to use composer (not recommended, though).
*/
$vendorPath = ROOT . DS . APP_DIR . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php';
if (!defined('CAKE_CORE_INCLUDE_PATH') && file_exists($vendorPath . DS . $dispatcher)) {
define('CAKE_CORE_INCLUDE_PATH', $vendorPath);
}
/**
* Editing below this line should not be necessary.
* Change at your own risk.

View file

@ -45,6 +45,8 @@ class MemcachedEngine extends CacheEngine {
* - 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.
* - options - Additional options for the memcached client. Should be an array of option => value.
* Use the Memcached::OPT_* constants as keys.
*
* @var array
*/
@ -92,7 +94,8 @@ class MemcachedEngine extends CacheEngine {
'persistent' => false,
'login' => null,
'password' => null,
'serialize' => 'php'
'serialize' => 'php',
'options' => array()
);
parent::init($settings);
@ -133,6 +136,11 @@ class MemcachedEngine extends CacheEngine {
$this->_Memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$this->_Memcached->setSaslAuthData($this->settings['login'], $this->settings['password']);
}
if (is_array($this->settings['options'])) {
foreach ($this->settings['options'] as $opt => $value) {
$this->_Memcached->setOption($opt, $value);
}
}
return true;
}

View file

@ -59,7 +59,7 @@ class RedisEngine extends CacheEngine {
}
parent::init(array_merge(array(
'engine' => 'Redis',
'prefix' => null,
'prefix' => Inflector::slug(APP_DIR) . '_',
'server' => '127.0.0.1',
'database' => 0,
'port' => 6379,
@ -79,7 +79,6 @@ class RedisEngine extends CacheEngine {
* @return bool True if Redis server was connected
*/
protected function _connect() {
$return = false;
try {
$this->_Redis = new Redis();
if (!empty($this->settings['unix_socket'])) {
@ -91,15 +90,15 @@ class RedisEngine extends CacheEngine {
$return = $this->_Redis->pconnect($this->settings['server'], $this->settings['port'], $this->settings['timeout'], $persistentId);
}
} catch (RedisException $e) {
$return = false;
}
if (!$return) {
return false;
}
if ($return && $this->settings['password']) {
$return = $this->_Redis->auth($this->settings['password']);
if ($this->settings['password'] && !$this->_Redis->auth($this->settings['password'])) {
return false;
}
if ($return) {
$return = $this->_Redis->select($this->settings['database']);
}
return $return;
return $this->_Redis->select($this->settings['database']);
}
/**

View file

@ -48,8 +48,8 @@ if ($plugins = CakePlugin::loaded()) {
$plugins[$key] = Inflector::underscore($value);
}
$pluginPattern = implode('|', $plugins);
$match = array('plugin' => $pluginPattern);
$shortParams = array('routeClass' => 'PluginShortRoute', 'plugin' => $pluginPattern);
$match = array('plugin' => $pluginPattern, 'defaultRoute' => true);
$shortParams = array('routeClass' => 'PluginShortRoute', 'plugin' => $pluginPattern, 'defaultRoute' => true);
foreach ($prefixes as $prefix) {
$params = array('prefix' => $prefix, $prefix => true);
@ -66,11 +66,11 @@ if ($plugins = CakePlugin::loaded()) {
foreach ($prefixes as $prefix) {
$params = array('prefix' => $prefix, $prefix => true);
$indexParams = $params + array('action' => 'index');
Router::connect("/{$prefix}/:controller", $indexParams);
Router::connect("/{$prefix}/:controller/:action/*", $params);
Router::connect("/{$prefix}/:controller", $indexParams, array('defaultRoute' => true));
Router::connect("/{$prefix}/:controller/:action/*", $params, array('defaultRoute' => true));
}
Router::connect('/:controller', array('action' => 'index'));
Router::connect('/:controller/:action/*');
Router::connect('/:controller', array('action' => 'index'), array('defaultRoute' => true));
Router::connect('/:controller/:action/*', array(), array('defaultRoute' => true));
$namedConfig = Router::namedConfig();
if ($namedConfig['rules'] === false) {
@ -79,3 +79,4 @@ if ($namedConfig['rules'] === false) {
unset($namedConfig, $params, $indexParams, $prefix, $prefixes, $shortParams, $match,
$pluginPattern, $plugins, $key, $value);

View file

@ -334,8 +334,7 @@ class SchemaShell extends AppShell {
$this->out("\n" . __d('cake_console', 'The following table(s) will be dropped.'));
$this->out(array_keys($drop));
if (
!empty($this->params['yes']) ||
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).'));
@ -345,8 +344,7 @@ class SchemaShell extends AppShell {
$this->out("\n" . __d('cake_console', 'The following table(s) will be created.'));
$this->out(array_keys($create));
if (
!empty($this->params['yes']) ||
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).'));
@ -399,8 +397,7 @@ class SchemaShell extends AppShell {
$this->out("\n" . __d('cake_console', 'The following statements will run.'));
$this->out(array_map('trim', $contents));
if (
!empty($this->params['yes']) ||
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();

View file

@ -251,13 +251,17 @@ class ExtractTask extends AppShell {
protected function _addTranslation($category, $domain, $msgid, $details = array()) {
if (empty($this->_translations[$category][$domain][$msgid])) {
$this->_translations[$category][$domain][$msgid] = array(
'msgid_plural' => false
'msgid_plural' => false,
'msgctxt' => ''
);
}
if (isset($details['msgid_plural'])) {
$this->_translations[$category][$domain][$msgid]['msgid_plural'] = $details['msgid_plural'];
}
if (isset($details['msgctxt'])) {
$this->_translations[$category][$domain][$msgid]['msgctxt'] = $details['msgctxt'];
}
if (isset($details['file'])) {
$line = 0;
@ -355,14 +359,14 @@ class ExtractTask extends AppShell {
protected function _extractTokens() {
foreach ($this->_files as $file) {
$this->_file = $file;
$this->out(__d('cake_console', 'Processing %s...', $file));
$this->out(__d('cake_console', 'Processing %s...', $file), 1, Shell::VERBOSE);
$code = file_get_contents($file);
$allTokens = token_get_all($code);
$this->_tokens = array();
foreach ($allTokens as $token) {
if (!is_array($token) || ($token[0] != T_WHITESPACE && $token[0] != T_INLINE_HTML)) {
if (!is_array($token) || ($token[0] !== T_WHITESPACE && $token[0] !== T_INLINE_HTML)) {
$this->_tokens[] = $token;
}
}
@ -374,6 +378,15 @@ class ExtractTask extends AppShell {
$this->_parse('__dc', array('domain', 'singular', 'category'));
$this->_parse('__dn', array('domain', 'singular', 'plural'));
$this->_parse('__dcn', array('domain', 'singular', 'plural', 'count', 'category'));
$this->_parse('__x', array('context', 'singular'));
$this->_parse('__xn', array('context', 'singular', 'plural'));
$this->_parse('__dx', array('domain', 'context', 'singular'));
$this->_parse('__dxc', array('domain', 'context', 'singular', 'category'));
$this->_parse('__dxn', array('domain', 'context', 'singular', 'plural'));
$this->_parse('__dxcn', array('domain', 'context', 'singular', 'plural', 'count', 'category'));
$this->_parse('__xc', array('context', 'singular', 'category'));
}
}
@ -427,6 +440,9 @@ class ExtractTask extends AppShell {
if (isset($plural)) {
$details['msgid_plural'] = $plural;
}
if (isset($context)) {
$details['msgctxt'] = $context;
}
$this->_addTranslation($categoryName, $domain, $singular, $details);
} else {
$this->_markerError($this->_file, $line, $functionName, $count);
@ -551,6 +567,7 @@ class ExtractTask extends AppShell {
foreach ($domains as $domain => $translations) {
foreach ($translations as $msgid => $details) {
$plural = $details['msgid_plural'];
$context = $details['msgctxt'];
$files = $details['references'];
$occurrences = array();
foreach ($files as $file => $lines) {
@ -560,11 +577,15 @@ class ExtractTask extends AppShell {
$occurrences = implode("\n#: ", $occurrences);
$header = '#: ' . str_replace(DS, '/', str_replace($paths, '', $occurrences)) . "\n";
$sentence = '';
if ($context) {
$sentence .= "msgctxt \"{$context}\"\n";
}
if ($plural === false) {
$sentence = "msgid \"{$msgid}\"\n";
$sentence .= "msgid \"{$msgid}\"\n";
$sentence .= "msgstr \"\"\n\n";
} else {
$sentence = "msgid \"{$msgid}\"\n";
$sentence .= "msgid \"{$msgid}\"\n";
$sentence .= "msgid_plural \"{$plural}\"\n";
$sentence .= "msgstr[0] \"\"\n";
$sentence .= "msgstr[1] \"\"\n\n";

View file

@ -242,8 +242,8 @@ class FixtureTask extends BakeTask {
$this->_Schema = new CakeSchema();
$data = $this->_Schema->read(array('models' => false, 'connection' => $this->connection));
if (!isset($data['tables'][$useTable])) {
$this->error('Could not find your selected table ' . $useTable);
return false;
$this->err("<warning>Warning:</warning> Could not find the '${useTable}' table for ${model}.");
return;
}
$tableInfo = $data['tables'][$useTable];

View file

@ -926,7 +926,7 @@ class ModelTask extends BakeTask {
$tableIsGood = $this->in(__d('cake_console', 'Do you want to use this table?'), array('y', 'n'), 'y');
}
if (strtolower($tableIsGood) === 'n') {
$useTable = $this->in(__d('cake_console', 'What is the name of the table?'));
$useTable = $this->in(__d('cake_console', 'What is the name of the table (without prefix)?'));
}
}
return $useTable;

View file

@ -108,18 +108,25 @@ class PluginTask extends AppShell {
$Folder = new Folder($this->path . $plugin);
$directories = array(
'Config' . DS . 'Schema',
'Model' . DS . 'Behavior',
'Model' . DS . 'Datasource',
'Console' . DS . 'Command' . DS . 'Task',
'Console' . DS . 'Templates',
'Controller' . DS . 'Component',
'Lib',
'View' . DS . 'Helper',
'Locale' . DS . 'eng' . DS . 'LC_MESSAGES',
'Model' . DS . 'Behavior',
'Model' . DS . 'Datasource',
'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component',
'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
'Test' . DS . 'Case' . DS . 'Lib',
'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior',
'Test' . DS . 'Case' . DS . 'Model' . DS . 'Datasource',
'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
'Test' . DS . 'Fixture',
'Vendor',
'webroot'
'View' . DS . 'Elements',
'View' . DS . 'Helper',
'View' . DS . 'Layout',
'webroot' . DS . 'css',
'webroot' . DS . 'js',
'webroot' . DS . 'img',
);
foreach ($directories as $directory) {

View file

@ -410,6 +410,17 @@ class ConsoleOptionParser {
return $this;
}
/**
* Remove a subcommand from the option parser.
*
* @param string $name The subcommand name to remove.
* @return $this
*/
public function removeSubcommand($name) {
unset($this->_subcommands[$name]);
return $this;
}
/**
* Add multiple subcommands at once.
*
@ -510,8 +521,7 @@ class ConsoleOptionParser {
* @return string Generated help.
*/
public function help($subcommand = null, $format = 'text', $width = 72) {
if (
isset($this->_subcommands[$subcommand]) &&
if (isset($this->_subcommands[$subcommand]) &&
$this->_subcommands[$subcommand]->parser() instanceof self
) {
$subparser = $this->_subcommands[$subcommand]->parser();

View file

@ -161,8 +161,7 @@ class ConsoleOutput {
public function __construct($stream = 'php://stdout') {
$this->_output = fopen($stream, 'w');
if (
(DS === '\\' && !(bool)env('ANSICON')) ||
if ((DS === '\\' && !(bool)env('ANSICON')) ||
(function_exists('posix_isatty') && !posix_isatty($this->_output))
) {
$this->_outputAs = self::PLAIN;

View file

@ -167,6 +167,14 @@ class Shell extends Object {
*/
public $stdin;
/**
* The number of bytes last written to the output stream
* used when overwriting the previous message.
*
* @var int
*/
protected $_lastWritten = 0;
/**
* Constructs this Shell instance.
*
@ -609,11 +617,44 @@ class Shell extends Object {
$currentLevel = Shell::QUIET;
}
if ($level <= $currentLevel) {
return $this->stdout->write($message, $newlines);
$this->_lastWritten = $this->stdout->write($message, $newlines);
return $this->_lastWritten;
}
return true;
}
/**
* Overwrite some already output text.
*
* Useful for building progress bars, or when you want to replace
* text already output to the screen with new text.
*
* **Warning** You cannot overwrite text that contains newlines.
*
* @param array|string $message The message to output.
* @param int $newlines Number of newlines to append.
* @param int $size The number of bytes to overwrite. Defaults to the
* length of the last message output.
* @return int|bool Returns the number of bytes returned from writing to stdout.
*/
public function overwrite($message, $newlines = 1, $size = null) {
$size = $size ? $size : $this->_lastWritten;
// Output backspaces.
$this->out(str_repeat("\x08", $size), 0);
$newBytes = $this->out($message, 0);
// Fill any remaining bytes with spaces.
$fill = $size - $newBytes;
if ($fill > 0) {
$this->out(str_repeat(' ', $fill), 0);
}
if ($newlines) {
$this->out($this->nl($newlines), 0);
}
}
/**
* Outputs a single or multiple error messages to stderr. If no parameters
* are passed outputs just a newline.

View file

@ -54,6 +54,16 @@ if (!defined('APP_DIR')) {
*/
//define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__);
/**
* This auto-detects CakePHP as a composer installed library.
* You may remove this if you are not planning to use composer (not recommended, though).
*/
$vendorPath = ROOT . DS . APP_DIR . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php';
if (!defined('CAKE_CORE_INCLUDE_PATH') && file_exists($vendorPath . DS . $dispatcher)) {
define('CAKE_CORE_INCLUDE_PATH', $vendorPath);
}
/**
* Editing below this line should NOT be necessary.
* Change at your own risk.

View file

@ -18,7 +18,7 @@ if (!defined('DS')) {
}
/**
* These defines should only be edited if you have cake installed in
* These defines should only be edited if you have CakePHP installed in
* a directory layout other than the way it is distributed.
* When using custom settings be sure to use the DS and do not add a trailing DS.
*/
@ -52,6 +52,16 @@ if (!defined('APP_DIR')) {
*/
//define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__);
/**
* This auto-detects CakePHP as a composer installed library.
* You may remove this if you are not planning to use composer (not recommended, though).
*/
$vendorPath = ROOT . DS . APP_DIR . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php';
if (!defined('CAKE_CORE_INCLUDE_PATH') && file_exists($vendorPath . DS . $dispatcher)) {
define('CAKE_CORE_INCLUDE_PATH', $vendorPath);
}
/**
* Editing below this line should not be necessary.
* Change at your own risk.

View file

@ -14,19 +14,21 @@
App::uses('Security', 'Utility');
App::uses('Hash', 'Utility');
App::uses('CakeEventListener', 'Event');
/**
* Base Authentication class with common methods and properties.
*
* @package Cake.Controller.Component.Auth
*/
abstract class BaseAuthenticate {
abstract class BaseAuthenticate implements CakeEventListener {
/**
* Settings for this object.
*
* - `fields` The fields to use to identify a user by.
* - `userModel` The model name of the User, defaults to User.
* - `userFields` Array of fields to retrieve from User model, null to retrieve all. Defaults to null.
* - `scope` Additional conditions to use when looking up and authenticating users,
* i.e. `array('User.is_active' => 1).`
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
@ -43,6 +45,7 @@ abstract class BaseAuthenticate {
'password' => 'password'
),
'userModel' => 'User',
'userFields' => null,
'scope' => array(),
'recursive' => 0,
'contain' => null,
@ -63,6 +66,15 @@ abstract class BaseAuthenticate {
*/
protected $_passwordHasher;
/**
* Implemented events
*
* @return array of events => callbacks.
*/
public function implementedEvents() {
return array();
}
/**
* Constructor
*
@ -105,9 +117,15 @@ abstract class BaseAuthenticate {
$conditions = array_merge($conditions, $this->settings['scope']);
}
$userFields = $this->settings['userFields'];
if ($password !== null && $userFields !== null) {
$userFields[] = $model . '.' . $fields['password'];
}
$result = ClassRegistry::init($userModel)->find('first', array(
'conditions' => $conditions,
'recursive' => $this->settings['recursive'],
'fields' => $userFields,
'contain' => $this->settings['contain'],
));
if (empty($result[$model])) {

View file

@ -60,6 +60,7 @@ class DigestAuthenticate extends BasicAuthenticate {
*
* - `fields` The fields to use to identify a user by.
* - `userModel` The model name of the User, defaults to User.
* - `userFields` Array of fields to retrieve from User model, null to retrieve all. Defaults to null.
* - `scope` Additional conditions to use when looking up and authenticating users,
* i.e. `array('User.is_active' => 1).`
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
@ -78,6 +79,7 @@ class DigestAuthenticate extends BasicAuthenticate {
'password' => 'password'
),
'userModel' => 'User',
'userFields' => null,
'scope' => array(),
'recursive' => 0,
'contain' => null,

View file

@ -26,6 +26,7 @@ App::uses('Hash', 'Utility');
App::uses('CakeSession', 'Model/Datasource');
App::uses('BaseAuthorize', 'Controller/Component/Auth');
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
App::uses('CakeEvent', 'Event');
/**
* Authentication control component class
@ -572,13 +573,18 @@ class AuthComponent extends Component {
* @return void
* @see BaseAuthorize::mapActions()
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#mapping-actions-when-using-crudauthorize
* @deprecated 3.0.0 Map actions using `actionMap` config key on authorize objects instead
*/
public function mapActions($map = array()) {
if (empty($this->_authorizeObjects)) {
$this->constructAuthorize();
}
$mappedActions = array();
foreach ($this->_authorizeObjects as $auth) {
$auth->mapActions($map);
$mappedActions = Hash::merge($mappedActions, $auth->mapActions($map));
}
if (empty($map)) {
return $mappedActions;
}
}
@ -603,6 +609,8 @@ class AuthComponent extends Component {
if ($user) {
$this->Session->renew();
$this->Session->write(self::$sessionKey, $user);
$event = new CakeEvent('Auth.afterIdentify', $this, array('user' => $user));
$this->_Collection->getController()->getEventManager()->dispatch($event);
}
return (bool)$this->user();
}
@ -791,7 +799,9 @@ class AuthComponent extends Component {
throw new CakeException(__d('cake_dev', 'Authentication objects must implement an %s method.', 'authenticate()'));
}
$settings = array_merge($global, (array)$settings);
$this->_authenticateObjects[] = new $className($this->_Collection, $settings);
$auth = new $className($this->_Collection, $settings);
$this->_Collection->getController()->getEventManager()->attach($auth);
$this->_authenticateObjects[] = $auth;
}
return $this->_authenticateObjects;
}

View file

@ -240,8 +240,7 @@ class PaginatorComponent extends Component {
throw new NotFoundException();
}
if (
!in_array('Paginator', $this->Controller->helpers) &&
if (!in_array('Paginator', $this->Controller->helpers) &&
!array_key_exists('Paginator', $this->Controller->helpers)
) {
$this->Controller->helpers[] = 'Paginator';

View file

@ -355,7 +355,7 @@ class SecurityComponent extends Component {
* Check if HTTP methods are required
*
* @param Controller $controller Instantiating controller
* @return bool|null True if $method is required
* @return bool True if $method is required
*/
protected function _methodsRequired(Controller $controller) {
foreach (array('Post', 'Get', 'Put', 'Delete') as $method) {
@ -365,7 +365,7 @@ class SecurityComponent extends Component {
if (in_array($this->_action, $require) || $this->$property === array('*')) {
if (!$this->request->is($method)) {
if (!$this->blackHole($controller, $method)) {
return null;
return false;
}
}
}
@ -378,7 +378,7 @@ class SecurityComponent extends Component {
* Check if access requires secure connection
*
* @param Controller $controller Instantiating controller
* @return bool|null True if secure connection required
* @return bool True if secure connection required
*/
protected function _secureRequired(Controller $controller) {
if (is_array($this->requireSecure) && !empty($this->requireSecure)) {
@ -387,7 +387,7 @@ class SecurityComponent extends Component {
if (in_array($this->_action, $requireSecure) || $this->requireSecure === array('*')) {
if (!$this->request->is('ssl')) {
if (!$this->blackHole($controller, 'secure')) {
return null;
return false;
}
}
}
@ -415,8 +415,7 @@ class SecurityComponent extends Component {
if ($this->Session->check('_Token')) {
$tData = $this->Session->read('_Token');
if (
!empty($tData['allowedControllers']) &&
if (!empty($tData['allowedControllers']) &&
!in_array($this->request->params['controller'], $tData['allowedControllers']) ||
!empty($tData['allowedActions']) &&
!in_array($this->request->params['action'], $tData['allowedActions'])

View file

@ -361,7 +361,7 @@ class App {
* @param string $plugin CamelCased/lower_cased plugin name to find the path of.
* @return string full path to the plugin.
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::pluginPath
* @deprecated 3.0.0 Use CakePlugin::path() instead.
* @deprecated 3.0.0 Use `CakePlugin::path()` instead.
*/
public static function pluginPath($plugin) {
return CakePlugin::path($plugin);

View file

@ -197,8 +197,7 @@ class Object {
protected function _mergeVars($properties, $class, $normalize = true) {
$classProperties = get_class_vars($class);
foreach ($properties as $var) {
if (
isset($classProperties[$var]) &&
if (isset($classProperties[$var]) &&
!empty($classProperties[$var]) &&
is_array($this->{$var}) &&
$this->{$var} != $classProperties[$var]

View file

@ -153,9 +153,20 @@ class ExceptionRenderer {
try {
$controller = new CakeErrorController($request, $response);
$controller->startupProcess();
$startup = true;
} catch (Exception $e) {
if (!empty($controller) && $controller->Components->enabled('RequestHandler')) {
$startup = false;
}
// Retry RequestHandler, as another aspect of startupProcess()
// could have failed. Ignore any exceptions out of startup, as
// there could be userland input data parsers.
if ($startup === false &&
!empty($controller) &&
$controller->Components->enabled('RequestHandler')
) {
try {
$controller->RequestHandler->startup($controller);
} catch (Exception $e) {
}
}
}

View file

@ -188,10 +188,13 @@ class I18n {
* @param int $count Count Count is used with $plural to choose the correct plural form.
* @param string $language Language to translate string to.
* If null it checks for language in session followed by Config.language configuration variable.
* @param string $context Context The context of the translation, e.g a verb or a noun.
* @return string translated string.
* @throws CakeException When '' is provided as a domain.
*/
public static function translate($singular, $plural = null, $domain = null, $category = self::LC_MESSAGES, $count = null, $language = null) {
public static function translate($singular, $plural = null, $domain = null, $category = self::LC_MESSAGES,
$count = null, $language = null, $context = null
) {
$_this = I18n::getInstance();
if (strpos($singular, "\r\n") !== false) {
@ -254,8 +257,10 @@ class I18n {
}
}
if (!empty($_this->_domains[$domain][$_this->_lang][$_this->category][$singular])) {
if (($trans = $_this->_domains[$domain][$_this->_lang][$_this->category][$singular]) || ($plurals) && ($trans = $_this->_domains[$domain][$_this->_lang][$_this->category][$plural])) {
if (!empty($_this->_domains[$domain][$_this->_lang][$_this->category][$singular][$context])) {
if (($trans = $_this->_domains[$domain][$_this->_lang][$_this->category][$singular][$context]) ||
($plurals) && ($trans = $_this->_domains[$domain][$_this->_lang][$_this->category][$plural][$context])
) {
if (is_array($trans)) {
if (isset($trans[$plurals])) {
$trans = $trans[$plurals];
@ -311,6 +316,8 @@ class I18n {
* @param string $header Type
* @param int $n Number
* @return int plural match
* @link http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html
* @link https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals#List_of_Plural_Rules
*/
protected function _pluralGuess($header, $n) {
if (!is_string($header) || $header === "nplurals=1;plural=0;" || !isset($header[0])) {
@ -351,7 +358,15 @@ class I18n {
}
} elseif (strpos($header, "plurals=5")) {
return $n == 1 ? 0 : ($n == 2 ? 1 : ($n >= 3 && $n <= 6 ? 2 : ($n >= 7 && $n <= 10 ? 3 : 4)));
} elseif (strpos($header, "plurals=6")) {
return $n == 0 ? 0 :
($n == 1 ? 1 :
($n == 2 ? 2 :
($n % 100 >= 3 && $n % 100 <= 10 ? 3 :
($n % 100 >= 11 ? 4 : 5))));
}
return 0;
}
/**
@ -372,7 +387,9 @@ class I18n {
$pluginDomain = Inflector::underscore($plugin);
if ($pluginDomain === $domain) {
$searchPaths[] = CakePlugin::path($plugin) . 'Locale' . DS;
$searchPaths = array_reverse($searchPaths);
if (!Configure::read('I18n.preferApp')) {
$searchPaths = array_reverse($searchPaths);
}
break;
}
}
@ -469,6 +486,7 @@ class I18n {
// Binary files extracted makes non-standard local variables
if ($data = file_get_contents($filename)) {
$translations = array();
$context = null;
$header = substr($data, 0, 20);
$header = unpack('L1magic/L1version/L1count/L1o_msg/L1o_trn', $header);
extract($header);
@ -488,6 +506,10 @@ class I18n {
if (strpos($msgstr, "\000")) {
$msgstr = explode("\000", $msgstr);
}
if ($msgid != '') {
$msgstr = array($context => $msgstr);
}
$translations[$msgid] = $msgstr;
if (isset($msgid_plural)) {
@ -515,12 +537,15 @@ class I18n {
$type = 0;
$translations = array();
$translationKey = '';
$translationContext = null;
$plural = 0;
$header = '';
do {
$line = trim(fgets($file));
if ($line === '' || $line[0] === '#') {
$translationContext = null;
continue;
}
if (preg_match("/msgid[[:space:]]+\"(.+)\"$/i", $line, $regs)) {
@ -529,31 +554,33 @@ class I18n {
} elseif (preg_match("/msgid[[:space:]]+\"\"$/i", $line, $regs)) {
$type = 2;
$translationKey = '';
} elseif (preg_match("/msgctxt[[:space:]]+\"(.+)\"$/i", $line, $regs)) {
$translationContext = $regs[1];
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && ($type == 1 || $type == 2 || $type == 3)) {
$type = 3;
$translationKey .= stripcslashes($regs[1]);
} elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
$translations[$translationKey] = stripcslashes($regs[1]);
$translations[$translationKey][$translationContext] = stripcslashes($regs[1]);
$type = 4;
} elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
$type = 4;
$translations[$translationKey] = '';
$translations[$translationKey][$translationContext] = '';
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 4 && $translationKey) {
$translations[$translationKey] .= stripcslashes($regs[1]);
$translations[$translationKey][$translationContext] .= stripcslashes($regs[1]);
} elseif (preg_match("/msgid_plural[[:space:]]+\".*\"$/i", $line, $regs)) {
$type = 6;
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 6 && $translationKey) {
$type = 6;
} elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
$plural = $regs[1];
$translations[$translationKey][$plural] = stripcslashes($regs[2]);
$translations[$translationKey][$translationContext][$plural] = stripcslashes($regs[2]);
$type = 7;
} elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
$plural = $regs[1];
$translations[$translationKey][$plural] = '';
$translations[$translationKey][$translationContext][$plural] = '';
$type = 7;
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 7 && $translationKey) {
$translations[$translationKey][$plural] .= stripcslashes($regs[1]);
$translations[$translationKey][$translationContext][$plural] .= stripcslashes($regs[1]);
} elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && $type == 2 && !$translationKey) {
$header .= stripcslashes($regs[1]);
$type = 5;
@ -563,9 +590,10 @@ class I18n {
} elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 5) {
$header .= stripcslashes($regs[1]);
} else {
unset($translations[$translationKey]);
unset($translations[$translationKey][$translationContext]);
$type = 0;
$translationKey = '';
$translationContext = null;
$plural = 0;
}
} while (!feof($file));
@ -643,6 +671,27 @@ class I18n {
return $definitions;
}
/**
* Puts the parameters in raw translated strings
*
* @param string $translated The raw translated string
* @param array $args The arguments to put in the translation
* @return string Translated string with arguments
*/
public static function insertArgs($translated, array $args) {
$len = count($args);
if ($len === 0 || ($len === 1 && $args[0] === null)) {
return $translated;
}
if (is_array($args[0])) {
$args = $args[0];
}
$translated = preg_replace('/(?<!%)%(?![%\'\-+bcdeEfFgGosuxX\d\.])/', '%%', $translated);
return vsprintf($translated, $args);
}
/**
* Auxiliary function to parse a symbol from a locale definition file
*

View file

@ -824,14 +824,14 @@ class Multibyte {
*
* @param int $char decimal value of character
* @param string $type Type 'lower' or 'upper'. Defaults to 'lower'.
* @return array|null
* @return array
*/
protected static function _find($char, $type = 'lower') {
$found = array();
if (!isset(self::$_codeRange[$char])) {
$range = self::_codepoint($char);
if ($range === false) {
return null;
return array();
}
if (!Configure::configured('_cake_core_')) {
App::uses('PhpReader', 'Configure');
@ -843,7 +843,7 @@ class Multibyte {
}
if (!self::$_codeRange[$char]) {
return null;
return array();
}
self::$_table = self::$_codeRange[$char];
$count = count(self::$_caseFold[self::$_table]);

View file

@ -48,8 +48,7 @@ class ConsoleLog extends BaseLog {
*/
public function __construct($config = array()) {
parent::__construct($config);
if (
(DS === '\\' && !(bool)env('ANSICON')) ||
if ((DS === '\\' && !(bool)env('ANSICON')) ||
(function_exists('posix_isatty') && !posix_isatty($this->_output))
) {
$outputAs = ConsoleOutput::PLAIN;

View file

@ -116,8 +116,7 @@ class AclNode extends Model {
$result = $db->read($this, $queryData, -1);
$path = array_values($path);
if (
!isset($result[0][$type]) ||
if (!isset($result[0][$type]) ||
(!empty($path) && $result[0][$type]['alias'] != $path[count($path) - 1]) ||
(empty($path) && $result[0][$type]['alias'] != $start)
) {

View file

@ -73,7 +73,7 @@ class AclBehavior extends ModelBehavior {
* @param Model $model Model using this behavior.
* @param string|array|Model $ref Array with 'model' and 'foreign_key', model object, or string value
* @param string $type Only needed when Acl is set up as 'both', specify 'Aro' or 'Aco' to get the correct node
* @return array|null
* @return array
* @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/acl.html#node
*/
public function node(Model $model, $ref = null, $type = null) {
@ -81,7 +81,7 @@ class AclBehavior extends ModelBehavior {
$type = $this->_typeMaps[$this->settings[$model->name]['type']];
if (is_array($type)) {
trigger_error(__d('cake_dev', 'AclBehavior is setup with more then one type, please specify type parameter for node()'), E_USER_WARNING);
return null;
return array();
}
}
if (empty($ref)) {
@ -104,7 +104,7 @@ class AclBehavior extends ModelBehavior {
$types = array($types);
}
foreach ($types as $type) {
$parent = $model->parentNode();
$parent = $model->parentNode($type);
if (!empty($parent)) {
$parent = $this->node($model, $parent, $type);
}

View file

@ -157,8 +157,7 @@ class TranslateBehavior extends ModelBehavior {
);
foreach ($fields as $key => $value) {
$field = (is_numeric($key)) ? $value : $key;
if (
$isAllFields ||
if ($isAllFields ||
in_array($Model->alias . '.' . $field, $query['fields']) ||
in_array($field, $query['fields'])
) {
@ -437,6 +436,10 @@ class TranslateBehavior extends ModelBehavior {
$tempData = $this->_prepareTranslations($Model, $tempData);
}
$locale = $this->_getLocale($Model);
$atomic = array();
if (isset($options['atomic'])) {
$atomic = array('atomic' => $options['atomic']);
}
foreach ($tempData as $field => $value) {
unset($conditions['content']);
@ -466,10 +469,11 @@ class TranslateBehavior extends ModelBehavior {
$RuntimeModel->save(array(
$RuntimeModel->alias => array_merge(
$conditions, array('id' => $translations[$_locale])
)
),
$atomic
));
} else {
$RuntimeModel->save(array($RuntimeModel->alias => $conditions));
$RuntimeModel->save(array($RuntimeModel->alias => $conditions), $atomic);
}
}
}
@ -585,7 +589,8 @@ class TranslateBehavior extends ModelBehavior {
$RuntimeModel = $this->translateModel($Model);
$default = array(
'className' => $RuntimeModel->alias,
'foreignKey' => 'foreign_key'
'foreignKey' => 'foreign_key',
'order' => 'id'
);
foreach ($fields as $key => $value) {

View file

@ -306,7 +306,9 @@ class TreeBehavior extends ModelBehavior {
* @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::children
*/
public function children(Model $Model, $id = null, $direct = false, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) {
$options = array();
if (is_array($id)) {
$options = $this->_getOptions($id);
extract(array_merge(array('id' => null), $id));
}
$overrideRecursive = $recursive;
@ -348,7 +350,10 @@ class TreeBehavior extends ModelBehavior {
$Model->escapeField($left) . ' >' => $result[0][$left]
);
}
return $Model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
$options = array_merge(compact(
'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
), $options);
return $Model->find('all', $options);
}
/**
@ -426,7 +431,9 @@ class TreeBehavior extends ModelBehavior {
* @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::getParentNode
*/
public function getParentNode(Model $Model, $id = null, $fields = null, $recursive = null) {
$options = array();
if (is_array($id)) {
$options = $this->_getOptions($id);
extract(array_merge(array('id' => null), $id));
}
$overrideRecursive = $recursive;
@ -446,18 +453,32 @@ class TreeBehavior extends ModelBehavior {
if ($parentId) {
$parentId = $parentId[$Model->alias][$parent];
$parent = $Model->find('first', array(
$options = array_merge(array(
'conditions' => array($Model->escapeField() => $parentId),
'fields' => $fields,
'order' => false,
'recursive' => $recursive
));
), $options);
$parent = $Model->find('first', $options);
return $parent;
}
return false;
}
/**
* Convenience method to create default find() options from $arg when it is an
* associative array.
*
* @param array $arg Array
* @return array Options array
*/
protected function _getOptions($arg) {
return count(array_filter(array_keys($arg), 'is_string') > 0) ?
$arg :
array();
}
/**
* Get the path to the given node
*
@ -465,13 +486,25 @@ class TreeBehavior extends ModelBehavior {
* @param int|string $id The ID of the record to read
* @param string|array $fields Either a single string of a field name, or an array of field names
* @param int $recursive The number of levels deep to fetch associated records
* @return array|null Array of nodes from top most parent to current node
* @return array Array of nodes from top most parent to current node
* @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::getPath
*/
public function getPath(Model $Model, $id = null, $fields = null, $recursive = null) {
$options = array();
if (is_array($id)) {
$options = $this->_getOptions($id);
extract(array_merge(array('id' => null), $id));
}
if (!empty($options)) {
$fields = null;
if (!empty($options['fields'])) {
$fields = $options['fields'];
}
if (!empty($options['recursive'])) {
$recursive = $options['recursive'];
}
}
$overrideRecursive = $recursive;
if (empty($id)) {
$id = $Model->id;
@ -489,15 +522,20 @@ class TreeBehavior extends ModelBehavior {
if ($result) {
$result = array_values($result);
} else {
return null;
return array();
}
$item = $result[0];
$results = $Model->find('all', array(
'conditions' => array($scope, $Model->escapeField($left) . ' <=' => $item[$left], $Model->escapeField($right) . ' >=' => $item[$right]),
'fields' => $fields, 'order' => array($Model->escapeField($left) => 'asc'),
'order' => false,
$options = array_merge(array(
'conditions' => array(
$scope,
$Model->escapeField($left) . ' <=' => $item[$left],
$Model->escapeField($right) . ' >=' => $item[$right],
),
'fields' => $fields,
'order' => array($Model->escapeField($left) => 'asc'),
'recursive' => $recursive
));
), $options);
$results = $Model->find('all', $options);
return $results;
}

View file

@ -397,8 +397,10 @@ class CakeSchema extends Object {
}
/**
* Generate the code for a table. Takes a table name and $fields array
* Returns a completed variable declaration to be used in schema classes.
* Generate the schema code for a table.
*
* Takes a table name and $fields array and returns a completed,
* escaped variable declaration to be used in schema classes.
*
* @param string $table Table name you want returned.
* @param array $fields Array of field information to generate the table with.
@ -426,10 +428,7 @@ class CakeSchema extends Object {
$col .= implode(",\n\t\t\t", $props) . "\n\t\t";
} elseif ($field === 'tableParameters') {
$col = "\t\t'tableParameters' => array(";
$props = array();
foreach ((array)$value as $key => $param) {
$props[] = "'{$key}' => '$param'";
}
$props = $this->_values($value);
$col .= implode(', ', $props);
}
$col .= ")";

View file

@ -102,7 +102,8 @@ class Mysql extends DboSource {
public $tableParameters = array(
'charset' => array('value' => 'DEFAULT CHARSET', 'quote' => false, 'join' => '=', 'column' => 'charset'),
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => '=', 'column' => 'Collation'),
'engine' => array('value' => 'ENGINE', 'quote' => false, 'join' => '=', 'column' => 'Engine')
'engine' => array('value' => 'ENGINE', 'quote' => false, 'join' => '=', 'column' => 'Engine'),
'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => '=', 'column' => 'Comment'),
);
/**
@ -352,7 +353,7 @@ class Mysql extends DboSource {
$fields[$column->Field]['unsigned'] = $this->_unsigned($column->Type);
}
if ($fields[$column->Field]['type'] === 'timestamp' && strtoupper($column->Default) === 'CURRENT_TIMESTAMP') {
$fields[$column->Field]['default'] = '';
$fields[$column->Field]['default'] = null;
}
if (!empty($column->Key) && isset($this->index[$column->Key])) {
$fields[$column->Field]['key'] = $this->index[$column->Key];
@ -563,7 +564,11 @@ class Mysql extends DboSource {
if (!isset($col['name'])) {
$col['name'] = $field;
}
$colList[] = 'CHANGE ' . $this->name($field) . ' ' . $this->buildColumn($col);
$alter = 'CHANGE ' . $this->name($field) . ' ' . $this->buildColumn($col);
if (isset($col['after'])) {
$alter .= ' AFTER ' . $this->name($col['after']);
}
$colList[] = $alter;
}
break;
}

View file

@ -46,6 +46,7 @@ class Postgres extends DboSource {
'schema' => 'public',
'port' => 5432,
'encoding' => '',
'sslmode' => 'allow',
'flags' => array()
);
@ -118,7 +119,7 @@ class Postgres extends DboSource {
try {
$this->_connection = new PDO(
"pgsql:host={$config['host']};port={$config['port']};dbname={$config['database']}",
"pgsql:host={$config['host']};port={$config['port']};dbname={$config['database']};sslmode={$config['sslmode']}",
$config['login'],
$config['password'],
$flags

View file

@ -181,7 +181,7 @@ class DboSource extends DataSource {
*
* @var array
*/
protected $_sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
protected $_sqlOps = array('like', 'ilike', 'rlike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
/**
* Indicates the level of nested transactions
@ -834,9 +834,7 @@ class DboSource extends DataSource {
$matches[1] . '(' . $this->name($matches[2]) . ')'
);
}
if (
preg_match('/^([\w-]+(\.[\w-]+|\(.*\))*)\s+' . preg_quote($this->alias) . '\s*([\w-]+)$/i', $data, $matches
)) {
if (preg_match('/^([\w-]+(\.[\w-]+|\(.*\))*)\s+' . preg_quote($this->alias) . '\s*([\w-]+)$/i', $data, $matches)) {
return $this->cacheMethod(
__FUNCTION__, $cacheKey,
preg_replace(
@ -1200,6 +1198,30 @@ class DboSource extends DataSource {
return $filtering;
}
/**
* Passes association results through afterFind filters of the corresponding model.
*
* Similar to DboSource::_filterResults(), but this filters only specified models.
* The primary model can not be specified, because this call DboSource::_filterResults() internally.
*
* @param array &$resultSet Reference of resultset to be filtered.
* @param Model $Model Instance of model to operate against.
* @param array $toBeFiltered List of classes to be filtered.
* @return array Array of results that have been filtered through $Model->afterFind.
*/
protected function _filterResultsInclusive(&$resultSet, Model $Model, $toBeFiltered = array()) {
$exclude = array();
if (is_array($resultSet)) {
$current = reset($resultSet);
if (is_array($current)) {
$exclude = array_diff(array_keys($current), $toBeFiltered);
}
}
return $this->_filterResults($resultSet, $Model, $exclude);
}
/**
* Queries associations.
*
@ -1271,7 +1293,7 @@ class DboSource extends DataSource {
// Filter
if ($queryData['callbacks'] === true || $queryData['callbacks'] === 'after') {
$this->_filterResults($assocResultSet, $Model);
$this->_filterResultsInclusive($assocResultSet, $Model, array($association));
}
// Merge
@ -1300,7 +1322,7 @@ class DboSource extends DataSource {
// Filter
if ($queryData['callbacks'] === true || $queryData['callbacks'] === 'after') {
$this->_filterResults($assocResultSet, $Model);
$this->_filterResultsInclusive($assocResultSet, $Model, array($association, $with));
}
}
@ -1313,8 +1335,7 @@ class DboSource extends DataSource {
$assocResultSet = array();
$prefetched = false;
if (
($type === 'hasOne' || $type === 'belongsTo') &&
if (($type === 'hasOne' || $type === 'belongsTo') &&
isset($row[$LinkModel->alias], $joined[$Model->alias]) &&
in_array($LinkModel->alias, $joined[$Model->alias])
) {
@ -1337,8 +1358,7 @@ class DboSource extends DataSource {
foreach ($LinkModel->{$type1} as $assoc1 => $assocData1) {
$DeepModel = $LinkModel->{$assoc1};
if (
$type1 === 'belongsTo' ||
if ($type1 === 'belongsTo' ||
($type === 'belongsTo' && $DeepModel->alias === $modelAlias) ||
($DeepModel->alias !== $modelAlias)
) {
@ -1370,10 +1390,15 @@ class DboSource extends DataSource {
$this->_mergeAssociation($row, $merge, $association, $type);
}
} else {
if (!$prefetched && $LinkModel->useConsistentAfterFind) {
if ($queryData['callbacks'] === true || $queryData['callbacks'] === 'after') {
$this->_filterResultsInclusive($assocResultSet, $Model, array($association));
}
}
$this->_mergeAssociation($row, $assocResultSet, $association, $type, $selfJoin);
}
if ($type !== 'hasAndBelongsToMany' && isset($row[$association]) && !$prefetched) {
if ($type !== 'hasAndBelongsToMany' && isset($row[$association]) && !$prefetched && !$LinkModel->useConsistentAfterFind) {
$row[$association] = $LinkModel->afterFind($row[$association], false);
}
@ -1589,8 +1614,7 @@ class DboSource extends DataSource {
$assocFields = $this->fields($Model, null, "{$Model->alias}.{$Model->primaryKey}");
$passedFields = $queryData['fields'];
if (
count($passedFields) > 1 ||
if (count($passedFields) > 1 ||
(strpos($passedFields[0], $assocFields[0]) === false && !preg_match('/^[a-z]+\(/i', $passedFields[0]))
) {
$queryData['fields'] = array_merge($passedFields, $assocFields);

View file

@ -142,8 +142,8 @@ class Model extends Object implements CakeEventListener {
*
* {{{
* public $validate = array(
* 'age' => array(
* 'rule' => array('between', 5, 25)
* 'length' => array(
* 'rule' => array('lengthBetween', 5, 25)
* )
* );
* }}}
@ -171,9 +171,9 @@ class Model extends Object implements CakeEventListener {
*
* {{{
* public $validate = array(
* 'age' => array(
* 'rule' => array('between', 5, 25),
* 'message' => array('The age must be between %d and %d.')
* 'length' => array(
* 'rule' => array('lengthBetween', 5, 15),
* 'message' => array('Between %d to %d characters')
* )
* );
* }}}
@ -603,6 +603,25 @@ class Model extends Object implements CakeEventListener {
// @codingStandardsIgnoreEnd
/**
* If true, afterFind will be passed consistent formatted $results in case of $primary is false.
* The format will be such as the following.
*
* {{{
* $results = array(
* 0 => array(
* 'ModelName' => array(
* 'field1' => 'value1',
* 'field2' => 'value2'
* )
* )
* );
* }}}
*
* @var bool
*/
public $useConsistentAfterFind = true;
/**
* The ID of the model record that was last inserted.
*
@ -1293,8 +1312,7 @@ class Model extends Object implements CakeEventListener {
return null;
}
if (
isset($data['hour']) &&
if (isset($data['hour']) &&
isset($data['meridian']) &&
!empty($data['hour']) &&
$data['hour'] != 12 &&
@ -1683,13 +1701,15 @@ class Model extends Object implements CakeEventListener {
/**
* Saves model data (based on white-list, if supplied) to the database. By
* default, validation occurs before save.
* default, validation occurs before save. Passthrough method to _doSave() with
* transaction handling.
*
* @param array $data Data to save.
* @param bool|array $validate Either a boolean, or an array.
* If a boolean, indicates whether or not to validate before saving.
* If an array, can have following keys:
*
* - atomic: If true (default), will attempt to save the record in a single transaction.
* - validate: Set to true/false to enable or disable validation.
* - fieldList: An array of fields you want to allow for saving.
* - callbacks: Set to false to disable callbacks. Using 'before' or 'after'
@ -1698,6 +1718,7 @@ class Model extends Object implements CakeEventListener {
*
* @param array $fieldList List of fields to allow to be saved
* @return mixed On success Model::$data if its not empty or true, false on failure
* @throws Exception
* @throws PDOException
* @triggers Model.beforeSave $this, array($options)
* @triggers Model.afterSave $this, array($created, $options)
@ -1706,10 +1727,9 @@ class Model extends Object implements CakeEventListener {
public function save($data = null, $validate = true, $fieldList = array()) {
$defaults = array(
'validate' => true, 'fieldList' => array(),
'callbacks' => true, 'counterCache' => true
'callbacks' => true, 'counterCache' => true,
'atomic' => true
);
$_whitelist = $this->whitelist;
$fields = array();
if (!is_array($validate)) {
$options = compact('validate', 'fieldList') + $defaults;
@ -1717,6 +1737,51 @@ class Model extends Object implements CakeEventListener {
$options = $validate + $defaults;
}
if (!$options['atomic']) {
return $this->_doSave($data, $options);
}
$db = $this->getDataSource();
$transactionBegun = $db->begin();
try {
$success = $this->_doSave($data, $options);
if ($transactionBegun) {
if ($success) {
$db->commit();
} else {
$db->rollback();
}
}
return $success;
} catch (Exception $e) {
if ($transactionBegun) {
$db->rollback();
}
throw $e;
}
}
/**
* Saves model data (based on white-list, if supplied) to the database. By
* default, validation occurs before save.
*
* @param array $data Data to save.
* @param array $options can have following keys:
*
* - validate: Set to true/false to enable or disable validation.
* - fieldList: An array of fields you want to allow for saving.
* - callbacks: Set to false to disable callbacks. Using 'before' or 'after'
* will enable only those callbacks.
* - `counterCache`: Boolean to control updating of counter caches (if any)
*
* @return mixed On success Model::$data if its not empty or true, false on failure
* @throws PDOException
* @link http://book.cakephp.org/2.0/en/models/saving-your-data.html
*/
protected function _doSave($data = null, $options = array()) {
$_whitelist = $this->whitelist;
$fields = array();
if (!empty($options['fieldList'])) {
if (!empty($options['fieldList'][$this->alias]) && is_array($options['fieldList'][$this->alias])) {
$this->whitelist = $options['fieldList'][$this->alias];
@ -1794,12 +1859,10 @@ class Model extends Object implements CakeEventListener {
}
}
$db = $this->getDataSource();
if (empty($this->data[$this->alias][$this->primaryKey])) {
unset($this->data[$this->alias][$this->primaryKey]);
}
$fields = $values = array();
$joined = $fields = $values = array();
foreach ($this->data as $n => $v) {
if (isset($this->hasAndBelongsToMany[$n])) {
@ -1822,6 +1885,11 @@ class Model extends Object implements CakeEventListener {
}
}
if (empty($fields) && empty($joined)) {
$this->whitelist = $_whitelist;
return false;
}
$count = count($fields);
if (!$exists && $count > 0) {
@ -1865,36 +1933,35 @@ class Model extends Object implements CakeEventListener {
}
}
if (!empty($joined) && $success === true) {
if ($success && !empty($joined)) {
$this->_saveMulti($joined, $this->id, $db);
}
if ($success && $count === 0) {
$success = false;
$this->whitelist = $_whitelist;
if (!$success) {
return $success;
}
if ($success && $count > 0) {
if (!empty($this->data)) {
if ($created) {
$this->data[$this->alias][$this->primaryKey] = $this->id;
}
if ($count > 0) {
if ($created) {
$this->data[$this->alias][$this->primaryKey] = $this->id;
}
if ($options['callbacks'] === true || $options['callbacks'] === 'after') {
$event = new CakeEvent('Model.afterSave', $this, array($created, $options));
$this->getEventManager()->dispatch($event);
}
if (!empty($this->data)) {
$success = $this->data;
}
$this->_clearCache();
$this->validationErrors = array();
$this->data = false;
}
$this->whitelist = $_whitelist;
if (!empty($this->data)) {
$success = $this->data;
}
$this->_clearCache();
$this->validationErrors = array();
$this->data = false;
return $success;
}
@ -2015,7 +2082,7 @@ class Model extends Object implements CakeEventListener {
$Model->create();
}
$Model->save($data);
$Model->save($data, array('atomic' => false));
}
}
@ -2262,9 +2329,9 @@ class Model extends Object implements CakeEventListener {
$saved = false;
if ($validates) {
if ($options['deep']) {
$saved = $this->saveAssociated($record, array_merge($options, array('atomic' => false)));
$saved = $this->saveAssociated($record, array('atomic' => false) + $options);
} else {
$saved = $this->save($record, $options);
$saved = $this->save($record, array('atomic' => false) + $options);
}
}
@ -2427,7 +2494,7 @@ class Model extends Object implements CakeEventListener {
$return[$association] = $validates;
}
if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
if ($validates && !($this->create(null) !== null && $this->save($data, array('atomic' => false) + $options))) {
$validationErrors[$this->alias] = $this->validationErrors;
$validates = false;
}

View file

@ -541,7 +541,7 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable {
* ->add('user_id', 'valid', array('rule' => 'numeric', 'message' => 'Invalid User'))
*
* $validator->add('password', array(
* 'size' => array('rule' => array('between', 8, 20)),
* 'size' => array('rule' => array('lengthBetween', 8, 20)),
* 'hasSpecialCharacter' => array('rule' => 'validateSpecialchar', 'message' => 'not valid')
* ));
* }}}

View file

@ -186,7 +186,7 @@ class CakeValidationSet implements ArrayAccess, IteratorAggregate, Countable {
* {{{
* $set
* ->setRule('required', array('rule' => 'notEmpty', 'required' => true))
* ->setRule('inRange', array('rule' => array('between', 4, 10))
* ->setRule('between', array('rule' => array('lengthBetween', 4, 10))
* }}}
*
* @param string $name The name under which the rule should be set

View file

@ -162,8 +162,7 @@ class CakeRequest implements ArrayAccess {
protected function _processPost() {
if ($_POST) {
$this->data = $_POST;
} elseif (
($this->is('put') || $this->is('delete')) &&
} elseif (($this->is('put') || $this->is('delete')) &&
strpos(env('CONTENT_TYPE'), 'application/x-www-form-urlencoded') === 0
) {
$data = $this->_readInput();
@ -261,8 +260,7 @@ class CakeRequest implements ArrayAccess {
}
$endsWithIndex = '/webroot/index.php';
$endsWithLength = strlen($endsWithIndex);
if (
strlen($uri) >= $endsWithLength &&
if (strlen($uri) >= $endsWithLength &&
substr($uri, -$endsWithLength) === $endsWithIndex
) {
$uri = '/';
@ -874,8 +872,13 @@ class CakeRequest implements ArrayAccess {
* return false if the parameter doesn't exist or is falsey.
*/
public function param($name) {
$args = func_get_args();
if (count($args) === 2) {
$this->params = Hash::insert($this->params, $name, $args[1]);
return $this;
}
if (!isset($this->params[$name])) {
return false;
return Hash::get($this->params, $name, false);
}
return $this->params[$name];
}
@ -910,6 +913,17 @@ class CakeRequest implements ArrayAccess {
return $input;
}
/**
* Modify data originally from `php://input`. Useful for altering json/xml data
* in middleware or DispatcherFilters before it gets to RequestHandlerComponent
*
* @param string $input A string to replace original parsed data from input()
* @return void
*/
public function setInput($input) {
$this->_input = $input;
}
/**
* Allow only certain HTTP request methods. If the request method does not match
* a 405 error will be shown and the required "Allow" response header will be set.

View file

@ -464,8 +464,7 @@ class CakeResponse {
);
$charset = false;
if (
$this->_charset &&
if ($this->_charset &&
(strpos($this->_contentType, 'text/') === 0 || in_array($this->_contentType, $whitelist))
) {
$charset = true;
@ -517,14 +516,18 @@ class CakeResponse {
* @param string $name the header name
* @param string $value the header value
* @return void
* @throws CakeException When headers have already been sent
*/
protected function _sendHeader($name, $value = null) {
if (!headers_sent()) {
if ($value === null) {
header($name);
} else {
header("{$name}: {$value}");
}
if (headers_sent($filename, $linenum)) {
throw new CakeException(
__d('cake_dev', 'Headers already sent in %s on line %s', $filename, $linenum)
);
}
if ($value === null) {
header($name);
} else {
header("{$name}: {$value}");
}
}
@ -1378,18 +1381,17 @@ class CakeResponse {
$name = $options['name'];
}
$this->download($name);
$this->header('Accept-Ranges', 'bytes');
$this->header('Content-Transfer-Encoding', 'binary');
}
$httpRange = env('HTTP_RANGE');
if (isset($httpRange)) {
$this->_fileRange($file, $httpRange);
} else {
$this->header('Content-Length', $fileSize);
}
$this->header('Accept-Ranges', 'bytes');
$httpRange = env('HTTP_RANGE');
if (isset($httpRange)) {
$this->_fileRange($file, $httpRange);
} else {
$this->header('Content-Length', $fileSize);
}
$this->_clearBuffer();
$this->_file = $file;
}

View file

@ -116,9 +116,6 @@ class CakeSocket {
*/
public function __construct($config = array()) {
$this->config = array_merge($this->_baseConfig, $config);
if (!is_numeric($this->config['protocol'])) {
$this->config['protocol'] = getprotobyname($this->config['protocol']);
}
}
/**
@ -133,8 +130,8 @@ class CakeSocket {
}
$scheme = null;
if (isset($this->config['request']['uri']) && $this->config['request']['uri']['scheme'] === 'https') {
$scheme = 'ssl://';
if (!empty($this->config['protocol']) && strpos($this->config['host'], '://') === false) {
$scheme = $this->config['protocol'] . '://';
}
if (!empty($this->config['context'])) {
@ -387,3 +384,4 @@ class CakeSocket {
}
}

View file

@ -1481,8 +1481,7 @@ class CakeEmail {
$msg[] = '--' . $boundary;
$msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
$msg[] = 'Content-Transfer-Encoding: base64';
if (
!isset($fileInfo['contentDisposition']) ||
if (!isset($fileInfo['contentDisposition']) ||
$fileInfo['contentDisposition']
) {
$msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"';

View file

@ -294,6 +294,7 @@ class HttpSocket extends CakeSocket {
if (isset($host)) {
$this->config['host'] = $host;
}
$this->_setProxy();
$this->request['proxy'] = $this->_proxy;
@ -311,8 +312,7 @@ class HttpSocket extends CakeSocket {
if (isset($this->request['uri']['port'])) {
$port = $this->request['uri']['port'];
}
if (
($scheme === 'http' && $port != 80) ||
if (($scheme === 'http' && $port != 80) ||
($scheme === 'https' && $port != 443) ||
($port != 80 && $port != 443)
) {
@ -343,6 +343,9 @@ class HttpSocket extends CakeSocket {
if (!empty($this->request['body']) && !isset($this->request['header']['Content-Length'])) {
$this->request['header']['Content-Length'] = strlen($this->request['body']);
}
if (isset($this->request['uri']['scheme']) && $this->request['uri']['scheme'] === 'https' && in_array($this->config['protocol'], array(false, 'tcp'))) {
$this->config['protocol'] = 'ssl';
}
$connectionType = null;
if (isset($this->request['header']['Connection'])) {
@ -463,6 +466,32 @@ class HttpSocket extends CakeSocket {
return $this->request($request);
}
/**
* Issues a HEAD request to the specified URI, query, and request.
*
* By definition HEAD request are identical to GET request except they return no response body. This means that all
* information and examples relevant to GET also applys to HEAD.
*
* @param string|array $uri URI to request. Either a string URI, or a URI array, see HttpSocket::_parseUri()
* @param array $query Querystring parameters to append to URI
* @param array $request An indexed array with indexes such as 'method' or uri
* @return mixed Result of request, either false on failure or the response to the request.
*/
public function head($uri = null, $query = array(), $request = array()) {
if (!empty($query)) {
$uri = $this->_parseUri($uri, $this->config['request']['uri']);
if (isset($uri['query'])) {
$uri['query'] = array_merge($uri['query'], $query);
} else {
$uri['query'] = $query;
}
$uri = $this->_buildUri($uri);
}
$request = Hash::merge(array('method' => 'HEAD', 'uri' => $uri), $request);
return $this->request($request);
}
/**
* Issues a POST request to the specified URI, query, and request.
*
@ -1034,3 +1063,4 @@ class HttpSocket extends CakeSocket {
}
}

View file

@ -448,8 +448,7 @@ class CakeRoute {
}
// pull out named params if named params are greedy or a rule exists.
if (
($greedyNamed || isset($allowedNamedParams[$key])) &&
if (($greedyNamed || isset($allowedNamedParams[$key])) &&
($value !== false && $value !== null) &&
(!in_array($key, $prefixes))
) {
@ -546,4 +545,22 @@ class CakeRoute {
return $out;
}
/**
* Set state magic method to support var_export
*
* This method helps for applications that want to implement
* router caching.
*
* @param array $fields Key/Value of object attributes
* @return CakeRoute A new instance of the route
*/
public static function __set_state($fields) {
$class = function_exists('get_called_class') ? get_called_class() : __CLASS__;
$obj = new $class('');
foreach ($fields as $field => $value) {
$obj->$field = $value;
}
return $obj;
}
}

View file

@ -227,8 +227,7 @@ class Router {
* @throws RouterException
*/
protected static function _validateRouteClass($routeClass) {
if (
$routeClass !== 'CakeRoute' &&
if ($routeClass !== 'CakeRoute' &&
(!class_exists($routeClass) || !is_subclass_of($routeClass, 'CakeRoute'))
) {
throw new RouterException(__d('cake_dev', 'Route class not found, or route class is not a subclass of CakeRoute'));
@ -355,9 +354,8 @@ class Router {
break;
}
}
if (isset($defaults['prefix'])) {
if (isset($defaults['prefix']) && !in_array($defaults['prefix'], self::$_prefixes)) {
self::$_prefixes[] = $defaults['prefix'];
self::$_prefixes = array_keys(array_flip(self::$_prefixes));
}
$defaults += array('plugin' => null);
if (empty($options['action'])) {
@ -610,11 +608,9 @@ class Router {
extract(self::_parseExtension($url));
for ($i = 0, $len = count(self::$routes); $i < $len; $i++) {
$route =& self::$routes[$i];
foreach (self::$routes as $route) {
if (($r = $route->parse($url)) !== false) {
self::$_currentRoute[] =& $route;
self::$_currentRoute[] = $route;
$out = $r;
break;
}
@ -734,7 +730,7 @@ class Router {
*
* @param string $name Parameter name
* @param bool $current Current parameter, useful when using requestAction
* @return string Parameter value
* @return string|null Parameter value
*/
public static function getParam($name = 'controller', $current = false) {
$params = Router::getParams($current);
@ -906,12 +902,12 @@ class Router {
$match = false;
for ($i = 0, $len = count(self::$routes); $i < $len; $i++) {
foreach (self::$routes as $route) {
$originalUrl = $url;
$url = self::$routes[$i]->persistParams($url, $params);
$url = $route->persistParams($url, $params);
if ($match = self::$routes[$i]->match($url)) {
if ($match = $route->match($url)) {
$output = trim($match, '/');
break;
}
@ -995,12 +991,10 @@ class Router {
);
$keys = array_values(array_diff(array_keys($url), $skip));
$count = count($keys);
// Remove this once parsed URL parameters can be inserted into 'pass'
for ($i = 0; $i < $count; $i++) {
$key = $keys[$i];
if (is_numeric($keys[$i])) {
foreach ($keys as $key) {
if (is_numeric($key)) {
$args[] = $url[$key];
} else {
$named[$key] = $url[$key];

View file

@ -20,6 +20,7 @@ require_once CAKE . 'basics.php';
App::uses('Folder', 'Utility');
App::uses('CakeResponse', 'Network');
App::uses('Debugger', 'Utility');
/**
* BasicsTest class
@ -384,8 +385,8 @@ class BasicsTest extends CakeTestCase {
$expected = 'Some string with %s and a null argument';
$this->assertEquals($expected, $result);
$result = __('Some string with multiple %s%s, first beeing null', null, 'arguments');
$expected = 'Some string with multiple arguments, first beeing null';
$result = __('Some string with multiple %s%s, first being null', null, 'arguments');
$expected = 'Some string with multiple arguments, first being null';
$this->assertEquals($expected, $result);
$result = __('Some string with %s %s', array('multiple', 'arguments'));
@ -1148,6 +1149,24 @@ EXPECTED;
$this->assertEquals($expected, stripslashes_deep($nested));
}
/**
* Tests that the stackTrace() method is a shortcut for Debugger::trace()
*
* @return void
*/
public function testStackTrace() {
ob_start();
list(, $expected) = array(stackTrace(), Debugger::trace());
$result = ob_get_clean();
$this->assertEquals($expected, $result);
$opts = array('args' => true);
ob_start();
list(, $expected) = array(stackTrace($opts), Debugger::trace($opts));
$result = ob_get_clean();
$this->assertEquals($expected, $result);
}
/**
* test pluginSplit
*

View file

@ -103,7 +103,8 @@ class MemcachedEngineTest extends CakeTestCase {
'login' => null,
'password' => null,
'groups' => array(),
'serialize' => 'php'
'serialize' => 'php',
'options' => array()
);
$this->assertEquals($expecting, $settings);
}
@ -133,6 +134,23 @@ class MemcachedEngineTest extends CakeTestCase {
$this->assertTrue($MemcachedCompressed->getMemcached()->getOption(Memcached::OPT_COMPRESSION));
}
/**
* test setting options
*
* @return void
*/
public function testOptionsSetting() {
$memcached = new TestMemcachedEngine();
$memcached->init(array(
'engine' => 'Memcached',
'servers' => array('127.0.0.1:11211'),
'options' => array(
Memcached::OPT_BINARY_PROTOCOL => true
)
));
$this->assertEquals(1, $memcached->getMemcached()->getOption(Memcached::OPT_BINARY_PROTOCOL));
}
/**
* test accepts only valid serializer engine
*

View file

@ -77,6 +77,7 @@ class RedisEngineTest extends CakeTestCase {
'persistent' => true,
'password' => false,
'database' => 0,
'unix_socket' => false,
);
$this->assertEquals($expecting, $settings);
}

View file

@ -162,6 +162,10 @@ class ExtractTaskTest extends CakeTestCase {
$this->assertContains('msgid "double \\"quoted\\""', $result, 'Strings with quotes not handled correctly');
$this->assertContains("msgid \"single 'quoted'\"", $result, 'Strings with quotes not handled correctly');
$pattern = '/\#: (\\\\|\/)extract\.ctp:33\n';
$pattern .= 'msgctxt "mail"/';
$this->assertRegExp($pattern, $result);
// extract.ctp - reading the domain.pot
$result = file_get_contents($this->path . DS . 'domain.pot');

View file

@ -315,7 +315,7 @@ class ModelTaskTest extends CakeTestCase {
$this->Task->initValidations();
$this->Task->interactive = true;
$this->Task->expects($this->any())->method('in')
->will($this->onConsecutiveCalls('24', 'y', '18', 'n'));
->will($this->onConsecutiveCalls('25', 'y', '19', 'n'));
$result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
$expected = array('notEmpty' => 'notEmpty', 'maxLength' => 'maxLength');
@ -333,7 +333,7 @@ class ModelTaskTest extends CakeTestCase {
$this->Task->interactive = true;
$this->Task->expects($this->any())->method('in')
->will($this->onConsecutiveCalls('999999', '24', 'n'));
->will($this->onConsecutiveCalls('999999', '25', 'n'));
$this->Task->expects($this->at(10))->method('out')
->with($this->stringContains('make a valid'));
@ -368,7 +368,7 @@ class ModelTaskTest extends CakeTestCase {
$this->Task->initValidations();
$this->Task->interactive = true;
$this->Task->expects($this->any())->method('in')
->will($this->onConsecutiveCalls('24', 'y', 's'));
->will($this->onConsecutiveCalls('25', 'y', 's'));
$result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
$expected = array('notEmpty' => 'notEmpty', '_skipFields' => true);
@ -384,7 +384,7 @@ class ModelTaskTest extends CakeTestCase {
$this->Task->initValidations();
$this->Task->interactive = true;
$this->Task->expects($this->any())->method('in')
->will($this->onConsecutiveCalls('24', 's'));
->will($this->onConsecutiveCalls('25', 's'));
$result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
$expected = array('notEmpty' => 'notEmpty', '_skipFields' => true);
@ -400,7 +400,7 @@ class ModelTaskTest extends CakeTestCase {
public function testInteractiveDoValidationWithSkipping() {
$this->Task->expects($this->any())
->method('in')
->will($this->onConsecutiveCalls('35', '24', 'n', '11', 's'));
->will($this->onConsecutiveCalls('36', '25', 'n', '11', 's'));
$this->Task->interactive = true;
$Model = $this->getMock('Model');
$Model->primaryKey = 'id';

View file

@ -100,18 +100,25 @@ class PluginTaskTest extends CakeTestCase {
$directories = array(
'Config' . DS . 'Schema',
'Model' . DS . 'Behavior',
'Model' . DS . 'Datasource',
'Console' . DS . 'Command' . DS . 'Task',
'Console' . DS . 'Templates',
'Controller' . DS . 'Component',
'Lib',
'View' . DS . 'Helper',
'Locale' . DS . 'eng' . DS . 'LC_MESSAGES',
'Model' . DS . 'Behavior',
'Model' . DS . 'Datasource',
'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component',
'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
'Test' . DS . 'Case' . DS . 'Lib',
'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior',
'Test' . DS . 'Case' . DS . 'Model' . DS . 'Datasource',
'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
'Test' . DS . 'Fixture',
'Vendor',
'webroot'
'View' . DS . 'Elements',
'View' . DS . 'Helper',
'View' . DS . 'Layout',
'webroot' . DS . 'css',
'webroot' . DS . 'js',
'webroot' . DS . 'img',
);
foreach ($directories as $dir) {
$this->assertTrue(is_dir($path . DS . $dir), 'Missing directory for ' . $dir);

View file

@ -476,6 +476,21 @@ class ConsoleOptionParserTest extends CakeTestCase {
$this->assertEquals('test', $result['test']->name());
}
/**
* test removeSubcommand with an object.
*
* @return void
*/
public function testRemoveSubcommand() {
$parser = new ConsoleOptionParser('test', false);
$parser->addSubcommand(new ConsoleInputSubcommand('test'));
$result = $parser->subcommands();
$this->assertEquals(1, count($result));
$parser->removeSubcommand('test');
$result = $parser->subcommands();
$this->assertEquals(0, count($result), 'Remove a subcommand does not work');
}
/**
* test adding multiple subcommands
*

View file

@ -368,6 +368,36 @@ class ShellTest extends CakeTestCase {
$this->Shell->out('Quiet', 1, Shell::QUIET);
}
/**
* Test overwriting.
*
* @return void
*/
public function testOverwrite() {
$number = strlen('Some text I want to overwrite');
$this->Shell->stdout->expects($this->at(0))
->method('write')
->with('Some <info>text</info> I want to overwrite', 0)
->will($this->returnValue($number));
$this->Shell->stdout->expects($this->at(1))
->method('write')
->with(str_repeat("\x08", $number), 0);
$this->Shell->stdout->expects($this->at(2))
->method('write')
->with('Less text', 0)
->will($this->returnValue(9));
$this->Shell->stdout->expects($this->at(3))
->method('write')
->with(str_repeat(' ', $number - 9), 0);
$this->Shell->out('Some <info>text</info> I want to overwrite', 0);
$this->Shell->overwrite('Less text');
}
/**
* testErr method
*

View file

@ -36,7 +36,7 @@ class BasicAuthenticateTest extends CakeTestCase {
*
* @var array
*/
public $fixtures = array('core.user', 'core.auth_user');
public $fixtures = array('core.user', 'core.auth_user', 'core.article');
/**
* setup
@ -197,6 +197,80 @@ class BasicAuthenticateTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
/**
* test contain success
*
* @return void
*/
public function testAuthenticateContainSuccess() {
$User = ClassRegistry::init('User');
$User->bindModel(array('hasMany' => array('Article')));
$User->Behaviors->load('Containable');
$this->auth->settings['contain'] = 'Article';
$request = new CakeRequest('posts/index', false);
$request->addParams(array('pass' => array(), 'named' => array()));
$_SERVER['PHP_AUTH_USER'] = 'mariano';
$_SERVER['PHP_AUTH_PW'] = 'password';
$result = $this->auth->authenticate($request, $this->response);
$expected = array(
'id' => 1,
'user_id' => 1,
'title' => 'First Article',
'body' => 'First Article Body',
'published' => 'Y',
'created' => '2007-03-18 10:39:23',
'updated' => '2007-03-18 10:41:31'
);
$this->assertEquals($expected, $result['Article'][0]);
}
/**
* test userFields success
*
* @return void
*/
public function testAuthenticateUserFieldsSuccess() {
$this->auth->settings['userFields'] = array('id', 'user');
$request = new CakeRequest('posts/index', false);
$request->addParams(array('pass' => array(), 'named' => array()));
$_SERVER['PHP_AUTH_USER'] = 'mariano';
$_SERVER['PHP_AUTH_PW'] = 'password';
$result = $this->auth->authenticate($request, $this->response);
$expected = array(
'id' => 1,
'user' => 'mariano',
);
$this->assertEquals($expected, $result);
}
/**
* test userFields and related models success
*
* @return void
*/
public function testAuthenticateUserFieldsRelatedModelsSuccess() {
$User = ClassRegistry::init('User');
$User->bindModel(array('hasOne' => array('Article')));
$this->auth->settings['recursive'] = 0;
$this->auth->settings['userFields'] = array('Article.id', 'Article.title');
$request = new CakeRequest('posts/index', false);
$request->addParams(array('pass' => array(), 'named' => array()));
$_SERVER['PHP_AUTH_USER'] = 'mariano';
$_SERVER['PHP_AUTH_PW'] = 'password';
$result = $this->auth->authenticate($request, $this->response);
$expected = array(
'id' => 1,
'title' => 'First Article',
);
$this->assertEquals($expected, $result['Article']);
}
/**
* test scope failure.
*

View file

@ -19,7 +19,54 @@
App::uses('Controller', 'Controller');
App::uses('AuthComponent', 'Controller/Component');
App::uses('AclComponent', 'Controller/Component');
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
App::uses('FormAuthenticate', 'Controller/Component/Auth');
App::uses('CakeEvent', 'Event');
/**
* TestFormAuthenticate class
*
* @package Cake.Test.Case.Controller.Component
*/
class TestBaseAuthenticate extends BaseAuthenticate {
/**
* Implemented events
*
* @return array of events => callbacks.
*/
public function implementedEvents() {
return array(
'Auth.afterIdentify' => 'afterIdentify'
);
}
public $afterIdentifyCallable = null;
/**
* Test function to be used in event dispatching
*
* @return void
*/
public function afterIdentify($event) {
call_user_func($this->afterIdentifyCallable, $event);
}
/**
* Authenticate a user based on the request information.
*
* @param CakeRequest $request Request to get authentication information from.
* @param CakeResponse $response A response object that can have headers added.
* @return mixed Either false on failure, or an array of user data on success.
*/
public function authenticate(CakeRequest $request, CakeResponse $response) {
return array(
'id' => 1,
'username' => 'mark'
);
}
}
/**
* TestAuthComponent class
@ -39,13 +86,24 @@ class TestAuthComponent extends AuthComponent {
* Helper method to add/set an authenticate object instance
*
* @param int $index The index at which to add/set the object
* @param Object $object The object to add/set
* @param object $object The object to add/set
* @return void
*/
public function setAuthenticateObject($index, $object) {
$this->_authenticateObjects[$index] = $object;
}
/**
* Helper method to get an authenticate object instance
*
* @param int $index The index at which to get the object
* @return object $object
*/
public function getAuthenticateObject($index) {
$this->constructAuthenticate();
return isset($this->_authenticateObjects[$index]) ? $this->_authenticateObjects[$index] : null;
}
/**
* Helper method to add/set an authorize object instance
*
@ -266,6 +324,27 @@ class AjaxAuthController extends Controller {
}
/**
* Mock class used to test event dispatching
*
* @package Cake.Test.Case.Event
*/
class AuthEventTestListener {
public $callStack = array();
/**
* Test function to be used in event dispatching
*
* @return void
*/
public function listenerFunction() {
$this->callStack[] = __FUNCTION__;
}
}
/**
* AuthComponentTest class
*
@ -411,6 +490,33 @@ class AuthComponentTest extends CakeTestCase {
$this->assertEquals($user, $this->Auth->user());
}
/**
* testLogin afterIdentify event method
*
* @return void
*/
public function testLoginAfterIdentify() {
$this->Auth->authenticate = array(
'TestBase',
);
$user = array(
'id' => 1,
'username' => 'mark'
);
$auth = $this->Auth->getAuthenticateObject(0);
$listener = $this->getMock('AuthEventTestListener');
$auth->afterIdentifyCallable = array($listener, 'listenerFunction');
$event = new CakeEvent('Auth.afterIdentify', $this->Auth, array('user' => $user));
$listener->expects($this->once())->method('listenerFunction')->with($event);
$result = $this->Auth->login();
$this->assertTrue($result);
$this->assertTrue($this->Auth->loggedIn());
$this->assertEquals($user, $this->Auth->user());
}
/**
* testRedirectVarClearing method
*
@ -1305,6 +1411,45 @@ class AuthComponentTest extends CakeTestCase {
$this->Auth->logout();
}
/**
* Test mapActions as a getter
*
* @return void
*/
public function testMapActions() {
$MapActionMockAuthorize = $this->getMock(
'BaseAuthorize',
array('authorize'),
array(),
'',
false
);
$this->Auth->authorize = array('MapActionAuthorize');
$this->Auth->setAuthorizeObject(0, $MapActionMockAuthorize);
$actions = array('my_action' => 'create');
$this->Auth->mapActions($actions);
$actions = array(
'create' => array('my_other_action'),
'update' => array('updater')
);
$this->Auth->mapActions($actions);
$actions = $this->Auth->mapActions();
$result = $actions['my_action'];
$expected = 'create';
$this->assertEquals($expected, $result);
$result = $actions['my_other_action'];
$expected = 'create';
$this->assertEquals($expected, $result);
$result = $actions['updater'];
$expected = 'update';
$this->assertEquals($expected, $result);
}
/**
* test mapActions loading and delegating to authorize objects.
*

View file

@ -75,15 +75,15 @@ class I18nTest extends CakeTestCase {
$this->assertEquals('Dom 1 Foo', I18n::translate('dom1.foo', false, 'dom1'));
$this->assertEquals('Dom 1 Bar', I18n::translate('dom1.bar', false, 'dom1'));
$domains = I18n::domains();
$this->assertEquals('Dom 1 Foo', $domains['dom1']['cache_test_po']['LC_MESSAGES']['dom1.foo']);
$this->assertEquals('Dom 1 Foo', $domains['dom1']['cache_test_po']['LC_MESSAGES']['dom1.foo']['']);
// reset internally stored entries
I18n::clear();
// now only dom1 should be in cache
$cachedDom1 = Cache::read('dom1_' . $lang, '_cake_core_');
$this->assertEquals('Dom 1 Foo', $cachedDom1['LC_MESSAGES']['dom1.foo']);
$this->assertEquals('Dom 1 Bar', $cachedDom1['LC_MESSAGES']['dom1.bar']);
$this->assertEquals('Dom 1 Foo', $cachedDom1['LC_MESSAGES']['dom1.foo']['']);
$this->assertEquals('Dom 1 Bar', $cachedDom1['LC_MESSAGES']['dom1.bar']['']);
// dom2 not in cache
$this->assertFalse(Cache::read('dom2_' . $lang, '_cake_core_'));
@ -92,11 +92,11 @@ class I18nTest extends CakeTestCase {
// verify dom2 was cached through manual read from cache
$cachedDom2 = Cache::read('dom2_' . $lang, '_cake_core_');
$this->assertEquals('Dom 2 Foo', $cachedDom2['LC_MESSAGES']['dom2.foo']);
$this->assertEquals('Dom 2 Bar', $cachedDom2['LC_MESSAGES']['dom2.bar']);
$this->assertEquals('Dom 2 Foo', $cachedDom2['LC_MESSAGES']['dom2.foo']['']);
$this->assertEquals('Dom 2 Bar', $cachedDom2['LC_MESSAGES']['dom2.bar']['']);
// modify cache entry manually to verify that dom1 entries now will be read from cache
$cachedDom1['LC_MESSAGES']['dom1.foo'] = 'FOO';
$cachedDom1['LC_MESSAGES']['dom1.foo'][''] = 'FOO';
Cache::write('dom1_' . $lang, $cachedDom1, '_cake_core_');
$this->assertEquals('FOO', I18n::translate('dom1.foo', false, 'dom1'));
}
@ -1512,6 +1512,127 @@ class I18nTest extends CakeTestCase {
$this->assertTrue(in_array('25 everything else (from core translated)', $corePlurals));
}
/**
* testMoRulesFifteen method
*
* @return void
*/
public function testMoRulesFifteen() {
Configure::write('Config.language', 'rule_15_mo');
$this->assertRulesFifteen();
}
/**
* testPoRulesFifteen method
*
* @return void
*/
public function testPoRulesFifteen() {
Configure::write('Config.language', 'rule_15_po');
$this->assertRulesFifteen();
}
/**
* Assertions for plural rules fifteen
*
* @return void
*/
public function assertRulesFifteen() {
$singular = $this->_singular();
$this->assertEquals('Plural Rule 15 (translated)', $singular);
$plurals = $this->_plural(111);
$this->assertTrue(in_array('0 is 0 (translated)', $plurals));
$this->assertTrue(in_array('1 is 1 (translated)', $plurals));
$this->assertTrue(in_array('2 is 2 (translated)', $plurals));
$this->assertTrue(in_array('3 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('4 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('5 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('6 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('7 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('8 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('9 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('10 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('11 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('12 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('13 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('14 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('15 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('16 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('17 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('18 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('19 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('20 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('31 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('42 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('53 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('64 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('75 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('86 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('97 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('98 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('99 ends with 11-99 (translated)', $plurals));
$this->assertTrue(in_array('100 everything else (translated)', $plurals));
$this->assertTrue(in_array('101 everything else (translated)', $plurals));
$this->assertTrue(in_array('102 everything else (translated)', $plurals));
$this->assertTrue(in_array('103 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('104 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('105 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('106 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('107 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('108 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('109 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('110 ends with 03-10 (translated)', $plurals));
$this->assertTrue(in_array('111 ends with 11-99 (translated)', $plurals));
$coreSingular = $this->_singularFromCore();
$this->assertEquals('Plural Rule 15 (from core translated)', $coreSingular);
$corePlurals = $this->_pluralFromCore(111);
$this->assertTrue(in_array('0 is 0 (from core translated)', $corePlurals));
$this->assertTrue(in_array('1 is 1 (from core translated)', $corePlurals));
$this->assertTrue(in_array('2 is 2 (from core translated)', $corePlurals));
$this->assertTrue(in_array('3 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('4 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('5 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('6 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('7 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('8 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('9 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('10 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('11 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('12 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('13 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('14 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('15 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('16 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('17 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('18 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('19 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('20 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('31 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('42 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('53 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('64 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('75 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('86 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('97 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('98 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('99 ends with 11-99 (from core translated)', $corePlurals));
$this->assertTrue(in_array('100 everything else (from core translated)', $corePlurals));
$this->assertTrue(in_array('101 everything else (from core translated)', $corePlurals));
$this->assertTrue(in_array('102 everything else (from core translated)', $corePlurals));
$this->assertTrue(in_array('103 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('104 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('105 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('106 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('107 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('108 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('109 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('110 ends with 03-10 (from core translated)', $corePlurals));
$this->assertTrue(in_array('111 ends with 11-99 (from core translated)', $corePlurals));
}
/**
* testSetLanguageWithSession method
*
@ -1637,6 +1758,30 @@ class I18nTest extends CakeTestCase {
$this->assertTrue(in_array('25 = 0 or > 1 (from plugin)', $plurals));
}
/**
* Test that Configure::read('I18n.preferApp') will prefer app.
*
* @return void
*/
public function testPluginTranslationPreferApp() {
// Reset internally stored entries
I18n::clear();
Cache::clear(false, '_cake_core_');
Configure::write('I18n.preferApp', true);
App::build(array(
'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
));
Configure::write('Config.language', 'po');
$singular = $this->_domainSingular();
$this->assertEquals('Plural Rule 1', $singular);
$plurals = $this->_domainPlural();
$this->assertTrue(in_array('0 = 0 or > 1', $plurals));
}
/**
* testPoMultipleLineTranslation method
*
@ -1879,6 +2024,22 @@ class I18nTest extends CakeTestCase {
$this->assertSame($expected, $result['day']);
}
/**
* Test basic context support
*
* @return void
*/
public function testContext() {
Configure::write('Config.language', 'nld');
$this->assertSame("brief", __x('mail', 'letter'));
$this->assertSame("letter", __x('character', 'letter'));
$this->assertSame("bal", __x('spherical object', 'ball'));
$this->assertSame("danspartij", __x('social gathering', 'ball'));
$this->assertSame("balans", __('balance'));
$this->assertSame("saldo", __x('money', 'balance'));
}
/**
* Singular method
*
@ -1948,11 +2109,12 @@ class I18nTest extends CakeTestCase {
/**
* Plural method
*
* @param int $upTo For numbers upto (default to 25)
* @return void
*/
protected function _plural() {
protected function _plural($upTo = 25) {
$plurals = array();
for ($number = 0; $number <= 25; $number++) {
for ($number = 0; $number <= $upTo; $number++) {
$plurals[] = sprintf(__n('%d = 1', '%d = 0 or > 1', (float)$number), (float)$number);
}
return $plurals;
@ -1971,11 +2133,12 @@ class I18nTest extends CakeTestCase {
/**
* pluralFromCore method
*
* @param int $upTo For numbers upto (default to 25)
* @return void
*/
protected function _pluralFromCore() {
protected function _pluralFromCore($upTo = 25) {
$plurals = array();
for ($number = 0; $number <= 25; $number++) {
for ($number = 0; $number <= $upTo; $number++) {
$plurals[] = sprintf(__n('%d = 1 (from core)', '%d = 0 or > 1 (from core)', (float)$number), (float)$number);
}
return $plurals;

View file

@ -139,8 +139,7 @@ class ConsoleLogTest extends CakeTestCase {
TestCakeLog::config('test_console_log', array(
'engine' => 'TestConsole',
));
if (
(DS === '\\' && !(bool)env('ANSICON')) ||
if ((DS === '\\' && !(bool)env('ANSICON')) ||
(function_exists('posix_isatty') && !posix_isatty(null))
) {
$expected = ConsoleOutput::PLAIN;

View file

@ -719,6 +719,54 @@ class TranslateBehaviorTest extends CakeTestCase {
$this->assertCount(2, $result['Content']);
}
/**
* testSaveAssociatedAtomic method
*
* @return void
*/
public function testSaveAssociatedAtomic() {
$this->loadFixtures('Translate', 'TranslatedItem');
$TestModel = new TranslatedItem();
$data = array(
'slug' => 'fourth_translated',
'title' => array(
'eng' => 'Title #4'
),
'content' => array(
'eng' => 'Content #4'
),
'translated_article_id' => 1,
);
$Mock = $this->getMockForModel('TranslateTestModel', array('save'));
$TestModel->Behaviors->Translate->runtime[$TestModel->alias]['model'] = $Mock;
$with = array(
'TranslateTestModel' => array (
'model' => 'TranslatedItem',
'foreign_key' => '4',
'field' => 'content',
'locale' => 'eng',
'content' => 'Content #4',
)
);
$Mock->expects($this->at(0))->method('save')->with($with, array('atomic' => false));
$with = array(
'TranslateTestModel' => array (
'model' => 'TranslatedItem',
'foreign_key' => '4',
'field' => 'title',
'locale' => 'eng',
'content' => 'Title #4',
)
);
$Mock->expects($this->at(1))->method('save')->with($with, array('atomic' => false));
$TestModel->create();
$TestModel->saveAssociated($data, array('atomic' => false));
}
/**
* Test that saving only some of the translated fields allows the record to be found again.
*

View file

@ -704,7 +704,8 @@ class MysqlTest extends CakeTestCase {
'tableParameters' => array(
'charset' => 'utf8',
'collate' => 'utf8_general_ci',
'engine' => 'InnoDB'
'engine' => 'InnoDB',
'comment' => 'Newly table added comment.',
)
)
));
@ -712,6 +713,7 @@ class MysqlTest extends CakeTestCase {
$this->assertContains('DEFAULT CHARSET=utf8', $result);
$this->assertContains('ENGINE=InnoDB', $result);
$this->assertContains('COLLATE=utf8_general_ci', $result);
$this->assertContains('COMMENT=\'Newly table added comment.\'', $result);
$this->Dbo->rawQuery($result);
$result = $this->Dbo->listDetailedSources($this->Dbo->fullTableName('altertest', false, false));
@ -775,13 +777,15 @@ class MysqlTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$table = $this->Dbo->fullTableName($tableName);
$this->Dbo->rawQuery('CREATE TABLE ' . $table . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id)) ENGINE=MyISAM DEFAULT CHARSET=cp1250 COLLATE=cp1250_general_ci;');
$this->Dbo->rawQuery('CREATE TABLE ' . $table . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id)) ENGINE=MyISAM DEFAULT CHARSET=cp1250 COLLATE=cp1250_general_ci COMMENT=\'Table\'\'s comment\';');
$result = $this->Dbo->readTableParameters($this->Dbo->fullTableName($tableName, false, false));
$this->Dbo->rawQuery('DROP TABLE ' . $table);
$expected = array(
'charset' => 'cp1250',
'collate' => 'cp1250_general_ci',
'engine' => 'MyISAM');
'engine' => 'MyISAM',
'comment' => 'Table\'s comment',
);
$this->assertEquals($expected, $result);
}
@ -906,8 +910,16 @@ SQL;
'alias' => 'TimestampDefaultValue'
));
$result = $this->Dbo->describe($model);
$this->assertEquals('', $result['limit_date']['default']);
$this->Dbo->execute('DROP TABLE ' . $name);
$this->assertNull($result['limit_date']['default']);
$schema = new CakeSchema(array(
'connection' => 'test',
'testdescribes' => $result
));
$result = $this->Dbo->createSchema($schema);
$this->assertContains('`limit_date` timestamp NOT NULL,', $result);
}
/**
@ -1267,7 +1279,7 @@ SQL;
* @param Model $model
* @param array $queryData
* @param array $binding
* @return void
* @return array The prepared association query
*/
protected function &_prepareAssociationQuery(Model $model, &$queryData, $binding) {
$type = $binding['type'];
@ -2380,6 +2392,10 @@ SQL;
$expected = " WHERE ((`User`.`user` = 'mariano') OR (`User`.`user` = 'nate'))";
$this->assertEquals($expected, $result);
$result = $this->Dbo->conditions(array('User.user RLIKE' => 'mariano|nate'));
$expected = " WHERE `User`.`user` RLIKE 'mariano|nate'";
$this->assertEquals($expected, $result);
$result = $this->Dbo->conditions(array('or' => array(
'score BETWEEN ? AND ?' => array('4', '5'), 'rating >' => '20'
)));

View file

@ -1463,7 +1463,7 @@ class DboSourceTest extends CakeTestCase {
}
/**
* Test that count how many times is afterFind called
* Test that count how many times afterFind is called
*
* @return void
*/
@ -1472,7 +1472,6 @@ class DboSourceTest extends CakeTestCase {
// Use alias to make testing "primary = true" easy
$Primary = $this->getMock('Comment', array('afterFind'), array(array('alias' => 'Primary')), '', true);
$Primary->expects($this->any())->method('afterFind')->will($this->returnArgument(0));
$Article = $this->getMock('Article', array('afterFind'), array(), '', true);
$User = $this->getMock('User', array('afterFind'), array(), '', true);
@ -1507,6 +1506,99 @@ class DboSourceTest extends CakeTestCase {
$result = $Primary->find('first', array('conditions' => array('Primary.id' => 5), 'recursive' => 2));
$this->assertCount(2, $result['Article']['Tag']);
$this->assertCount(2, $result['Article']['Comment']);
// hasMany special case
// Both User and Article has many Comments
$User = $this->getMock('User', array('afterFind'), array(), '', true);
$Article = $this->getMock('Article', array('afterFind'), array(), '', true);
$Comment = $this->getMock('Comment', array('afterFind'), array(), '', true);
$User->bindModel(array('hasMany' => array('Comment', 'Article')));
$Article->unbindModel(array('belongsTo' => array('User'), 'hasAndBelongsToMany' => array('Tag')));
$Comment->unbindModel(array('belongsTo' => array('User', 'Article'), 'hasOne' => 'Attachment'));
$User->Comment = $Comment;
$User->Article = $Article;
$User->Article->Comment = $Comment;
// primary = true
$User->expects($this->once())
->method('afterFind')->with($this->anything(), $this->isTrue())->will($this->returnArgument(0));
$Article->expects($this->exactly(2)) // User has 2 Articles
->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0));
$Comment->expects($this->exactly(7)) // User1 has 3 Comments, Article[id=1] has 4 Comments and Article[id=3] has 0 Comments
->method('afterFind')->with($this->anything(), $this->isFalse())->will($this->returnArgument(0));
$result = $User->find('first', array('conditions' => array('User.id' => 1), 'recursive' => 2));
$this->assertCount(3, $result['Comment']);
$this->assertCount(2, $result['Article']);
$this->assertCount(4, $result['Article'][0]['Comment']);
$this->assertCount(0, $result['Article'][1]['Comment']);
}
/**
* Test format of $results in afterFind
*
* @return void
*/
public function testUseConsistentAfterFind() {
$this->loadFixtures('Author', 'Post');
$expected = array(
'Author' => array(
'id' => '1',
'user' => 'mariano',
'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
'created' => '2007-03-17 01:16:23',
'updated' => '2007-03-17 01:18:31',
'test' => 'working',
),
'Post' => array(
array(
'id' => '1',
'author_id' => '1',
'title' => 'First Post',
'body' => 'First Post Body',
'published' => 'Y',
'created' => '2007-03-18 10:39:23',
'updated' => '2007-03-18 10:41:31',
),
array(
'id' => '3',
'author_id' => '1',
'title' => 'Third Post',
'body' => 'Third Post Body',
'published' => 'Y',
'created' => '2007-03-18 10:43:23',
'updated' => '2007-03-18 10:45:31',
),
),
);
$Author = new Author();
$Post = $this->getMock('Post', array('afterFind'), array(), '', true);
$Post->expects($this->at(0))->method('afterFind')->with(array(array('Post' => $expected['Post'][0])), $this->isFalse())->will($this->returnArgument(0));
$Post->expects($this->at(1))->method('afterFind')->with(array(array('Post' => $expected['Post'][1])), $this->isFalse())->will($this->returnArgument(0));
$Author->bindModel(array('hasMany' => array('Post' => array('limit' => 2, 'order' => 'Post.id'))));
$Author->Post = $Post;
$result = $Author->find('first', array('conditions' => array('Author.id' => 1), 'recursive' => 1));
$this->assertEquals($expected, $result);
// Backward compatiblity
$Author = new Author();
$Post = $this->getMock('Post', array('afterFind'), array(), '', true);
$Post->expects($this->once())->method('afterFind')->with($expected['Post'], $this->isFalse())->will($this->returnArgument(0));
$Post->useConsistentAfterFind = false;
$Author->bindModel(array('hasMany' => array('Post' => array('limit' => 2, 'order' => 'Post.id'))));
$Author->Post = $Post;
$result = $Author->find('first', array('conditions' => array('Author.id' => 1), 'recursive' => 1));
$this->assertEquals($expected, $result);
}
/**

View file

@ -239,6 +239,32 @@ class ModelIntegrationTest extends BaseModelTest {
$this->assertFalse(isset($TestModel->Behaviors->Tree));
}
/**
* testTreeWithContainable method
*
* @return void
*/
public function testTreeWithContainable() {
$this->loadFixtures('Ad', 'Campaign');
$TestModel = new Ad();
$TestModel->Behaviors->load('Tree');
$TestModel->Behaviors->load('Containable');
$node = $TestModel->findById(2);
$node['Ad']['parent_id'] = 1;
$TestModel->save($node);
$result = $TestModel->getParentNode(array('id' => 2, 'contain' => 'Campaign'));
$this->assertTrue(array_key_exists('Campaign', $result));
$result = $TestModel->children(array('id' => 1, 'contain' => 'Campaign'));
$this->assertTrue(array_key_exists('Campaign', $result[0]));
$result = $TestModel->getPath(array('id' => 2, 'contain' => 'Campaign'));
$this->assertTrue(array_key_exists('Campaign', $result[0]));
$this->assertTrue(array_key_exists('Campaign', $result[1]));
}
/**
* testFindWithJoinsOption method
*

View file

@ -767,7 +767,7 @@ class ModelValidationTest extends BaseModelTest {
'last' => false
),
'between' => array(
'rule' => array('between', 5, 15),
'rule' => array('lengthBetween', 5, 15),
'message' => array('You may enter up to %s chars (minimum is %s chars)', 14, 6)
)
)
@ -1844,7 +1844,7 @@ class ModelValidationTest extends BaseModelTest {
$set = array(
'numeric' => array('rule' => 'numeric', 'allowEmpty' => false),
'range' => array('rule' => array('between', 1, 5), 'allowEmpty' => false),
'between' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
);
$Validator['other'] = $set;
$rules = $Validator['other'];
@ -1853,7 +1853,7 @@ class ModelValidationTest extends BaseModelTest {
$validators = $rules->getRules();
$this->assertCount(2, $validators);
$this->assertEquals('numeric', $validators['numeric']->rule);
$this->assertEquals(array('between', 1, 5), $validators['range']->rule);
$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
$Validator['new'] = new CakeValidationSet('new', $set, array());
$rules = $Validator['new'];
@ -1862,7 +1862,7 @@ class ModelValidationTest extends BaseModelTest {
$validators = $rules->getRules();
$this->assertCount(2, $validators);
$this->assertEquals('numeric', $validators['numeric']->rule);
$this->assertEquals(array('between', 1, 5), $validators['range']->rule);
$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
}
/**
@ -1917,7 +1917,7 @@ class ModelValidationTest extends BaseModelTest {
$set = array(
'numeric' => array('rule' => 'numeric', 'allowEmpty' => false),
'range' => array('rule' => array('between', 1, 5), 'allowEmpty' => false),
'range' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
);
$Validator['other'] = $set;
$this->assertCount(4, $Validator);
@ -1938,14 +1938,14 @@ class ModelValidationTest extends BaseModelTest {
$Validator = $TestModel->validator();
$Validator->add('other', 'numeric', array('rule' => 'numeric', 'allowEmpty' => false));
$Validator->add('other', 'range', array('rule' => array('between', 1, 5), 'allowEmpty' => false));
$Validator->add('other', 'between', array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false));
$rules = $Validator['other'];
$this->assertEquals('other', $rules->field);
$validators = $rules->getRules();
$this->assertCount(2, $validators);
$this->assertEquals('numeric', $validators['numeric']->rule);
$this->assertEquals(array('between', 1, 5), $validators['range']->rule);
$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
}
/**
@ -1962,13 +1962,13 @@ class ModelValidationTest extends BaseModelTest {
$this->assertFalse(isset($Validator['title']));
$Validator->add('other', 'numeric', array('rule' => 'numeric', 'allowEmpty' => false));
$Validator->add('other', 'range', array('rule' => array('between', 1, 5), 'allowEmpty' => false));
$Validator->add('other', 'between', array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false));
$this->assertTrue(isset($Validator['other']));
$Validator->remove('other', 'numeric');
$this->assertTrue(isset($Validator['other']));
$this->assertFalse(isset($Validator['other']['numeric']));
$this->assertTrue(isset($Validator['other']['range']));
$this->assertTrue(isset($Validator['other']['between']));
}
/**
@ -2126,7 +2126,7 @@ class ModelValidationTest extends BaseModelTest {
$set = array(
'numeric' => array('rule' => 'numeric', 'allowEmpty' => false),
'range' => array('rule' => array('between', 1, 5), 'allowEmpty' => false),
'between' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
);
$Validator->add('other', $set);
@ -2136,11 +2136,11 @@ class ModelValidationTest extends BaseModelTest {
$validators = $rules->getRules();
$this->assertCount(2, $validators);
$this->assertEquals('numeric', $validators['numeric']->rule);
$this->assertEquals(array('between', 1, 5), $validators['range']->rule);
$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
$set = new CakeValidationSet('other', array(
'a' => array('rule' => 'numeric', 'allowEmpty' => false),
'b' => array('rule' => array('between', 1, 5), 'allowEmpty' => false),
'b' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
));
$Validator->add('other', $set);

View file

@ -706,6 +706,258 @@ class ModelWriteTest extends BaseModelTest {
$this->assertFalse($result);
}
/**
* testSaveAtomic method
*
* @return void
*/
public function testSaveAtomic() {
$this->loadFixtures('Article');
$TestModel = new Article();
// Create record with 'atomic' = false
$data = array(
'Article' => array(
'user_id' => '1',
'title' => 'Fourth Article',
'body' => 'Fourth Article Body',
'published' => 'Y'
)
);
$TestModel->create();
$result = $TestModel->save($data, array('atomic' => false));
$this->assertTrue((bool)$result);
// Check record we created
$TestModel->recursive = -1;
$result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 4);
$expected = array(
'Article' => array(
'id' => '4',
'user_id' => '1',
'title' => 'Fourth Article',
'body' => 'Fourth Article Body',
'published' => 'Y'
)
);
$this->assertEquals($expected, $result);
// Create record with 'atomic' = true
$data = array(
'Article' => array(
'user_id' => '4',
'title' => 'Fifth Article',
'body' => 'Fifth Article Body',
'published' => 'Y'
)
);
$TestModel->create();
$result = $TestModel->save($data, array('atomic' => true));
$this->assertTrue((bool)$result);
// Check record we created
$TestModel->recursive = -1;
$result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 5);
$expected = array(
'Article' => array(
'id' => '5',
'user_id' => '4',
'title' => 'Fifth Article',
'body' => 'Fifth Article Body',
'published' => 'Y'
)
);
$this->assertEquals($expected, $result);
}
/**
* test save with transaction and ensure there is no missing rollback.
*
* @return void
*/
public function testSaveTransactionNoRollback() {
$this->loadFixtures('Post', 'Article');
$db = $this->getMock('DboSource', array('begin', 'connect', 'rollback', 'describe'));
$db->expects($this->once())
->method('describe')
->will($this->returnValue(array()));
$db->expects($this->once())
->method('begin')
->will($this->returnValue(true));
$db->expects($this->once())
->method('rollback');
$Post = new TestPost();
$Post->setDataSourceObject($db);
$callback = array($this, 'callbackForTestSaveTransaction');
$Post->getEventManager()->attach($callback, 'Model.beforeSave');
$data = array(
'Post' => array(
'author_id' => 1,
'title' => 'New Fourth Post'
)
);
$Post->save($data, array('atomic' => true));
}
/**
* test callback used in testSaveTransaction method
*
* @return bool false to stop event propagation
*/
public function callbackForTestSaveTransaction($event) {
$TestModel = new Article();
// Create record. Do not use same model as in testSaveTransaction
// to avoid infinite loop.
$data = array(
'Article' => array(
'user_id' => '1',
'title' => 'Fourth Article',
'body' => 'Fourth Article Body',
'published' => 'Y'
)
);
$TestModel->create();
$result = $TestModel->save($data);
$this->assertTrue((bool)$result);
// force transaction to be rolled back in Post model
$event->stopPropagation();
return false;
}
/**
* testSaveTransaction method
*
* @return void
*/
public function testSaveTransaction() {
$this->loadFixtures('Post', 'Article');
$PostModel = new Post();
// Check if Database supports transactions
$PostModel->validate = array('title' => 'notEmpty');
$data = array(
array('author_id' => 1, 'title' => 'New Fourth Post'),
array('author_id' => 1, 'title' => 'New Fifth Post'),
array('author_id' => 1, 'title' => '')
);
$this->assertFalse($PostModel->saveAll($data));
$result = $PostModel->find('all', array('recursive' => -1));
$expectedPosts = array(
array(
'Post' => array(
'id' => '1',
'author_id' => 1,
'title' => 'First Post',
'body' => 'First Post Body',
'published' => 'Y',
'created' => '2007-03-18 10:39:23',
'updated' => '2007-03-18 10:41:31'
)
),
array(
'Post' => array(
'id' => '2',
'author_id' => 3,
'title' => 'Second Post',
'body' => 'Second Post Body',
'published' => 'Y',
'created' => '2007-03-18 10:41:23',
'updated' => '2007-03-18 10:43:31'
)
),
array(
'Post' => array(
'id' => '3',
'author_id' => 1,
'title' => 'Third Post',
'body' => 'Third Post Body',
'published' => 'Y',
'created' => '2007-03-18 10:43:23',
'updated' => '2007-03-18 10:45:31'
)
)
);
$this->skipIf(count($result) !== 3, 'Database does not support transactions.');
$this->assertEquals($expectedPosts, $result);
// Database supports transactions --> continue tests
$data = array(
'Post' => array(
'author_id' => 1,
'title' => 'New Fourth Post'
)
);
$callback = array($this, 'callbackForTestSaveTransaction');
$PostModel->getEventManager()->attach($callback, 'Model.beforeSave');
$PostModel->create();
$result = $PostModel->save($data, array('atomic' => true));
$this->assertFalse($result);
$result = $PostModel->find('all', array('recursive' => -1));
$this->assertEquals($expectedPosts, $result);
// Check record we created in callbackForTestSaveTransaction method.
// record should not exist due to rollback
$ArticleModel = new Article();
$result = $ArticleModel->find('all', array('recursive' => -1));
$expectedArticles = array(
array(
'Article' => array(
'user_id' => '1',
'title' => 'First Article',
'body' => 'First Article Body',
'published' => 'Y',
'created' => '2007-03-18 10:39:23',
'updated' => '2007-03-18 10:41:31',
'id' => '1'
)
),
array(
'Article' => array(
'user_id' => '3',
'title' => 'Second Article',
'body' => 'Second Article Body',
'published' => 'Y',
'created' => '2007-03-18 10:41:23',
'updated' => '2007-03-18 10:43:31',
'id' => '2'
)
),
array(
'Article' => array(
'user_id' => '1',
'title' => 'Third Article',
'body' => 'Third Article Body',
'published' => 'Y',
'created' => '2007-03-18 10:43:23',
'updated' => '2007-03-18 10:45:31',
'id' => '3'
)
)
);
$this->assertEquals($expectedArticles, $result);
}
/**
* testSaveField method
*
@ -1869,7 +2121,9 @@ class ModelWriteTest extends BaseModelTest {
$data = array('Item' => array('Item' => array(1, 2)));
$TestModel->id = 2;
$TestModel->save($data);
$result = $TestModel->save($data);
$this->assertTrue((bool)$result);
$result = $TestModel->findById(2);
$result['Item'] = Hash::sort($result['Item'], '{n}.id', 'asc');
$expected = array(

View file

@ -732,8 +732,14 @@ class ModifiedAttachment extends CakeTestModel {
* @return void
*/
public function afterFind($results, $primary = false) {
if (isset($results['id'])) {
$results['callback'] = 'Fired';
if ($this->useConsistentAfterFind) {
if (isset($results[0][$this->alias]['id'])) {
$results[0][$this->alias]['callback'] = 'Fired';
}
} else {
if (isset($results['id'])) {
$results['callback'] = 'Fired';
}
}
return $results;
}

View file

@ -1995,26 +1995,6 @@ class CakeRequestTest extends CakeTestCase {
$this->assertNull($result);
}
/**
* Test using param()
*
* @return void
*/
public function testReadingParams() {
$request = new CakeRequest();
$request->addParams(array(
'controller' => 'posts',
'admin' => true,
'truthy' => 1,
'zero' => '0',
));
$this->assertFalse($request->param('not_set'));
$this->assertTrue($request->param('admin'));
$this->assertEquals(1, $request->param('truthy'));
$this->assertEquals('posts', $request->param('controller'));
$this->assertEquals('0', $request->param('zero'));
}
/**
* Test the data() method reading
*
@ -2077,6 +2057,100 @@ class CakeRequestTest extends CakeTestCase {
$this->assertSame('', $request->data['Post']['empty']);
}
/**
* Test reading params
*
* @dataProvider paramReadingDataProvider
*/
public function testParamReading($toRead, $expected) {
$request = new CakeRequest('/');
$request->addParams(array(
'action' => 'index',
'foo' => 'bar',
'baz' => array(
'a' => array(
'b' => 'c',
),
),
'admin' => true,
'truthy' => 1,
'zero' => '0',
));
$this->assertEquals($expected, $request->param($toRead));
}
/**
* Data provider for testing reading values with CakeRequest::param()
*
* @return array
*/
public function paramReadingDataProvider() {
return array(
array(
'action',
'index',
),
array(
'baz',
array(
'a' => array(
'b' => 'c',
),
),
),
array(
'baz.a.b',
'c',
),
array(
'does_not_exist',
false,
),
array(
'admin',
true,
),
array(
'truthy',
1,
),
array(
'zero',
'0',
),
);
}
/**
* test writing request params with param()
*
* @return void
*/
public function testParamWriting() {
$request = new CakeRequest('/');
$request->addParams(array(
'action' => 'index',
));
$this->assertInstanceOf('CakeRequest', $request->param('some', 'thing'), 'Method has not returned $this');
$request->param('Post.null', null);
$this->assertNull($request->params['Post']['null']);
$request->param('Post.false', false);
$this->assertFalse($request->params['Post']['false']);
$request->param('Post.zero', 0);
$this->assertSame(0, $request->params['Post']['zero']);
$request->param('Post.empty', '');
$this->assertSame('', $request->params['Post']['empty']);
$this->assertSame('index', $request->action);
$request->param('action', 'edit');
$this->assertSame('edit', $request->action);
}
/**
* Test accept language
*
@ -2158,6 +2232,22 @@ class CakeRequestTest extends CakeTestCase {
$this->assertEquals('/admin/settings/settings/prefix/Access%20Control', $result);
}
/**
* Test the input() method.
*
* @return void
*/
public function testSetInput() {
$request = new CakeRequest('/');
$request->setInput('I came from setInput');
$result = $request->input();
$this->assertEquals('I came from setInput', $result);
$result = $request->input();
$this->assertEquals('I came from setInput', $result);
}
/**
* Test the input() method.
*

View file

@ -1199,6 +1199,10 @@ class CakeResponseTest extends CakeTestCase {
->will($this->returnArgument(0));
$response->expects($this->at(1))
->method('header')
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(2))
->method('header')
->with('Content-Length', 38);
@ -1215,7 +1219,7 @@ class CakeResponseTest extends CakeTestCase {
$result = $response->send();
$output = ob_get_clean();
$this->assertEquals("/* this is the test asset css file */\n", $output);
$this->assertTrue($result !== false);
$this->assertNotSame(false, $result);
}
/**
@ -1249,11 +1253,11 @@ class CakeResponseTest extends CakeTestCase {
$response->expects($this->at(2))
->method('header')
->with('Accept-Ranges', 'bytes');
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(3))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(4))
->method('header')
@ -1272,7 +1276,7 @@ class CakeResponseTest extends CakeTestCase {
$result = $response->send();
$output = ob_get_clean();
$this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
$this->assertTrue($result !== false);
$this->assertNotSame(false, $result);
if ($currentUserAgent !== null) {
$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
}
@ -1314,11 +1318,11 @@ class CakeResponseTest extends CakeTestCase {
$response->expects($this->at(3))
->method('header')
->with('Accept-Ranges', 'bytes');
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(4))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(5))
->method('header')
@ -1336,7 +1340,7 @@ class CakeResponseTest extends CakeTestCase {
$result = $response->send();
$output = ob_get_clean();
$this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
$this->assertTrue($result !== false);
$this->assertNotSame(false, $result);
if ($currentUserAgent !== null) {
$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
}
@ -1378,11 +1382,11 @@ class CakeResponseTest extends CakeTestCase {
$response->expects($this->at(3))
->method('header')
->with('Accept-Ranges', 'bytes');
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(4))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(5))
->method('header')
@ -1402,7 +1406,7 @@ class CakeResponseTest extends CakeTestCase {
$result = $response->send();
$output = ob_get_clean();
$this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
$this->assertTrue($result !== false);
$this->assertNotSame(false, $result);
if ($currentUserAgent !== null) {
$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
}
@ -1432,6 +1436,10 @@ class CakeResponseTest extends CakeTestCase {
->with('ini')
->will($this->returnValue(false));
$response->expects($this->at(1))
->method('header')
->with('Accept-Ranges', 'bytes');
$response->expects($this->never())
->method('download');
@ -1584,11 +1592,11 @@ class CakeResponseTest extends CakeTestCase {
$response->expects($this->at(2))
->method('header')
->with('Accept-Ranges', 'bytes');
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(3))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(4))
->method('header')
@ -1639,11 +1647,11 @@ class CakeResponseTest extends CakeTestCase {
$response->expects($this->at(2))
->method('header')
->with('Accept-Ranges', 'bytes');
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(3))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(4))
->method('header')
@ -1668,7 +1676,7 @@ class CakeResponseTest extends CakeTestCase {
$output = ob_get_clean();
$this->assertEquals(206, $response->statusCode());
$this->assertEquals("is the test asset ", $output);
$this->assertTrue($result !== false);
$this->assertNotSame(false, $result);
}
/**
@ -1694,11 +1702,11 @@ class CakeResponseTest extends CakeTestCase {
$response->expects($this->at(2))
->method('header')
->with('Accept-Ranges', 'bytes');
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(3))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(4))
->method('header')
@ -1715,6 +1723,136 @@ class CakeResponseTest extends CakeTestCase {
$result = $response->send();
}
/**
* testFileRangeOffsetsNoDownload method
*
* @dataProvider rangeProvider
* @return void
*/
public function testFileRangeOffsetsNoDownload($range, $length, $offsetResponse) {
$_SERVER['HTTP_RANGE'] = $range;
$response = $this->getMock('CakeResponse', array(
'header',
'type',
'_sendHeader',
'_isActive',
'_clearBuffer',
'_flushBuffer'
));
$response->expects($this->at(1))
->method('header')
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(2))
->method('header')
->with(array(
'Content-Length' => $length,
'Content-Range' => $offsetResponse,
));
$response->expects($this->any())
->method('_isActive')
->will($this->returnValue(true));
$response->file(
CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
array('download' => false)
);
ob_start();
$result = $response->send();
ob_get_clean();
}
/**
* testFileRangeNoDownload method
*
* @return void
*/
public function testFileRangeNoDownload() {
$_SERVER['HTTP_RANGE'] = 'bytes=8-25';
$response = $this->getMock('CakeResponse', array(
'header',
'type',
'_sendHeader',
'_setContentType',
'_isActive',
'_clearBuffer',
'_flushBuffer'
));
$response->expects($this->exactly(1))
->method('type')
->with('css')
->will($this->returnArgument(0));
$response->expects($this->at(1))
->method('header')
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(2))
->method('header')
->with(array(
'Content-Length' => 18,
'Content-Range' => 'bytes 8-25/38',
));
$response->expects($this->once())->method('_clearBuffer');
$response->expects($this->any())
->method('_isActive')
->will($this->returnValue(true));
$response->file(
CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
array('download' => false)
);
ob_start();
$result = $response->send();
$output = ob_get_clean();
$this->assertEquals(206, $response->statusCode());
$this->assertEquals("is the test asset ", $output);
$this->assertNotSame(false, $result);
}
/**
* testFileRangeInvalidNoDownload method
*
* @return void
*/
public function testFileRangeInvalidNoDownload() {
$_SERVER['HTTP_RANGE'] = 'bytes=30-2';
$response = $this->getMock('CakeResponse', array(
'header',
'type',
'_sendHeader',
'_setContentType',
'_isActive',
'_clearBuffer',
'_flushBuffer'
));
$response->expects($this->at(1))
->method('header')
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(2))
->method('header')
->with(array(
'Content-Range' => 'bytes 0-37/38',
));
$response->file(
CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
array('download' => false)
);
$this->assertEquals(416, $response->statusCode());
$result = $response->send();
}
/**
* Test the location method.
*

View file

@ -56,7 +56,7 @@ class CakeSocketTest extends CakeTestCase {
$this->assertSame($config, array(
'persistent' => false,
'host' => 'localhost',
'protocol' => getprotobyname('tcp'),
'protocol' => 'tcp',
'port' => 80,
'timeout' => 30
));
@ -71,7 +71,7 @@ class CakeSocketTest extends CakeTestCase {
$config['host'] = 'www.cakephp.org';
$config['port'] = 23;
$config['protocol'] = 17;
$config['protocol'] = 'udp';
$this->assertSame($this->Socket->config, $config);
}

View file

@ -217,7 +217,6 @@ class HttpSocketTest extends CakeTestCase {
$this->Socket->expects($this->never())->method('connect');
$this->Socket->__construct(array('host' => 'foo-bar'));
$baseConfig['host'] = 'foo-bar';
$baseConfig['protocol'] = getprotobyname($baseConfig['protocol']);
$this->assertEquals($this->Socket->config, $baseConfig);
$this->Socket->reset();
@ -226,7 +225,6 @@ class HttpSocketTest extends CakeTestCase {
$baseConfig['host'] = $baseConfig['request']['uri']['host'] = 'www.cakephp.org';
$baseConfig['port'] = $baseConfig['request']['uri']['port'] = 23;
$baseConfig['request']['uri']['scheme'] = 'http';
$baseConfig['protocol'] = getprotobyname($baseConfig['protocol']);
$this->assertEquals($this->Socket->config, $baseConfig);
$this->Socket->reset();
@ -495,6 +493,9 @@ class HttpSocketTest extends CakeTestCase {
)
)
),
'reset10' => array(
'config.protocol' => 'ssl'
),
array(
'request' => array(
'method' => 'POST',
@ -523,6 +524,9 @@ class HttpSocketTest extends CakeTestCase {
)
)
),
'reset11' => array(
'config.protocol' => 'ssl'
),
array(
'request' => array(
'version' => '1.0',
@ -1048,6 +1052,54 @@ class HttpSocketTest extends CakeTestCase {
));
}
/**
* Test the head method
*
* @return void
*/
public function testHead() {
$this->RequestSocket->reset();
$this->RequestSocket->expects($this->at(0))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'http://www.google.com/'));
$this->RequestSocket->expects($this->at(1))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'http://www.google.com/?foo=bar'));
$this->RequestSocket->expects($this->at(2))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'http://www.google.com/?foo=bar'));
$this->RequestSocket->expects($this->at(3))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'http://www.google.com/?foo=23&foobar=42'));
$this->RequestSocket->expects($this->at(4))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'http://www.google.com/', 'version' => '1.0'));
$this->RequestSocket->expects($this->at(5))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'https://secure.example.com/test.php?one=two'));
$this->RequestSocket->expects($this->at(6))
->method('request')
->with(array('method' => 'HEAD', 'uri' => 'https://example.com/oauth/access?clientid=123&redirect_uri=http%3A%2F%2Fexample.com&code=456'));
$this->RequestSocket->head('http://www.google.com/');
$this->RequestSocket->head('http://www.google.com/', array('foo' => 'bar'));
$this->RequestSocket->head('http://www.google.com/', 'foo=bar');
$this->RequestSocket->head('http://www.google.com/?foo=bar', array('foobar' => '42', 'foo' => '23'));
$this->RequestSocket->head('http://www.google.com/', null, array('version' => '1.0'));
$this->RequestSocket->head('https://secure.example.com/test.php', array('one' => 'two'));
$this->RequestSocket->head('https://example.com/oauth/access', array(
'clientid' => '123',
'redirect_uri' => 'http://example.com',
'code' => 456
));
}
/**
* Test authentication
*

View file

@ -977,4 +977,34 @@ class CakeRouteTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
/**
* Test for __set_state magic method on CakeRoute
*
* @return void
*/
public function testSetState() {
$route = CakeRoute::__set_state(array(
'keys' => array(),
'options' => array(),
'defaults' => array(
'controller' => 'pages',
'action' => 'display',
'home',
),
'template' => '/',
'_greedy' => false,
'_compiledRoute' => null,
'_headerMap' => array (
'type' => 'content_type',
'method' => 'request_method',
'server' => 'server_name',
),
));
$this->assertInstanceOf('CakeRoute', $route);
$this->assertSame('/', $route->match(array('controller' => 'pages', 'action' => 'display', 'home')));
$this->assertFalse($route->match(array('controller' => 'pages', 'action' => 'display', 'about')));
$expected = array('controller' => 'pages', 'action' => 'display', 'pass' => array('home'), 'named' => array());
$this->assertEquals($expected, $route->parse('/'));
}
}

View file

@ -108,9 +108,9 @@ class CakeTimeTest extends CakeTestCase {
array('-2 days -3 hours', '2 days, 3 hours ago'),
array('-1 week', '1 week ago'),
array('-2 weeks -2 days', '2 weeks, 2 days ago'),
array('+1 week', '1 week'),
array('+1 week 1 day', '1 week, 1 day'),
array('+2 weeks 2 day', '2 weeks, 2 days'),
array('+1 week', 'in 1 week'),
array('+1 week 1 day', 'in 1 week, 1 day'),
array('+2 weeks 2 day', 'in 2 weeks, 2 days'),
array('2007-9-24', 'on 24/9/07'),
array('now', 'just now'),
);
@ -136,37 +136,37 @@ class CakeTimeTest extends CakeTestCase {
return array(
array(
'+4 months +2 weeks +3 days',
'4 months, 2 weeks, 3 days',
'in 4 months, 2 weeks, 3 days',
'8 years'
),
array(
'+4 months +2 weeks +1 day',
'4 months, 2 weeks, 1 day',
'in 4 months, 2 weeks, 1 day',
'8 years'
),
array(
'+3 months +2 weeks',
'3 months, 2 weeks',
'in 3 months, 2 weeks',
'8 years'
),
array(
'+3 months +2 weeks +1 day',
'3 months, 2 weeks, 1 day',
'in 3 months, 2 weeks, 1 day',
'8 years'
),
array(
'+1 months +1 week +1 day',
'1 month, 1 week, 1 day',
'in 1 month, 1 week, 1 day',
'8 years'
),
array(
'+2 months +2 days',
'2 months, 2 days',
'in 2 months, 2 days',
'on ' . date('j/n/y', strtotime('+2 months +2 days'))
),
array(
'+2 months +12 days',
'2 months, 1 week, 5 days',
'in 2 months, 1 week, 5 days',
'3 months'
),
);
@ -198,6 +198,13 @@ class CakeTimeTest extends CakeTestCase {
$expected = 'at least 8 years ago';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('relativeStringFuture' => 'not in the next %s', 'accuracy' => array('year' => 'year'), 'end' => '+10 years')
);
$expected = 'not in the next 8 years';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+4 months +2 weeks +3 days'),
array('absoluteString' => 'exactly on %s', 'accuracy' => array('year' => 'year'), 'end' => '+2 months')
@ -216,35 +223,35 @@ class CakeTimeTest extends CakeTestCase {
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'year'), 'end' => '+10 years')
);
$expected = '8 years';
$expected = 'in 8 years';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'month'), 'end' => '+10 years')
);
$expected = '8 years, 4 months';
$expected = 'in 8 years, 4 months';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'week'), 'end' => '+10 years')
);
$expected = '8 years, 4 months, 2 weeks';
$expected = 'in 8 years, 4 months, 2 weeks';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'day'), 'end' => '+10 years')
);
$expected = '8 years, 4 months, 2 weeks, 3 days';
$expected = 'in 8 years, 4 months, 2 weeks, 3 days';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+1 years +5 weeks'),
array('accuracy' => array('year' => 'year'), 'end' => '+10 years')
);
$expected = '1 year';
$expected = 'in 1 year';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
@ -263,7 +270,7 @@ class CakeTimeTest extends CakeTestCase {
}
/**
* Test the format option of timeAgoInWords()
* Test the format option of timeAgoInWords() with date() and strftime compatible strings
*
* @return void
*/
@ -271,20 +278,32 @@ class CakeTimeTest extends CakeTestCase {
$result = $this->Time->timeAgoInWords('2007-9-25', 'Y-m-d');
$this->assertEquals('on 2007-09-25', $result);
$result = $this->Time->timeAgoInWords('2007-9-25', 'Y-m-d');
$this->assertEquals('on 2007-09-25', $result);
$result = $this->Time->timeAgoInWords('2007-9-25', '%x');
$this->assertEquals('on ' . strftime('%x', strtotime('2007-9-25')), $result);
$result = $this->Time->timeAgoInWords(
strtotime('+2 weeks +2 days'),
'Y-m-d'
);
$this->assertRegExp('/^2 weeks, [1|2] day(s)?$/', $result);
$this->assertRegExp('/^in 2 weeks, [1|2] day(s)?$/', $result);
$result = $this->Time->timeAgoInWords(
strtotime('+2 weeks +2 days'),
'%x'
);
$this->assertRegExp('/^in 2 weeks, [1|2] day(s)?$/', $result);
$result = $this->Time->timeAgoInWords(
strtotime('+2 months +2 days'),
array('end' => '1 month', 'format' => 'Y-m-d')
);
$this->assertEquals('on ' . date('Y-m-d', strtotime('+2 months +2 days')), $result);
$result = $this->Time->timeAgoInWords(
strtotime('+2 months +2 days'),
array('end' => '1 month', 'format' => '%x')
);
$this->assertEquals('on ' . strftime('%x', strtotime('+2 months +2 days')), $result);
}
/**

View file

@ -81,8 +81,7 @@ class FileTest extends CakeTestCase {
'filesize' => filesize($file),
'mime' => 'text/plain'
);
if (
!function_exists('finfo_open') &&
if (!function_exists('finfo_open') &&
(!function_exists('mime_content_type') ||
function_exists('mime_content_type') &&
mime_content_type($this->File->pwd()) === false)

View file

@ -564,6 +564,8 @@ class FolderTest extends CakeTestCase {
$this->assertFalse(Folder::isAbsolute('0:\\path\\to\\file'));
$this->assertFalse(Folder::isAbsolute('\\path/to/file'));
$this->assertFalse(Folder::isAbsolute('\\path\\to\\file'));
$this->assertFalse(Folder::isAbsolute('notRegisteredStreamWrapper://example'));
$this->assertFalse(Folder::isAbsolute('://example'));
$this->assertTrue(Folder::isAbsolute('/usr/local'));
$this->assertTrue(Folder::isAbsolute('//path/to/file'));
@ -571,6 +573,7 @@ class FolderTest extends CakeTestCase {
$this->assertTrue(Folder::isAbsolute('C:\\path\\to\\file'));
$this->assertTrue(Folder::isAbsolute('d:\\path\\to\\file'));
$this->assertTrue(Folder::isAbsolute('\\\\vmware-host\\Shared Folders\\file'));
$this->assertTrue(Folder::isAbsolute('http://www.example.com'));
}
/**

View file

@ -229,6 +229,16 @@ class HashTest extends CakeTestCase {
$this->assertEquals($data[1]['Article'], $result);
}
/**
* Test get() with an invalid path
*
* @expectedException InvalidArgumentException
* @return void
*/
public function testGetInvalidPath() {
Hash::get(array('one' => 'two'), true);
}
/**
* Test dimensions.
*
@ -2286,8 +2296,9 @@ class HashTest extends CakeTestCase {
}
/**
* Tests that nest() returns an empty array for invalid input instead of throwing notices.
* Tests that nest() throws an InvalidArgumentException when providing an invalid input.
*
* @expectedException InvalidArgumentException
* @return void
*/
public function testNestInvalid() {
@ -2300,8 +2311,7 @@ class HashTest extends CakeTestCase {
)
)
);
$result = Hash::nest($input);
$this->assertSame(array(), $result);
Hash::nest($input);
}
/**

View file

@ -186,6 +186,10 @@ class InflectorTest extends CakeTestCase {
* @return void
*/
public function testInflectingPlurals() {
$this->assertEquals(Inflector::pluralize('axman'), 'axmen');
$this->assertEquals(Inflector::pluralize('man'), 'men');
$this->assertEquals(Inflector::pluralize('woman'), 'women');
$this->assertEquals(Inflector::pluralize('human'), 'humans');
$this->assertEquals(Inflector::pluralize('categoria'), 'categorias');
$this->assertEquals(Inflector::pluralize('house'), 'houses');
$this->assertEquals(Inflector::pluralize('powerhouse'), 'powerhouses');

View file

@ -203,17 +203,17 @@ class ValidationTest extends CakeTestCase {
}
/**
* testBetween method
* testLengthBetween method
*
* @return void
*/
public function testBetween() {
$this->assertTrue(Validation::between('abcdefg', 1, 7));
$this->assertTrue(Validation::between('', 0, 7));
$this->assertTrue(Validation::between('אกあアꀀ豈', 1, 7));
public function testLengthBetween() {
$this->assertTrue(Validation::lengthBetween('abcdefg', 1, 7));
$this->assertTrue(Validation::lengthBetween('', 0, 7));
$this->assertTrue(Validation::lengthBetween('אกあアꀀ豈', 1, 7));
$this->assertFalse(Validation::between('abcdefg', 1, 6));
$this->assertFalse(Validation::between('ÆΔΩЖÇ', 1, 3));
$this->assertFalse(Validation::lengthBetween('abcdefg', 1, 6));
$this->assertFalse(Validation::lengthBetween('ÆΔΩЖÇ', 1, 3));
}
/**

View file

@ -2046,7 +2046,7 @@ class FormHelperTest extends CakeTestCase {
'Email',
'/label',
array('input' => array(
'type' => 'text', 'name' => 'data[Contact][email]',
'maxlength' => 255, 'type' => 'text', 'name' => 'data[Contact][email]',
'id' => 'ContactEmail'
)),
'/div'
@ -2060,7 +2060,7 @@ class FormHelperTest extends CakeTestCase {
'Email',
'/label',
array('input' => array(
'type' => 'text', 'name' => 'data[Contact][5][email]',
'maxlength' => 255, 'type' => 'text', 'name' => 'data[Contact][5][email]',
'id' => 'Contact5Email'
)),
'/div'
@ -7464,6 +7464,37 @@ class FormHelperTest extends CakeTestCase {
$this->assertTags($result, $expected);
}
/**
* Test textareas maxlength reading from schema.
*
* @return void
*/
public function testTextAreaMaxLength() {
$result = $this->Form->input('UserForm.other', array('type' => 'textarea'));
$expected = array(
'div' => array('class' => 'input textarea'),
'label' => array('for' => 'UserFormOther'),
'Other',
'/label',
'textarea' => array('name' => 'data[UserForm][other]', 'cols' => '30', 'rows' => '6', 'id' => 'UserFormOther'),
'/textarea',
'/div'
);
$this->assertTags($result, $expected);
$result = $this->Form->input('UserForm.stuff', array('type' => 'textarea'));
$expected = array(
'div' => array('class' => 'input textarea'),
'label' => array('for' => 'UserFormStuff'),
'Stuff',
'/label',
'textarea' => array('name' => 'data[UserForm][stuff]', 'maxlength' => 10, 'cols' => '30', 'rows' => '6', 'id' => 'UserFormStuff'),
'/textarea',
'/div'
);
$this->assertTags($result, $expected);
}
/**
* testTextAreaWithStupidCharacters method
*
@ -9586,6 +9617,7 @@ class FormHelperTest extends CakeTestCase {
'textarea' => array(
'id' => 'ValidateProfile1ValidateItem2Name',
'name' => 'data[ValidateProfile][1][ValidateItem][2][name]',
'maxlength' => 255,
'cols' => 30,
'rows' => 6
),
@ -9702,7 +9734,7 @@ class FormHelperTest extends CakeTestCase {
$expected = array(
'div' => array('class' => 'input text'),
'input' => array(
'type' => 'text', 'name' => 'data[Contact][email]',
'maxlength' => 255, 'type' => 'text', 'name' => 'data[Contact][email]',
'id' => 'ContactEmail'
),
'/div'
@ -9716,7 +9748,7 @@ class FormHelperTest extends CakeTestCase {
$expected = array(
'div' => array('class' => 'input text'),
array('input' => array(
'type' => 'text', 'name' => 'data[Contact][email]',
'maxlength' => 255, 'type' => 'text', 'name' => 'data[Contact][email]',
'id' => 'ContactEmail'
)),
'label' => array('for' => 'ContactEmail'),
@ -9736,7 +9768,7 @@ class FormHelperTest extends CakeTestCase {
$expected = array(
'div' => array('class' => 'input text'),
array('input' => array(
'type' => 'text', 'name' => 'data[Contact][email]',
'maxlength' => 255, 'type' => 'text', 'name' => 'data[Contact][email]',
'id' => 'ContactEmail'
)),
array('div' => array()),

View file

@ -696,6 +696,31 @@ class HtmlHelperTest extends CakeTestCase {
$this->assertTags($result, $expected);
}
/**
* Test css() with once option.
*
* @return void
*/
public function testCssLinkOnce() {
Configure::write('Asset.filter.css', false);
$result = $this->Html->css('screen', array('once' => true));
$expected = array(
'link' => array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => 'preg:/.*css\/screen\.css/')
);
$this->assertTags($result, $expected);
$result = $this->Html->css('screen', array('once' => true));
$this->assertEquals('', $result);
// Default is once=false
$result = $this->Html->css('screen');
$expected = array(
'link' => array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => 'preg:/.*css\/screen\.css/')
);
$this->assertTags($result, $expected);
}
/**
* Test css link BC usage
*
@ -874,6 +899,22 @@ class HtmlHelperTest extends CakeTestCase {
CakePlugin::unload('TestPlugin');
}
/**
* Resource names must be treated differently for css() and script()
*
* @return void
*/
public function testBufferedCssAndScriptWithIdenticalResourceName() {
$this->View->expects($this->at(0))
->method('append')
->with('css', $this->stringContains('test.min.css'));
$this->View->expects($this->at(1))
->method('append')
->with('script', $this->stringContains('test.min.js'));
$this->Html->css('test.min', array('inline' => false));
$this->Html->script('test.min', array('inline' => false));
}
/**
* test timestamp enforcement for script tags.
*

View file

@ -1006,6 +1006,23 @@ class PaginatorHelperTest extends CakeTestCase {
)
);
$result = $this->Paginator->prev('<i class="fa fa-angle-left"></i>', array('escape' => false), null, array('class' => 'prev disabled'));
$expected = array(
'span' => array('class' => 'prev disabled'),
'i' => array('class' => 'fa fa-angle-left'),
'/i',
'/span'
);
$this->assertTags($result, $expected);
$result = $this->Paginator->prev('<i class="fa fa-angle-left"></i>', array('escape' => false), null, array('escape' => true));
$expected = array(
'span' => array('class' => 'prev'),
'&lt;i class=&quot;fa fa-angle-left&quot;&gt;&lt;/i&gt;',
'/span'
);
$this->assertTags($result, $expected);
$result = $this->Paginator->prev('<< Previous', null, '<strong>Disabled</strong>');
$expected = array(
'span' => array('class' => 'prev'),
@ -2731,9 +2748,9 @@ class PaginatorHelperTest extends CakeTestCase {
'paramType' => 'named',
)
);
$this->assertFalse($this->Paginator->numbers());
$this->assertFalse($this->Paginator->first());
$this->assertFalse($this->Paginator->last());
$this->assertSame('', $this->Paginator->numbers());
$this->assertSame('', $this->Paginator->first());
$this->assertSame('', $this->Paginator->last());
}
/**
@ -2763,4 +2780,110 @@ class PaginatorHelperTest extends CakeTestCase {
$expected = '0 of 1';
$this->assertEquals($expected, $result);
}
/**
* Verify that no next and prev links are created for single page results
*
* @return void
*/
public function testMetaPage0() {
$this->Paginator->request['paging'] = array(
'Article' => array(
'page' => 1,
'prevPage' => false,
'nextPage' => false,
'pageCount' => 1,
)
);
$expected = '';
$result = $this->Paginator->meta();
$this->assertSame($expected, $result);
}
/**
* Verify that page 1 only has a next link
*
* @return void
*/
public function testMetaPage1() {
$this->Paginator->request['paging'] = array(
'Article' => array(
'page' => 1,
'prevPage' => false,
'nextPage' => true,
'pageCount' => 2,
'options' => array(),
'paramType' => 'querystring'
)
);
$expected = '<link href="/?page=2" rel="next" />';
$result = $this->Paginator->meta();
$this->assertSame($expected, $result);
}
/**
* Verify that the method will append to a block
*
* @return void
*/
public function testMetaPage1InlineFalse() {
$this->Paginator->request['paging'] = array(
'Article' => array(
'page' => 1,
'prevPage' => false,
'nextPage' => true,
'pageCount' => 2,
'options' => array(),
'paramType' => 'querystring'
)
);
$expected = '<link href="/?page=2" rel="next" />';
$this->Paginator->meta(array('block' => true));
$result = $this->View->fetch('meta');
$this->assertSame($expected, $result);
}
/**
* Verify that the last page only has a prev link
*
* @return void
*/
public function testMetaPage1Last() {
$this->Paginator->request['paging'] = array(
'Article' => array(
'page' => 2,
'prevPage' => true,
'nextPage' => false,
'pageCount' => 2,
'options' => array(),
'paramType' => 'querystring'
)
);
$expected = '<link href="/" rel="prev" />';
$result = $this->Paginator->meta();
$this->assertSame($expected, $result);
}
/**
* Verify that a page in the middle has both links
*
* @return void
*/
public function testMetaPage10Last() {
$this->Paginator->request['paging'] = array(
'Article' => array(
'page' => 5,
'prevPage' => true,
'nextPage' => true,
'pageCount' => 10,
'options' => array(),
'paramType' => 'querystring'
)
);
$expected = '<link href="/?page=4" rel="prev" />';
$expected .= '<link href="/?page=6" rel="next" />';
$result = $this->Paginator->meta();
$this->assertSame($expected, $result);
}
}

View file

@ -175,7 +175,7 @@ class TimeHelperTest extends CakeTestCase {
'title' => $timestamp,
'class' => 'time-ago-in-words'
),
'2 weeks',
'in 2 weeks',
'/div'
);
$this->assertTags($result, $expected);

View file

@ -77,9 +77,6 @@ class MediaViewTest extends CakeTestCase {
array('name' => null, 'download' => null)
);
$this->MediaView->response->expects($this->once())
->method('send');
$this->MediaView->render();
}
@ -115,9 +112,6 @@ class MediaViewTest extends CakeTestCase {
)
);
$this->MediaView->response->expects($this->once())
->method('send');
$this->MediaView->render();
}
@ -137,10 +131,6 @@ class MediaViewTest extends CakeTestCase {
->with('jpg')
->will($this->returnArgument(0));
$this->MediaView->response->expects($this->at(0))
->method('send')
->will($this->returnValue(true));
$this->MediaView->render();
}

View file

@ -22,6 +22,8 @@ App::uses('Controller', 'Controller');
App::uses('CacheHelper', 'View/Helper');
App::uses('HtmlHelper', 'View/Helper');
App::uses('ErrorHandler', 'Error');
App::uses('CakeEventManager', 'Event');
App::uses('CakeEventListener', 'Event');
/**
* ViewPostsController class
@ -238,6 +240,61 @@ class TestObjectWithToString {
class TestObjectWithoutToString {
}
/**
* Class TestViewEventListener
*
* An event listener to test cakePHP events
*/
class TestViewEventListener implements CakeEventListener {
/**
* type of view before rendering has occurred
*
* @var string
*/
public $beforeRenderViewType;
/**
* type of view after rendering has occurred
*
* @var string
*/
public $afterRenderViewType;
/**
* implementedEvents method
*
* @return array
*/
public function implementedEvents() {
return array(
'View.beforeRender' => 'beforeRender',
'View.afterRender' => 'afterRender'
);
}
/**
* beforeRender method
*
* @param CakeEvent $event the event being sent
* @return void
*/
public function beforeRender($event) {
$this->beforeRenderViewType = $event->subject()->getCurrentType();
}
/**
* afterRender method
*
* @param CakeEvent $event the event being sent
* @return void
*/
public function afterRender($event) {
$this->afterRenderViewType = $event->subject()->getCurrentType();
}
}
/**
* ViewTest class
*
@ -808,6 +865,30 @@ class ViewTest extends CakeTestCase {
Cache::drop('test_view');
}
/**
* Test element events
*
* @return void
*/
public function testViewEvent() {
$View = new View($this->PostsController);
$View->autoLayout = false;
$listener = new TestViewEventListener();
$View->getEventManager()->attach($listener);
$View->render('index');
$this->assertEquals(View::TYPE_VIEW, $listener->beforeRenderViewType);
$this->assertEquals(View::TYPE_VIEW, $listener->afterRenderViewType);
$this->assertEquals($View->getCurrentType(), View::TYPE_VIEW);
$View->element('test_element', array(), array('callbacks' => true));
$this->assertEquals($View->getCurrentType(), View::TYPE_VIEW);
$this->assertEquals(View::TYPE_ELEMENT, $listener->beforeRenderViewType);
$this->assertEquals(View::TYPE_ELEMENT, $listener->afterRenderViewType);
}
/**
* Test __get allowing access to helpers.
*

View file

@ -0,0 +1,29 @@
msgctxt "character"
msgid "letter"
msgid_plural "letters"
msgstr[0] "letter"
msgstr[1] "letters"
msgctxt "mail"
msgid "letter"
msgid_plural "letters"
msgstr[0] "brief"
msgstr[1] "brieven"
msgctxt "spherical object"
msgid "ball"
msgstr "bal"
msgctxt "social gathering"
msgid "ball"
msgstr "danspartij"
msgid "ball"
msgstr "bal"
msgid "balance"
msgstr "balans"
msgctxt "money"
msgid "balance"
msgstr "saldo"

View file

@ -0,0 +1,21 @@
msgid ""
msgstr ""
"Project-Id-Version: CakePHP Testsuite\n"
"POT-Creation-Date: 2008-05-15 02:51-0700\n"
"PO-Revision-Date: \n"
"Last-Translator: CakePHP I18N & I10N Team <i10n.cakephp@gmail.com>\n"
"Language-Team: CakePHP I18N & I10N Team <i10n.cakephp@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Poedit-Language: Two Forms of Plurals\n"
"X-Poedit-SourceCharset: utf-8\n"
msgid "Plural Rule 1"
msgstr "Plural Rule 1"
msgid "%d = 1"
msgid_plural "%d = 0 or > 1"
msgstr[0] "%d = 1"
msgstr[1] "%d = 0 or > 1"

View file

@ -0,0 +1,25 @@
msgid ""
msgstr ""
"Project-Id-Version: CakePHP Testsuite\n"
"POT-Creation-Date: 2014-12-06 19:20-0300\n"
"PO-Revision-Date: \n"
"Language-Team: CakePHP I18N & I10N Team <i10n.cakephp@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
"X-Poedit-Language: Six Forms of Plurals\n"
"X-Poedit-SourceCharset: utf-8\n"
msgid "Plural Rule 1 (from core)"
msgstr "Plural Rule 15 (from core translated)"
msgid "%d = 1 (from core)"
msgid_plural "%d = 0 or > 1 (from core)"
msgstr[0] "%d is 0 (from core translated)"
msgstr[1] "%d is 1 (from core translated)"
msgstr[2] "%d is 2 (from core translated)"
msgstr[3] "%d ends with 03-10 (from core translated)"
msgstr[4] "%d ends with 11-99 (from core translated)"
msgstr[5] "%d everything else (from core translated)"

View file

@ -0,0 +1,25 @@
msgid ""
msgstr ""
"Project-Id-Version: CakePHP Testsuite\n"
"POT-Creation-Date: 2014-12-06 19:20-0300\n"
"PO-Revision-Date: \n"
"Language-Team: CakePHP I18N & I10N Team <i10n.cakephp@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
"X-Poedit-Language: Six Forms of Plurals\n"
"X-Poedit-SourceCharset: utf-8\n"
msgid "Plural Rule 1"
msgstr "Plural Rule 15 (translated)"
msgid "%d = 1"
msgid_plural "%d = 0 or > 1"
msgstr[0] "%d is 0 (translated)"
msgstr[1] "%d is 1 (translated)"
msgstr[2] "%d is 2 (translated)"
msgstr[3] "%d ends with 03-10 (translated)"
msgstr[4] "%d ends with 11-99 (translated)"
msgstr[5] "%d everything else (translated)"

View file

@ -36,7 +36,7 @@ class Extract extends AppModel {
'message' => 'double "quoted" validation'
),
'between' => array(
'rule' => array('between', 5, 15),
'rule' => array('lengthBetween', 5, 15),
'message' => "single 'quoted' validation"
)
),

View file

@ -38,7 +38,7 @@ class PersisterOne extends AppModel {
'message' => 'Post title is required'
),
'between' => array(
'rule' => array('between', 5, 15),
'rule' => array('lengthBetween', 5, 15),
'message' => array('You may enter up to %s chars (minimum is %s chars)', 14, 6)
)
),

View file

@ -29,3 +29,5 @@ __('Hot features!'
// Category
echo __c('You have a new message (category: LC_TIME).', 5);
echo __x('mail', 'letter');

View file

@ -183,7 +183,7 @@ abstract class ControllerTestCase extends CakeTestCase {
*
* @param string $name The name of the function
* @param array $arguments Array of arguments
* @return the return of _testAction
* @return mixed The return of _testAction.
* @throws BadMethodCallException when you call methods that don't exist.
*/
public function __call($name, $arguments) {
@ -210,12 +210,12 @@ abstract class ControllerTestCase extends CakeTestCase {
* - `result` Get the return value of the controller action. Useful
* for testing requestAction methods.
*
* @param string $url The url to test
* @param string $url The URL to test
* @param array $options See options
* @return mixed
* @return mixed The specified return type.
* @triggers ControllerTestCase $Dispatch, array('request' => $request)
*/
protected function _testAction($url = '', $options = array()) {
protected function _testAction($url, $options = array()) {
$this->vars = $this->result = $this->view = $this->contents = $this->headers = null;
$options += array(

View file

@ -298,15 +298,14 @@ class CakeTestFixture {
$message .= "The field '" . $field . "' is in the data fixture but not in the schema." . "\n";
}
throw new CakeException( $message );
throw new CakeException($message);
}
$values[] = $merge;
}
$nested = $db->useNestedTransactions;
$db->useNestedTransactions = false;
$result = $db->insertMulti($this->table, $fields, $values);
if (
$this->primaryKey &&
if ($this->primaryKey &&
isset($this->fields[$this->primaryKey]['type']) &&
in_array($this->fields[$this->primaryKey]['type'], array('integer', 'biginteger'))
) {

View file

@ -65,13 +65,13 @@ class CakeTime {
* @see CakeTime::timeAgoInWords()
*/
public static $wordAccuracy = array(
'year' => "day",
'month' => "day",
'week' => "day",
'day' => "hour",
'hour' => "minute",
'minute' => "minute",
'second' => "second",
'year' => 'day',
'month' => 'day',
'week' => 'day',
'day' => 'hour',
'hour' => 'minute',
'minute' => 'minute',
'second' => 'second',
);
/**
@ -322,8 +322,7 @@ class CakeTime {
if (is_int($dateString) || is_numeric($dateString)) {
$date = (int)$dateString;
} elseif (
$dateString instanceof DateTime &&
} elseif ($dateString instanceof DateTime &&
$dateString->getTimezone()->getName() != date_default_timezone_get()
) {
$clone = clone $dateString;
@ -713,9 +712,10 @@ class CakeTime {
* - minute => The format if minutes > 0 (default "minute")
* - second => The format if seconds > 0 (default "second")
* - `end` => The end of relative time telling
* - `relativeString` => The printf compatible string when outputting relative time
* - `relativeString` => The printf compatible string when outputting past relative time
* - `relativeStringFuture` => The printf compatible string when outputting future relative time
* - `absoluteString` => The printf compatible string when outputting absolute time
* - `userOffset` => Users offset from GMT (in hours) *Deprecated* use timezone intead.
* - `userOffset` => Users offset from GMT (in hours) *Deprecated* use timezone instead.
* - `timezone` => The user timezone the timestamp should be formatted in.
*
* Relative dates look something like this:
@ -737,13 +737,16 @@ class CakeTime {
*/
public static function timeAgoInWords($dateTime, $options = array()) {
$timezone = null;
$accuracies = self::$wordAccuracy;
$format = self::$wordFormat;
$end = self::$wordEnd;
$relativeString = __d('cake', '%s ago');
$relativeEnd = self::$wordEnd;
$relativeStringPast = __d('cake', '%s ago');
$relativeStringFuture = __d('cake', 'in %s');
$absoluteString = __d('cake', 'on %s');
$accuracy = self::$wordAccuracy;
if (is_array($options)) {
if (is_string($options)) {
$format = $options;
} elseif (!empty($options)) {
if (isset($options['timezone'])) {
$timezone = $options['timezone'];
} elseif (isset($options['userOffset'])) {
@ -752,10 +755,10 @@ class CakeTime {
if (isset($options['accuracy'])) {
if (is_array($options['accuracy'])) {
$accuracy = array_merge($accuracy, $options['accuracy']);
$accuracies = array_merge($accuracies, $options['accuracy']);
} else {
foreach ($accuracy as $key => $level) {
$accuracy[$key] = $options['accuracy'];
foreach ($accuracies as $key => $level) {
$accuracies[$key] = $options['accuracy'];
}
}
}
@ -764,47 +767,56 @@ class CakeTime {
$format = $options['format'];
}
if (isset($options['end'])) {
$end = $options['end'];
$relativeEnd = $options['end'];
}
if (isset($options['relativeString'])) {
$relativeString = $options['relativeString'];
$relativeStringPast = $options['relativeString'];
unset($options['relativeString']);
}
if (isset($options['relativeStringFuture'])) {
$relativeStringFuture = $options['relativeStringFuture'];
unset($options['relativeStringFuture']);
}
if (isset($options['absoluteString'])) {
$absoluteString = $options['absoluteString'];
unset($options['absoluteString']);
}
unset($options['end'], $options['format']);
} else {
$format = $options;
}
$now = self::fromString(time(), $timezone);
$inSeconds = self::fromString($dateTime, $timezone);
$backwards = ($inSeconds > $now);
$isFuture = ($inSeconds > $now);
$futureTime = $now;
$pastTime = $inSeconds;
if ($backwards) {
$futureTime = $inSeconds;
$pastTime = $now;
if ($isFuture) {
$startTime = $now;
$endTime = $inSeconds;
} else {
$startTime = $inSeconds;
$endTime = $now;
}
$diff = $futureTime - $pastTime;
$diff = $endTime - $startTime;
if (!$diff) {
if ($diff === 0) {
return __d('cake', 'just now', 'just now');
}
if ($diff > abs($now - self::fromString($end))) {
return sprintf($absoluteString, date($format, $inSeconds));
$isAbsoluteDate = $diff > abs($now - self::fromString($relativeEnd));
if ($isAbsoluteDate) {
if (strpos($format, '%') === false) {
$date = date($format, $inSeconds);
} else {
$date = self::_strftime($format, $inSeconds);
}
return sprintf($absoluteString, $date);
}
$years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
// If more than a week, then take into account the length of months
if ($diff >= 604800) {
list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $futureTime));
list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $pastTime));
$years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $endTime));
list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $startTime));
$years = $future['Y'] - $past['Y'];
$months = $future['m'] + ((12 * $years) - $past['m']);
@ -820,13 +832,13 @@ class CakeTime {
if ($future['d'] >= $past['d']) {
$days = $future['d'] - $past['d'];
} else {
$daysInPastMonth = date('t', $pastTime);
$daysInPastMonth = date('t', $startTime);
$daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y']));
if (!$backwards) {
$days = ($daysInPastMonth - $past['d']) + $future['d'];
} else {
if ($isFuture) {
$days = ($daysInFutureMonth - $past['d']) + $future['d'];
} else {
$days = ($daysInPastMonth - $past['d']) + $future['d'];
}
if ($future['m'] != $past['m']) {
@ -849,9 +861,7 @@ class CakeTime {
$days = $days - ($weeks * 7);
}
} else {
$years = $months = $weeks = 0;
$days = floor($diff / 86400);
$diff = $diff - ($days * 86400);
$hours = floor($diff / 3600);
@ -859,69 +869,58 @@ class CakeTime {
$minutes = floor($diff / 60);
$diff = $diff - ($minutes * 60);
$seconds = $diff;
}
$fWord = $accuracy['second'];
$accuracy = $accuracies['second'];
if ($years > 0) {
$fWord = $accuracy['year'];
$accuracy = $accuracies['year'];
} elseif (abs($months) > 0) {
$fWord = $accuracy['month'];
$accuracy = $accuracies['month'];
} elseif (abs($weeks) > 0) {
$fWord = $accuracy['week'];
$accuracy = $accuracies['week'];
} elseif (abs($days) > 0) {
$fWord = $accuracy['day'];
$accuracy = $accuracies['day'];
} elseif (abs($hours) > 0) {
$fWord = $accuracy['hour'];
$accuracy = $accuracies['hour'];
} elseif (abs($minutes) > 0) {
$fWord = $accuracy['minute'];
$accuracy = $accuracies['minute'];
}
$fNum = str_replace(array('year', 'month', 'week', 'day', 'hour', 'minute', 'second'), array(1, 2, 3, 4, 5, 6, 7), $fWord);
$accuracyNum = str_replace(array('year', 'month', 'week', 'day', 'hour', 'minute', 'second'), array(1, 2, 3, 4, 5, 6, 7), $accuracy);
$relativeDate = '';
if ($fNum >= 1 && $years > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d year', '%d years', $years, $years);
$relativeDate = array();
if ($accuracyNum >= 1 && $years > 0) {
$relativeDate[] = __dn('cake', '%d year', '%d years', $years, $years);
}
if ($fNum >= 2 && $months > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d month', '%d months', $months, $months);
if ($accuracyNum >= 2 && $months > 0) {
$relativeDate[] = __dn('cake', '%d month', '%d months', $months, $months);
}
if ($fNum >= 3 && $weeks > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d week', '%d weeks', $weeks, $weeks);
if ($accuracyNum >= 3 && $weeks > 0) {
$relativeDate[] = __dn('cake', '%d week', '%d weeks', $weeks, $weeks);
}
if ($fNum >= 4 && $days > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d day', '%d days', $days, $days);
if ($accuracyNum >= 4 && $days > 0) {
$relativeDate[] = __dn('cake', '%d day', '%d days', $days, $days);
}
if ($fNum >= 5 && $hours > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d hour', '%d hours', $hours, $hours);
if ($accuracyNum >= 5 && $hours > 0) {
$relativeDate[] = __dn('cake', '%d hour', '%d hours', $hours, $hours);
}
if ($fNum >= 6 && $minutes > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d minute', '%d minutes', $minutes, $minutes);
if ($accuracyNum >= 6 && $minutes > 0) {
$relativeDate[] = __dn('cake', '%d minute', '%d minutes', $minutes, $minutes);
}
if ($fNum >= 7 && $seconds > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d second', '%d seconds', $seconds, $seconds);
if ($accuracyNum >= 7 && $seconds > 0) {
$relativeDate[] = __dn('cake', '%d second', '%d seconds', $seconds, $seconds);
}
$relativeDate = implode(', ', $relativeDate);
// When time has passed
if (!$backwards && $relativeDate) {
if ($relativeDate) {
$relativeString = ($isFuture) ? $relativeStringFuture : $relativeStringPast;
return sprintf($relativeString, $relativeDate);
}
if (!$backwards) {
$aboutAgo = array(
'second' => __d('cake', 'about a second ago'),
'minute' => __d('cake', 'about a minute ago'),
'hour' => __d('cake', 'about an hour ago'),
'day' => __d('cake', 'about a day ago'),
'week' => __d('cake', 'about a week ago'),
'year' => __d('cake', 'about a year ago')
);
return $aboutAgo[$fWord];
}
// When time is to come
if (!$relativeDate) {
$aboutIn = array(
if ($isFuture) {
$strings = array(
'second' => __d('cake', 'in about a second'),
'minute' => __d('cake', 'in about a minute'),
'hour' => __d('cake', 'in about an hour'),
@ -929,11 +928,18 @@ class CakeTime {
'week' => __d('cake', 'in about a week'),
'year' => __d('cake', 'in about a year')
);
return $aboutIn[$fWord];
} else {
$strings = array(
'second' => __d('cake', 'about a second ago'),
'minute' => __d('cake', 'about a minute ago'),
'hour' => __d('cake', 'about an hour ago'),
'day' => __d('cake', 'about a day ago'),
'week' => __d('cake', 'about a week ago'),
'year' => __d('cake', 'about a year ago')
);
}
return $relativeDate;
return $strings[$accuracy];
}
/**

View file

@ -181,15 +181,9 @@ class ClassRegistry {
} elseif ($plugin && class_exists($plugin . 'AppModel')) {
$appModel = $plugin . 'AppModel';
}
if (!empty($appModel)) {
$settings['name'] = $class;
$instance = new $appModel($settings);
}
if (!isset($instance)) {
trigger_error(__d('cake_dev', '(ClassRegistry::init() could not create instance of %s', $class), E_USER_WARNING);
return false;
}
$settings['name'] = $class;
$instance = new $appModel($settings);
}
$_this->map($alias, $class);
}

View file

@ -278,7 +278,29 @@ class Folder {
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::isAbsolute
*/
public static function isAbsolute($path) {
return !empty($path) && ($path[0] === '/' || preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) === '\\\\');
if (empty($path)) {
return false;
}
return $path[0] === '/' ||
preg_match('/^[A-Z]:\\\\/i', $path) ||
substr($path, 0, 2) === '\\\\' ||
self::isRegisteredStreamWrapper($path);
}
/**
* Returns true if given $path is a registered stream wrapper.
*
* @param string $path Path to check
* @return boo true If path is registered stream wrapper.
*/
public static function isRegisteredStreamWrapper($path) {
if (preg_match('/^[A-Z]+(?=:\/\/)/i', $path, $matches) &&
in_array($matches[0], stream_get_wrappers())
) {
return true;
}
return false;
}
/**
@ -582,7 +604,7 @@ class Folder {
$path = $this->pwd();
}
if (!$path) {
return null;
return false;
}
$path = Folder::slashTerm($path);
if (is_dir($path)) {

View file

@ -38,6 +38,7 @@ class Hash {
* @param string|array $path The path being searched for. Either a dot
* separated string, or an array of path segments.
* @param mixed $default The return value when the path does not exist
* @throws InvalidArgumentException
* @return mixed The value fetched from the array, or null.
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::get
*/
@ -48,8 +49,16 @@ class Hash {
if (is_string($path) || is_numeric($path)) {
$parts = explode('.', $path);
} else {
if (!is_array($path)) {
throw new InvalidArgumentException(__d('cake_dev',
'Invalid Parameter %s, should be dot separated path or array.',
$path
));
}
$parts = $path;
}
foreach ($parts as $key) {
if (is_array($data) && isset($data[$key])) {
$data =& $data[$key];
@ -57,6 +66,7 @@ class Hash {
return $default;
}
}
return $data;
}
@ -220,8 +230,7 @@ class Hash {
if (!preg_match($val, $prop)) {
return false;
}
} elseif (
($op === '=' && $prop != $val) ||
} elseif (($op === '=' && $prop != $val) ||
($op === '!=' && $prop == $val) ||
($op === '>' && $prop <= $val) ||
($op === '<' && $prop >= $val) ||
@ -1025,6 +1034,7 @@ class Hash {
* @param array $options Options are:
* @return array of results, nested
* @see Hash::extract()
* @throws InvalidArgumentException When providing invalid data.
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::nest
*/
public static function nest(array $data, $options = array()) {
@ -1067,10 +1077,14 @@ class Hash {
}
}
if (!$return) {
throw new InvalidArgumentException(__d('cake_dev',
'Invalid data array to nest.'
));
}
if ($options['root']) {
$root = $options['root'];
} elseif (!$return) {
return array();
} else {
$root = self::get($return[0], $parentKeys);
}

View file

@ -44,7 +44,7 @@ class Inflector {
'/sis$/i' => 'ses',
'/([ti])um$/i' => '\1a',
'/(p)erson$/i' => '\1eople',
'/(m)an$/i' => '\1en',
'/(?<!u)(m)an$/i' => '\1en',
'/(c)hild$/i' => '\1hildren',
'/(buffal|tomat)o$/i' => '\1\2oes',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',

View file

@ -129,8 +129,7 @@ abstract class ObjectCollection {
if ($options['collectReturn'] === true) {
$collected[] = $result;
}
if (
$options['break'] && ($result === $options['breakOn'] ||
if ($options['break'] && ($result === $options['breakOn'] ||
(is_array($options['breakOn']) && in_array($result, $options['breakOn'], true)))
) {
return $result;

View file

@ -671,15 +671,18 @@ class String {
}
/**
* Creates a comma separated list where the last two items are joined with 'and', forming natural English
* Creates a comma separated list where the last two items are joined with 'and', forming natural language.
*
* @param array $list The list to be joined
* @param string $and The word used to join the last and second last items together with. Defaults to 'and'
* @param string $separator The separator used to join all the other items together. Defaults to ', '
* @param array $list The list to be joined.
* @param string $and The word used to join the last and second last items together with. Defaults to 'and'.
* @param string $separator The separator used to join all the other items together. Defaults to ', '.
* @return string The glued together string.
* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::toList
*/
public static function toList($list, $and = 'and', $separator = ', ') {
public static function toList($list, $and = null, $separator = ', ') {
if ($and === null) {
$and = __d('cake', 'and');
}
if (count($list) > 1) {
return implode($separator, array_slice($list, null, -1)) . ' ' . $and . ' ' . array_pop($list);
}

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