= 1) {
+if (Configure::read('debug') > 0) {
$duration = '+10 seconds';
}
diff --git a/lib/Cake/Console/Templates/skel/Console/cake b/lib/Cake/Console/Templates/skel/Console/cake
index 447743d0b..ca3e57ca3 100644
--- a/lib/Cake/Console/Templates/skel/Console/cake
+++ b/lib/Cake/Console/Templates/skel/Console/cake
@@ -10,24 +10,28 @@
# Licensed under The MIT License
# Redistributions of files must retain the above copyright notice.
#
-# @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
-# @link http://cakephp.org CakePHP(tm) Project
-# @package app.Console
-# @since CakePHP(tm) v 2.0
-# @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+# @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
+# @link http://cakephp.org CakePHP(tm) Project
+# @package app.Console
+# @since CakePHP(tm) v 2.0
+# @license MIT License (http://www.opensource.org/licenses/mit-license.php)
#
################################################################################
-LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0")
-while [ -h "$LIB" ]; do
- DIR=$(dirname -- "$LIB")
- SYM=$(readlink "$LIB")
- LIB=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
-done
+# Canonicalize by following every symlink of the given name recursively
+canonicalize() {
+ NAME=$1
+ while [ -h "$NAME" ]; do
+ DIR=$(dirname -- "$NAME")
+ SYM=$(readlink "$NAME")
+ NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
+ done
+ echo "$NAME"
+}
-LIB=$(dirname -- "$LIB")/
-APP=`pwd`
+CONSOLE=$(dirname $(canonicalize "$0"))
+APP=$(dirname "$CONSOLE")
-exec php -q "$LIB"cake.php -working "$APP" "$@"
+exec php -q $CONSOLE/cake.php -working "$APP" "$@"
exit;
diff --git a/lib/Cake/Console/Templates/skel/Controller/PagesController.php b/lib/Cake/Console/Templates/skel/Controller/PagesController.php
index 28edfb6ec..174d32bd2 100644
--- a/lib/Cake/Console/Templates/skel/Controller/PagesController.php
+++ b/lib/Cake/Console/Templates/skel/Controller/PagesController.php
@@ -18,6 +18,7 @@
* @since CakePHP(tm) v 0.2.9
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('AppController', 'Controller');
/**
* Static content controller
diff --git a/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp b/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
index 6d508604c..cfaff40a1 100644
--- a/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
+++ b/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
@@ -25,7 +25,7 @@
); ?>
0 ):
+if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace');
endif;
?>
diff --git a/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp b/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
index 4e1f36ece..54d3774df 100644
--- a/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
+++ b/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
@@ -22,7 +22,7 @@
0 ):
+if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace');
endif;
?>
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
index 4aab010a9..0bcf45401 100644
--- a/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
+++ b/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
@@ -16,7 +16,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
?>
-
+
Html->charset(); ?>
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp
index c7d67871f..bfbefe4a3 100644
--- a/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp
+++ b/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp
@@ -16,7 +16,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
?>
-
+
Html->charset(); ?>
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
index 35f5a942f..b96f52b26 100644
--- a/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
+++ b/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
@@ -16,7 +16,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
?>
-
+
Html->charset(); ?>
diff --git a/lib/Cake/Console/Templates/skel/View/Pages/home.ctp b/lib/Cake/Console/Templates/skel/View/Pages/home.ctp
index 82f76fe2a..93d017f44 100644
--- a/lib/Cake/Console/Templates/skel/View/Pages/home.ctp
+++ b/lib/Cake/Console/Templates/skel/View/Pages/home.ctp
@@ -15,7 +15,7 @@
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
-if (Configure::read('debug') == 0):
+if (!Configure::read('debug')):
throw new NotFoundException();
endif;
App::uses('Debugger', 'Utility');
@@ -127,11 +127,28 @@ if (isset($filePresent)):
echo '';
}
?>
+
+
+ ';
+ echo __d('cake_dev', 'DebugKit plugin is present');
+ echo '';
+ else:
+ echo '';
+ echo __d('cake_dev', 'DebugKit is not installed. It will help you inspect and debug different aspects of your application.');
+ echo '
';
+ echo __d('cake_dev', 'You can install it from %s', $this->Html->link('github', 'https://github.com/cakephp/debug_kit'));
+ echo '';
+ endif;
+ ?>
+
+
-To change its layout, create: APP/View/Layouts/default.ctp.
+echo __d('cake_dev', 'To change the content of this page, edit: APP/View/Pages/home.ctp.
+To change its layout, edit: APP/View/Layouts/default.ctp.
You can also add some CSS styles for your pages at: APP/webroot/css.');
?>
@@ -156,6 +173,20 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
?>
+
+
+
+ -
+ Html->link('DebugKit', 'https://github.com/cakephp/debug_kit') ?>:
+
+
+ -
+ Html->link('Localized', 'https://github.com/cakephp/localized') ?>:
+
+
+
+
+
@@ -175,8 +206,8 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
-
-
+
+
irc.freenode.net #cakephp
@@ -185,4 +216,4 @@ You can also add some CSS styles for your pages at: APP/webroot/css.');
-
+
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/webroot/index.php b/lib/Cake/Console/Templates/skel/webroot/index.php
index fd482f8c8..3b6e141ce 100644
--- a/lib/Cake/Console/Templates/skel/webroot/index.php
+++ b/lib/Cake/Console/Templates/skel/webroot/index.php
@@ -72,6 +72,11 @@ if (!defined('WWW_ROOT')) {
define('WWW_ROOT', dirname(__FILE__) . DS);
}
+// for built-in server
+if (php_sapi_name() == 'cli-server') {
+ $_SERVER['PHP_SELF'] = '/' . basename(__FILE__);
+}
+
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
if (function_exists('ini_set')) {
ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
@@ -93,5 +98,5 @@ App::uses('Dispatcher', 'Routing');
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(
new CakeRequest(),
- new CakeResponse(array('charset' => Configure::read('App.encoding')))
+ new CakeResponse()
);
diff --git a/lib/Cake/Console/Templates/skel/webroot/test.php b/lib/Cake/Console/Templates/skel/webroot/test.php
index 37b7f2528..da7088fd8 100644
--- a/lib/Cake/Console/Templates/skel/webroot/test.php
+++ b/lib/Cake/Console/Templates/skel/webroot/test.php
@@ -86,7 +86,7 @@ if (!empty($failed)) {
}
if (Configure::read('debug') < 1) {
- die(__d('cake_dev', 'Debug setting does not allow access to this url.'));
+ exit(__d('cake_dev', 'Debug setting does not allow access to this url.'));
}
require_once CAKE . 'TestSuite' . DS . 'CakeTestSuiteDispatcher.php';
diff --git a/lib/Cake/Console/cake b/lib/Cake/Console/cake
index fbef004b1..d3ae6b885 100755
--- a/lib/Cake/Console/cake
+++ b/lib/Cake/Console/cake
@@ -17,17 +17,21 @@
# @license MIT License (http://www.opensource.org/licenses/mit-license.php)
#
################################################################################
-LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0")
-while [ -h "$LIB" ]; do
- DIR=$(dirname -- "$LIB")
- SYM=$(readlink "$LIB")
- LIB=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
-done
+# Canonicalize by following every symlink of the given name recursively
+canonicalize() {
+ NAME=$1
+ while [ -h "$NAME" ]; do
+ DIR=$(dirname -- "$NAME")
+ SYM=$(readlink "$NAME")
+ NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
+ done
+ echo "$NAME"
+}
-LIB=$(dirname -- "$LIB")/
+CONSOLE=$(dirname $(canonicalize "$0"))
APP=`pwd`
-exec php -q "$LIB"cake.php -working "$APP" "$@"
+exec php -q $CONSOLE/cake.php -working "$APP" "$@"
exit;
diff --git a/lib/Cake/Controller/CakeErrorController.php b/lib/Cake/Controller/CakeErrorController.php
index c1835fd6e..aa965b2b1 100644
--- a/lib/Cake/Controller/CakeErrorController.php
+++ b/lib/Cake/Controller/CakeErrorController.php
@@ -71,18 +71,4 @@ class CakeErrorController extends AppController {
$this->_set(array('cacheAction' => false, 'viewPath' => 'Errors'));
}
-/**
- * Escapes the viewVars.
- *
- * @return void
- */
- public function beforeRender() {
- parent::beforeRender();
- foreach ($this->viewVars as $key => $value) {
- if (!is_object($value)) {
- $this->viewVars[$key] = h($value);
- }
- }
- }
-
}
diff --git a/lib/Cake/Controller/Component/Acl/IniAcl.php b/lib/Cake/Controller/Component/Acl/IniAcl.php
index d915443fb..4bcb5d214 100644
--- a/lib/Cake/Controller/Component/Acl/IniAcl.php
+++ b/lib/Cake/Controller/Component/Acl/IniAcl.php
@@ -91,7 +91,7 @@ class IniAcl extends Object implements AclInterface {
* @return boolean Success
*/
public function check($aro, $aco, $action = null) {
- if ($this->config == null) {
+ if (!$this->config) {
$this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php');
}
$aclConfig = $this->config;
diff --git a/lib/Cake/Controller/Component/Acl/PhpAcl.php b/lib/Cake/Controller/Component/Acl/PhpAcl.php
index bd9c7302e..468ea1267 100644
--- a/lib/Cake/Controller/Component/Acl/PhpAcl.php
+++ b/lib/Cake/Controller/Component/Acl/PhpAcl.php
@@ -170,11 +170,11 @@ class PhpAcl extends Object implements AclInterface {
foreach ($path as $depth => $node) {
foreach ($prioritizedAros as $aros) {
if (!empty($node['allow'])) {
- $allow = $allow || count(array_intersect($node['allow'], $aros)) > 0;
+ $allow = $allow || count(array_intersect($node['allow'], $aros));
}
if (!empty($node['deny'])) {
- $allow = $allow && count(array_intersect($node['deny'], $aros)) == 0;
+ $allow = $allow && !count(array_intersect($node['deny'], $aros));
}
}
}
diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
index e5bd08cfe..297dd5753 100644
--- a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
+++ b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
@@ -66,19 +66,28 @@ abstract class BaseAuthenticate {
/**
* Find a user record using the standard options.
*
- * @param string $username The username/identifier.
- * @param string $password The unhashed password.
+ * The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). If
+ * the password field is not included in the conditions the password will be returned.
+ *
+ * @param Mixed $conditions The username/identifier, or an array of find conditions.
+ * @param Mixed $password The password, only use if passing as $conditions = 'username'.
* @return Mixed Either false on failure, or an array of user data.
*/
- protected function _findUser($username, $password) {
+ protected function _findUser($conditions, $password = null) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
- $conditions = array(
- $model . '.' . $fields['username'] => $username,
- $model . '.' . $fields['password'] => $this->_password($password),
- );
+ if (!is_array($conditions)) {
+ if (!$password) {
+ return false;
+ }
+ $username = $conditions;
+ $conditions = array(
+ $model . '.' . $fields['username'] => $username,
+ $model . '.' . $fields['password'] => $this->_password($password),
+ );
+ }
if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}
@@ -91,7 +100,12 @@ abstract class BaseAuthenticate {
return false;
}
$user = $result[$model];
- unset($user[$fields['password']]);
+ if (
+ isset($conditions[$model . '.' . $fields['password']]) ||
+ isset($conditions[$fields['password']])
+ ) {
+ unset($user[$fields['password']]);
+ }
unset($result[$model]);
return array_merge($user, $result);
}
diff --git a/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php b/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php
new file mode 100644
index 000000000..96845efbc
--- /dev/null
+++ b/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php
@@ -0,0 +1,78 @@
+Auth->authenticate = array(
+ * 'Blowfish' => array(
+ * 'scope' => array('User.active' => 1)
+ * )
+ * )
+ * }}}
+ *
+ * When configuring BlowfishAuthenticate you can pass in settings to which fields, model and additional conditions
+ * are used. See FormAuthenticate::$settings for more information.
+ *
+ * For inital password hashing/creation see Security::hash(). Other than how the password is initally hashed,
+ * BlowfishAuthenticate works exactly the same way as FormAuthenticate.
+ *
+ * @package Cake.Controller.Component.Auth
+ * @since CakePHP(tm) v 2.3
+ * @see AuthComponent::$authenticate
+ */
+class BlowfishAuthenticate extends FormAuthenticate {
+
+/**
+ * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
+ * to find POST data that is used to find a matching record in the`settings.userModel`. Will return false if
+ * there is no post data, either username or password is missing, or if the scope conditions have not been met.
+ *
+ * @param CakeRequest $request The request that contains login information.
+ * @param CakeResponse $response Unused response object.
+ * @return mixed False on login failure. An array of User data on success.
+ */
+ public function authenticate(CakeRequest $request, CakeResponse $response) {
+ $userModel = $this->settings['userModel'];
+ list($plugin, $model) = pluginSplit($userModel);
+
+ $fields = $this->settings['fields'];
+ if (!$this->_checkFields($request, $model, $fields)) {
+ return false;
+ }
+ $user = $this->_findUser(
+ array(
+ $model . '.' . $fields['username'] => $request->data[$model][$fields['username']],
+ )
+ );
+ if (!$user) {
+ return false;
+ }
+ $password = Security::hash(
+ $request->data[$model][$fields['password']],
+ 'blowfish',
+ $user[$fields['password']]
+ );
+ if ($password === $user[$fields['password']]) {
+ unset($user[$fields['password']]);
+ return $user;
+ }
+ return false;
+ }
+}
diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
index 21c353339..3ef4b6510 100644
--- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
+++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
@@ -138,7 +138,7 @@ class DigestAuthenticate extends BaseAuthenticate {
if (empty($digest)) {
return false;
}
- $user = $this->_findUser($digest['username'], null);
+ $user = $this->_findUser($digest['username']);
if (empty($user)) {
return false;
}
@@ -157,7 +157,7 @@ class DigestAuthenticate extends BaseAuthenticate {
* @param string $password Unused password, digest doesn't require passwords.
* @return Mixed Either false on failure, or an array of user data.
*/
- protected function _findUser($username, $password) {
+ protected function _findUser($username, $password = null) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
diff --git a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php
index 0a51f527e..c6bc5a8bf 100644
--- a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php
+++ b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php
@@ -36,6 +36,27 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
*/
class FormAuthenticate extends BaseAuthenticate {
+/**
+ * Checks the fields to ensure they are supplied.
+ *
+ * @param CakeRequest $request The request that contains login information.
+ * @param string $model The model used for login verification.
+ * @param array $fields The fields to be checked.
+ * @return boolean False if the fields have not been supplied. True if they exist.
+ */
+ protected function _checkFields(CakeRequest $request, $model, $fields) {
+ if (empty($request->data[$model])) {
+ return false;
+ }
+ if (
+ empty($request->data[$model][$fields['username']]) ||
+ empty($request->data[$model][$fields['password']])
+ ) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
* to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
@@ -50,13 +71,7 @@ class FormAuthenticate extends BaseAuthenticate {
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
- if (empty($request->data[$model])) {
- return false;
- }
- if (
- empty($request->data[$model][$fields['username']]) ||
- empty($request->data[$model][$fields['password']])
- ) {
+ if (!$this->_checkFields($request, $model, $fields)) {
return false;
}
return $this->_findUser(
diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php
index 3ce93c999..5b667bf36 100644
--- a/lib/Cake/Controller/Component/AuthComponent.php
+++ b/lib/Cake/Controller/Component/AuthComponent.php
@@ -211,6 +211,15 @@ class AuthComponent extends Component {
*/
public $authError = null;
+/**
+ * Controls handling of unauthorized access. By default unauthorized user is
+ * redirected to the referrer url or AuthComponent::$loginAction or '/'.
+ * If set to false a ForbiddenException exception is thrown instead of redirecting.
+ *
+ * @var boolean
+ */
+ public $unauthorizedRedirect = true;
+
/**
* Controller actions for which user validation is not required.
*
@@ -289,13 +298,7 @@ class AuthComponent extends Component {
$url = Router::normalize($url);
$loginAction = Router::normalize($this->loginAction);
- $allowedActions = $this->allowedActions;
- $isAllowed = (
- $this->allowedActions == array('*') ||
- in_array($action, array_map('strtolower', $allowedActions))
- );
-
- if ($loginAction != $url && $isAllowed) {
+ if ($loginAction != $url && in_array($action, array_map('strtolower', $this->allowedActions))) {
return true;
}
@@ -306,27 +309,43 @@ class AuthComponent extends Component {
}
}
return true;
- } else {
- if (!$this->_getUser()) {
- if (!$request->is('ajax')) {
- $this->flash($this->authError);
- $this->Session->write('Auth.redirect', $request->here());
- $controller->redirect($loginAction);
- return false;
- } elseif (!empty($this->ajaxLogin)) {
- $controller->viewPath = 'Elements';
- echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
- $this->_stop();
- return false;
- } else {
- $controller->redirect(null, 403);
- }
- }
}
+
+ if (!$this->_getUser()) {
+ if (!$request->is('ajax')) {
+ $this->flash($this->authError);
+ $this->Session->write('Auth.redirect', $request->here());
+ $controller->redirect($loginAction);
+ return false;
+ }
+ if (!empty($this->ajaxLogin)) {
+ $controller->viewPath = 'Elements';
+ echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
+ $this->_stop();
+ return false;
+ }
+ $controller->redirect(null, 403);
+ }
+
if (empty($this->authorize) || $this->isAuthorized($this->user())) {
return true;
}
+ return $this->_unauthorized($controller);
+ }
+
+/**
+ * Handle unauthorized access attempt
+ *
+ * @param Controller $controller A reference to the controller object
+ * @return boolean Returns false
+ * @throws ForbiddenException
+ */
+ protected function _unauthorized(Controller $controller) {
+ if (!$this->unauthorizedRedirect) {
+ throw new ForbiddenException($this->authError);
+ }
+
$this->flash($this->authError);
$default = '/';
if (!empty($this->loginRedirect)) {
@@ -366,7 +385,8 @@ class AuthComponent extends Component {
public function isAuthorized($user = null, $request = null) {
if (empty($user) && !$this->user()) {
return false;
- } elseif (empty($user)) {
+ }
+ if (empty($user)) {
$user = $this->user();
}
if (empty($request)) {
@@ -434,12 +454,12 @@ class AuthComponent extends Component {
$args = func_get_args();
if (empty($args) || $action === null) {
$this->allowedActions = $this->_methods;
- } else {
- if (isset($args[0]) && is_array($args[0])) {
- $args = $args[0];
- }
- $this->allowedActions = array_merge($this->allowedActions, $args);
+ return;
}
+ if (isset($args[0]) && is_array($args[0])) {
+ $args = $args[0];
+ }
+ $this->allowedActions = array_merge($this->allowedActions, $args);
}
/**
@@ -460,18 +480,18 @@ class AuthComponent extends Component {
$args = func_get_args();
if (empty($args) || $action === null) {
$this->allowedActions = array();
- } else {
- if (isset($args[0]) && is_array($args[0])) {
- $args = $args[0];
- }
- foreach ($args as $arg) {
- $i = array_search($arg, $this->allowedActions);
- if (is_int($i)) {
- unset($this->allowedActions[$i]);
- }
- }
- $this->allowedActions = array_values($this->allowedActions);
+ return;
}
+ if (isset($args[0]) && is_array($args[0])) {
+ $args = $args[0];
+ }
+ foreach ($args as $arg) {
+ $i = array_search($arg, $this->allowedActions);
+ if (is_int($i)) {
+ unset($this->allowedActions[$i]);
+ }
+ }
+ $this->allowedActions = array_values($this->allowedActions);
}
/**
diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php
index 1d962bc28..7fd5e9e94 100644
--- a/lib/Cake/Controller/Component/CookieComponent.php
+++ b/lib/Cake/Controller/Component/CookieComponent.php
@@ -177,7 +177,7 @@ class CookieComponent extends Component {
if ($controller && isset($controller->response)) {
$this->_response = $controller->response;
} else {
- $this->_response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
+ $this->_response = new CakeResponse();
}
}
@@ -278,6 +278,19 @@ class CookieComponent extends Component {
return $this->_values[$this->name][$key];
}
+/**
+ * Returns true if given variable is set in cookie.
+ *
+ * @param string $var Variable name to check for
+ * @return boolean True if variable is there
+ */
+ public function check($key = null) {
+ if (empty($key)) {
+ return false;
+ }
+ return $this->read($key) !== null;
+ }
+
/**
* Delete a cookie value
*
@@ -378,11 +391,11 @@ class CookieComponent extends Component {
}
$this->_reset = $this->_expires;
- if ($expires == 0) {
+ if (!$expires) {
return $this->_expires = 0;
}
- if (is_integer($expires) || is_numeric($expires)) {
+ if (is_int($expires) || is_numeric($expires)) {
return $this->_expires = $now + intval($expires);
}
return $this->_expires = strtotime($expires, $now);
@@ -504,7 +517,7 @@ class CookieComponent extends Component {
$first = substr($string, 0, 1);
if ($first === '{' || $first === '[') {
$ret = json_decode($string, true);
- return ($ret != null) ? $ret : $string;
+ return ($ret) ? $ret : $string;
}
$array = array();
foreach (explode(',', $string) as $pair) {
diff --git a/lib/Cake/Controller/Component/EmailComponent.php b/lib/Cake/Controller/Component/EmailComponent.php
index 702ec911d..18c25baa8 100644
--- a/lib/Cake/Controller/Component/EmailComponent.php
+++ b/lib/Cake/Controller/Component/EmailComponent.php
@@ -316,7 +316,7 @@ class EmailComponent extends Component {
foreach ($this->headers as $key => $value) {
$headers['X-' . $key] = $value;
}
- if ($this->date != false) {
+ if ($this->date) {
$headers['Date'] = $this->date;
}
$lib->setHeaders($headers);
diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php
index bd3d31c18..eeeaa8720 100644
--- a/lib/Cake/Controller/Component/PaginatorComponent.php
+++ b/lib/Cake/Controller/Component/PaginatorComponent.php
@@ -16,6 +16,7 @@
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('Component', 'Controller');
App::uses('Hash', 'Utility');
/**
@@ -50,6 +51,20 @@ App::uses('Hash', 'Utility');
*
* This would allow you to have different pagination settings for `Comment` and `Post` models.
*
+ * #### Paginating with custom finders
+ *
+ * You can paginate with any find type defined on your model using the `findType` option.
+ *
+ * {{{
+ * $this->Paginator->settings = array(
+ * 'Post' => array(
+ * 'findType' => 'popular'
+ * )
+ * );
+ * }}}
+ *
+ * Would paginate using the `find('popular')` method.
+ *
* @package Cake.Controller.Component
* @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
*/
@@ -152,6 +167,12 @@ class PaginatorComponent extends Component {
$extra = array_diff_key($options, compact(
'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
));
+
+ if (!empty($extra['findType'])) {
+ $type = $extra['findType'];
+ unset($extra['findType']);
+ }
+
if ($type !== 'all') {
$extra['type'] = $type;
}
@@ -228,36 +249,34 @@ class PaginatorComponent extends Component {
if (strpos($object, '.') !== false) {
list($object, $assoc) = pluginSplit($object);
}
-
if ($assoc && isset($this->Controller->{$object}->{$assoc})) {
- $object = $this->Controller->{$object}->{$assoc};
- } elseif (
- $assoc && isset($this->Controller->{$this->Controller->modelClass}) &&
- isset($this->Controller->{$this->Controller->modelClass}->{$assoc}
- )) {
- $object = $this->Controller->{$this->Controller->modelClass}->{$assoc};
- } elseif (isset($this->Controller->{$object})) {
- $object = $this->Controller->{$object};
- } elseif (
- isset($this->Controller->{$this->Controller->modelClass}) && isset($this->Controller->{$this->Controller->modelClass}->{$object}
- )) {
- $object = $this->Controller->{$this->Controller->modelClass}->{$object};
+ return $this->Controller->{$object}->{$assoc};
}
- } elseif (empty($object) || $object === null) {
+ if ($assoc && isset($this->Controller->{$this->Controller->modelClass}->{$assoc})) {
+ return $this->Controller->{$this->Controller->modelClass}->{$assoc};
+ }
+ if (isset($this->Controller->{$object})) {
+ return $this->Controller->{$object};
+ }
+ if (isset($this->Controller->{$this->Controller->modelClass}->{$object})) {
+ return $this->Controller->{$this->Controller->modelClass}->{$object};
+ }
+ }
+ if (empty($object) || $object === null) {
if (isset($this->Controller->{$this->Controller->modelClass})) {
- $object = $this->Controller->{$this->Controller->modelClass};
- } else {
- $className = null;
- $name = $this->Controller->uses[0];
- if (strpos($this->Controller->uses[0], '.') !== false) {
- list($name, $className) = explode('.', $this->Controller->uses[0]);
- }
- if ($className) {
- $object = $this->Controller->{$className};
- } else {
- $object = $this->Controller->{$name};
- }
+ return $this->Controller->{$this->Controller->modelClass};
}
+
+ $className = null;
+ $name = $this->Controller->uses[0];
+ if (strpos($this->Controller->uses[0], '.') !== false) {
+ list($name, $className) = explode('.', $this->Controller->uses[0]);
+ }
+ if ($className) {
+ return $this->Controller->{$className};
+ }
+
+ return $this->Controller->{$name};
}
return $object;
}
@@ -299,10 +318,9 @@ class PaginatorComponent extends Component {
* @return array An array of pagination defaults for a model, or the general settings.
*/
public function getDefaults($alias) {
+ $defaults = $this->settings;
if (isset($this->settings[$alias])) {
$defaults = $this->settings[$alias];
- } else {
- $defaults = $this->settings;
}
return array_merge(
array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'),
@@ -323,13 +341,13 @@ class PaginatorComponent extends Component {
* @param array $whitelist The list of columns that can be used for sorting. If empty all keys are allowed.
* @return array An array of options with sort + direction removed and replaced with order if possible.
*/
- public function validateSort($object, $options, $whitelist = array()) {
+ public function validateSort(Model $object, array $options, array $whitelist = array()) {
if (isset($options['sort'])) {
$direction = null;
if (isset($options['direction'])) {
$direction = strtolower($options['direction']);
}
- if ($direction != 'asc' && $direction != 'desc') {
+ if (!in_array($direction, array('asc', 'desc'))) {
$direction = 'asc';
}
$options['order'] = array($options['sort'] => $direction);
@@ -371,7 +389,7 @@ class PaginatorComponent extends Component {
* @param array $options An array of options with a limit key to be checked.
* @return array An array of options for pagination
*/
- public function checkLimit($options) {
+ public function checkLimit(array $options) {
$options['limit'] = (int)$options['limit'];
if (empty($options['limit']) || $options['limit'] < 1) {
$options['limit'] = 1;
diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php
index d731c2885..f46ad5571 100644
--- a/lib/Cake/Controller/Component/RequestHandlerComponent.php
+++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php
@@ -19,6 +19,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('Component', 'Controller');
App::uses('Xml', 'Utility');
/**
@@ -88,6 +89,17 @@ class RequestHandlerComponent extends Component {
'json' => array('json_decode', true)
);
+/**
+ * A mapping between type and viewClass
+ * By default only JSON and XML are mapped, use RequestHandlerComponent::viewClassMap()
+ *
+ * @var array
+ */
+ protected $_viewClassMap = array(
+ 'json' => 'Json',
+ 'xml' => 'Xml'
+ );
+
/**
* Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
*
@@ -95,8 +107,7 @@ class RequestHandlerComponent extends Component {
* @param array $settings Array of settings.
*/
public function __construct(ComponentCollection $collection, $settings = array()) {
- $default = array('checkHttpCache' => true);
- parent::__construct($collection, $settings + $default);
+ parent::__construct($collection, $settings + array('checkHttpCache' => true));
$this->addInputType('xml', array(array($this, 'convertXml')));
$Controller = $collection->getController();
@@ -111,11 +122,10 @@ class RequestHandlerComponent extends Component {
* and the requested mime-types, RequestHandler::$ext is set to that value.
*
* @param Controller $controller A reference to the controller
- * @param array $settings Array of settings to _set().
* @return void
* @see Router::parseExtensions()
*/
- public function initialize(Controller $controller, $settings = array()) {
+ public function initialize(Controller $controller) {
if (isset($this->request->params['ext'])) {
$this->ext = $this->request->params['ext'];
}
@@ -123,7 +133,9 @@ class RequestHandlerComponent extends Component {
$this->_setExtension();
}
$this->params = $controller->params;
- $this->_set($settings);
+ if (!empty($this->settings['viewClassMap'])) {
+ $this->viewClassMap($this->settings['viewClassMap']);
+ }
}
/**
@@ -145,9 +157,11 @@ class RequestHandlerComponent extends Component {
$extensions = Router::extensions();
$preferred = array_shift($accept);
$preferredTypes = $this->response->mapType($preferred);
- $similarTypes = array_intersect($extensions, $preferredTypes);
- if (count($similarTypes) === 1 && !in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) {
- $this->ext = array_shift($similarTypes);
+ if (!in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) {
+ $similarTypes = array_intersect($extensions, $preferredTypes);
+ if (count($similarTypes) === 1) {
+ $this->ext = array_shift($similarTypes);
+ }
}
}
@@ -256,8 +270,7 @@ class RequestHandlerComponent extends Component {
* @return boolean false if the render process should be aborted
**/
public function beforeRender(Controller $controller) {
- $shouldCheck = $this->settings['checkHttpCache'];
- if ($shouldCheck && $this->response->checkNotModified($this->request)) {
+ if ($this->settings['checkHttpCache'] && $this->response->checkNotModified($this->request)) {
return false;
}
}
@@ -382,13 +395,11 @@ class RequestHandlerComponent extends Component {
* Gets Prototype version if call is Ajax, otherwise empty string.
* The Prototype library sets a special "Prototype version" HTTP header.
*
- * @return string Prototype version of component making Ajax call
+ * @return string|boolean When Ajax the prototype version of component making the call otherwise false
*/
public function getAjaxVersion() {
- if (env('HTTP_X_PROTOTYPE_VERSION') != null) {
- return env('HTTP_X_PROTOTYPE_VERSION');
- }
- return false;
+ $httpX = env('HTTP_X_PROTOTYPE_VERSION');
+ return ($httpX === null) ? false : $httpX;
}
/**
@@ -454,9 +465,10 @@ class RequestHandlerComponent extends Component {
public function accepts($type = null) {
$accepted = $this->request->accepts();
- if ($type == null) {
+ if (!$type) {
return $this->mapType($accepted);
- } elseif (is_array($type)) {
+ }
+ if (is_array($type)) {
foreach ($type as $t) {
$t = $this->mapAlias($t);
if (in_array($t, $accepted)) {
@@ -464,9 +476,9 @@ class RequestHandlerComponent extends Component {
}
}
return false;
- } elseif (is_string($type)) {
- $type = $this->mapAlias($type);
- return in_array($type, $accepted);
+ }
+ if (is_string($type)) {
+ return in_array($this->mapAlias($type), $accepted);
}
return false;
}
@@ -483,18 +495,20 @@ class RequestHandlerComponent extends Component {
if (!$this->request->is('post') && !$this->request->is('put')) {
return null;
}
-
- list($contentType) = explode(';', env('CONTENT_TYPE'));
- if ($type == null) {
- return $this->mapType($contentType);
- } elseif (is_array($type)) {
+ if (is_array($type)) {
foreach ($type as $t) {
if ($this->requestedWith($t)) {
return $t;
}
}
return false;
- } elseif (is_string($type)) {
+ }
+
+ list($contentType) = explode(';', env('CONTENT_TYPE'));
+ if (!$type) {
+ return $this->mapType($contentType);
+ }
+ if (is_string($type)) {
return ($type == $this->mapType($contentType));
}
}
@@ -522,10 +536,9 @@ class RequestHandlerComponent extends Component {
if (empty($acceptRaw)) {
return $this->ext;
}
- $accepts = array_shift($acceptRaw);
- $accepts = $this->mapType($accepts);
+ $accepts = $this->mapType(array_shift($acceptRaw));
- if ($type == null) {
+ if (!$type) {
if (empty($this->ext) && !empty($accepts)) {
return $accepts[0];
}
@@ -582,18 +595,27 @@ class RequestHandlerComponent extends Component {
}
$controller->ext = '.ctp';
- $viewClass = Inflector::classify($type);
+ $pluginDot = null;
+ $viewClassMap = $this->viewClassMap();
+ if (array_key_exists($type, $viewClassMap)) {
+ list($pluginDot, $viewClass) = pluginSplit($viewClassMap[$type], true);
+ } else {
+ $viewClass = Inflector::classify($type);
+ }
$viewName = $viewClass . 'View';
if (!class_exists($viewName)) {
- App::uses($viewName, 'View');
+ App::uses($viewName, $pluginDot . 'View');
}
if (class_exists($viewName)) {
$controller->viewClass = $viewClass;
} elseif (empty($this->_renderType)) {
$controller->viewPath .= DS . $type;
} else {
- $remove = preg_replace("/([\/\\\\]{$this->_renderType})$/", DS . $type, $controller->viewPath);
- $controller->viewPath = $remove;
+ $controller->viewPath = preg_replace(
+ "/([\/\\\\]{$this->_renderType})$/",
+ DS . $type,
+ $controller->viewPath
+ );
}
$this->_renderType = $type;
$controller->layoutPath = $type;
@@ -603,12 +625,8 @@ class RequestHandlerComponent extends Component {
}
$helper = ucfirst($type);
- $isAdded = (
- in_array($helper, $controller->helpers) ||
- array_key_exists($helper, $controller->helpers)
- );
- if (!$isAdded) {
+ if (!in_array($helper, $controller->helpers) && empty($controller->helpers[$helper])) {
App::uses('AppHelper', 'View/Helper');
App::uses($helper . 'Helper', 'View/Helper');
if (class_exists($helper . 'Helper')) {
@@ -634,39 +652,35 @@ class RequestHandlerComponent extends Component {
$defaults = array('index' => null, 'charset' => null, 'attachment' => false);
$options = $options + $defaults;
+ $cType = $type;
if (strpos($type, '/') === false) {
$cType = $this->response->getMimeType($type);
- if ($cType === false) {
- return false;
- }
- if (is_array($cType) && isset($cType[$options['index']])) {
+ }
+ if (is_array($cType)) {
+ if (isset($cType[$options['index']])) {
$cType = $cType[$options['index']];
}
- if (is_array($cType)) {
- if ($this->prefers($cType)) {
- $cType = $this->prefers($cType);
- } else {
- $cType = $cType[0];
- }
+
+ if ($this->prefers($cType)) {
+ $cType = $this->prefers($cType);
+ } else {
+ $cType = $cType[0];
}
- } else {
- $cType = $type;
}
- if ($cType != null) {
- if (empty($this->request->params['requested'])) {
- $this->response->type($cType);
- }
-
- if (!empty($options['charset'])) {
- $this->response->charset($options['charset']);
- }
- if (!empty($options['attachment'])) {
- $this->response->download($options['attachment']);
- }
- return true;
+ if (!$type) {
+ return false;
}
- return false;
+ if (empty($this->request->params['requested'])) {
+ $this->response->type($cType);
+ }
+ if (!empty($options['charset'])) {
+ $this->response->charset($options['charset']);
+ }
+ if (!empty($options['attachment'])) {
+ $this->response->download($options['attachment']);
+ }
+ return true;
}
/**
@@ -729,4 +743,25 @@ class RequestHandlerComponent extends Component {
$this->_inputTypeMap[$type] = $handler;
}
+/**
+ * Getter/setter for viewClassMap
+ *
+ * @param array|string $type The type string or array with format `array('type' => 'viewClass')` to map one or more
+ * @param array $viewClass The viewClass to be used for the type without `View` appended
+ * @return array]string Returns viewClass when only string $type is set, else array with viewClassMap
+ */
+ public function viewClassMap($type = null, $viewClass = null) {
+ if (!$viewClass && is_string($type) && isset($this->_viewClassMap[$type])) {
+ return $this->_viewClassMap[$type];
+ }
+ if (is_string($type)) {
+ $this->_viewClassMap[$type] = $viewClass;
+ } elseif (is_array($type)) {
+ foreach ($type as $key => $value) {
+ $this->viewClassMap($key, $value);
+ }
+ }
+ return $this->_viewClassMap;
+ }
+
}
diff --git a/lib/Cake/Controller/Component/SecurityComponent.php b/lib/Cake/Controller/Component/SecurityComponent.php
index 907b43a8f..b086e1fa5 100644
--- a/lib/Cake/Controller/Component/SecurityComponent.php
+++ b/lib/Cake/Controller/Component/SecurityComponent.php
@@ -129,6 +129,13 @@ class SecurityComponent extends Component {
*/
public $unlockedFields = array();
+/**
+ * Actions to exclude from any security checks
+ *
+ * @var array
+ */
+ public $unlockedActions = array();
+
/**
* Whether to validate POST data. Set to false to disable for data coming from 3rd party
* services, etc.
@@ -218,13 +225,11 @@ class SecurityComponent extends Component {
$controller->request->params['requested'] != 1
);
- if ($isPost && $isNotRequestAction && $this->validatePost) {
- if ($this->_validatePost($controller) === false) {
+ if (!in_array($this->_action, (array)$this->unlockedActions) && $isPost && $isNotRequestAction) {
+ if ($this->validatePost && $this->_validatePost($controller) === false) {
return $this->blackHole($controller, 'auth');
}
- }
- if ($isPost && $isNotRequestAction && $this->csrfCheck) {
- if ($this->_validateCsrf($controller) === false) {
+ if ($this->csrfCheck && $this->_validateCsrf($controller) === false) {
return $this->blackHole($controller, 'csrf');
}
}
@@ -309,11 +314,10 @@ class SecurityComponent extends Component {
* @throws BadRequestException
*/
public function blackHole(Controller $controller, $error = '') {
- if ($this->blackHoleCallback == null) {
+ if (!$this->blackHoleCallback) {
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
- } else {
- return $this->_callback($controller, $this->blackHoleCallback, array($error));
}
+ return $this->_callback($controller, $this->blackHoleCallback, array($error));
}
/**
@@ -385,7 +389,7 @@ class SecurityComponent extends Component {
$requireAuth = $this->requireAuth;
if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth == array('*')) {
- if (!isset($controller->request->data['_Token'] )) {
+ if (!isset($controller->request->data['_Token'])) {
if (!$this->blackHole($controller, 'auth')) {
return null;
}
@@ -489,7 +493,7 @@ class SecurityComponent extends Component {
$fieldList += $lockedFields;
$unlocked = implode('|', $unlocked);
- $check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'));
+ $check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'), 'sha1');
return ($token === $check);
}
@@ -588,11 +592,10 @@ class SecurityComponent extends Component {
* @throws BadRequestException When a the blackholeCallback is not callable.
*/
protected function _callback(Controller $controller, $method, $params = array()) {
- if (is_callable(array($controller, $method))) {
- return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
- } else {
+ if (!is_callable(array($controller, $method))) {
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
}
+ return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
}
}
diff --git a/lib/Cake/Controller/Controller.php b/lib/Cake/Controller/Controller.php
index 8b3098998..5f9b8865e 100644
--- a/lib/Cake/Controller/Controller.php
+++ b/lib/Cake/Controller/Controller.php
@@ -319,7 +319,7 @@ class Controller extends Object implements CakeEventListener {
$this->name = substr(get_class($this), 0, -10);
}
- if ($this->viewPath == null) {
+ if (!$this->viewPath) {
$this->viewPath = $this->name;
}
@@ -454,7 +454,7 @@ class Controller extends Object implements CakeEventListener {
$this->passedArgs = array_merge($request->params['pass'], $request->params['named']);
}
- if (array_key_exists('return', $request->params) && $request->params['return'] == 1) {
+ if (!empty($request->params['return']) && $request->params['return'] == 1) {
$this->autoRender = false;
}
if (!empty($request->params['bare'])) {
@@ -966,14 +966,15 @@ class Controller extends Object implements CakeEventListener {
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::referer
*/
public function referer($default = null, $local = false) {
- if ($this->request) {
- $referer = $this->request->referer($local);
- if ($referer == '/' && $default != null) {
- return Router::url($default, true);
- }
- return $referer;
+ if (!$this->request) {
+ return '/';
}
- return '/';
+
+ $referer = $this->request->referer($local);
+ if ($referer == '/' && $default) {
+ return Router::url($default, true);
+ }
+ return $referer;
}
/**
@@ -1061,7 +1062,7 @@ class Controller extends Object implements CakeEventListener {
$cond[$key] = $value;
}
}
- if ($bool != null && strtoupper($bool) != 'AND') {
+ if ($bool && strtoupper($bool) != 'AND') {
$cond = array($bool => $cond);
}
return $cond;
diff --git a/lib/Cake/Controller/Scaffold.php b/lib/Cake/Controller/Scaffold.php
index 854312686..434146eb4 100644
--- a/lib/Cake/Controller/Scaffold.php
+++ b/lib/Cake/Controller/Scaffold.php
@@ -146,7 +146,7 @@ class Scaffold {
$this->controller->viewClass = 'Scaffold';
}
$this->_validSession = (
- isset($this->controller->Session) && $this->controller->Session->valid() != false
+ isset($this->controller->Session) && $this->controller->Session->valid()
);
$this->_scaffold($request);
}
diff --git a/lib/Cake/Core/App.php b/lib/Cake/Core/App.php
index 7619bef6a..fd6d1d1b2 100644
--- a/lib/Cake/Core/App.php
+++ b/lib/Cake/Core/App.php
@@ -607,7 +607,7 @@ class App {
extract($parent, EXTR_OVERWRITE);
}
- if ($name == null && $file == null) {
+ if (!$name && !$file) {
return false;
}
diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php
index 9896aa8de..b1e58f288 100644
--- a/lib/Cake/Core/Configure.php
+++ b/lib/Cake/Core/Configure.php
@@ -170,6 +170,19 @@ class Configure {
return Hash::get(self::$_values, $var);
}
+/**
+ * Returns true if given variable is set in Configure.
+ *
+ * @param string $var Variable name to check for
+ * @return boolean True if variable is there
+ */
+ public static function check($var = null) {
+ if (empty($var)) {
+ return false;
+ }
+ return Hash::get(self::$_values, $var) !== null;
+ }
+
/**
* Used to delete a variable from Configure.
*
@@ -306,10 +319,10 @@ class Configure {
public static function dump($key, $config = 'default', $keys = array()) {
$reader = self::_getReader($config);
if (!$reader) {
- throw new ConfigureException(__d('cake', 'There is no "%s" adapter.', $config));
+ throw new ConfigureException(__d('cake_dev', 'There is no "%s" adapter.', $config));
}
if (!method_exists($reader, 'dump')) {
- throw new ConfigureException(__d('cake', 'The "%s" adapter, does not have a dump() method.', $config));
+ throw new ConfigureException(__d('cake_dev', 'The "%s" adapter, does not have a dump() method.', $config));
}
$values = self::$_values;
if (!empty($keys) && is_array($keys)) {
diff --git a/lib/Cake/Error/ExceptionRenderer.php b/lib/Cake/Error/ExceptionRenderer.php
index 3be08d26c..2cbdddc5b 100644
--- a/lib/Cake/Error/ExceptionRenderer.php
+++ b/lib/Cake/Error/ExceptionRenderer.php
@@ -102,10 +102,7 @@ class ExceptionRenderer {
if ($exception instanceof CakeException && !$methodExists) {
$method = '_cakeError';
- if (empty($template)) {
- $template = 'error500';
- }
- if ($template == 'internalError') {
+ if (empty($template) || $template == 'internalError') {
$template = 'error500';
}
} elseif ($exception instanceof PDOException) {
@@ -119,13 +116,12 @@ class ExceptionRenderer {
}
}
- if (Configure::read('debug') == 0) {
- if ($method == '_cakeError') {
- $method = 'error400';
- }
- if ($code == 500) {
- $method = 'error500';
- }
+ $isNotDebug = !Configure::read('debug');
+ if ($isNotDebug && $method == '_cakeError') {
+ $method = 'error400';
+ }
+ if ($isNotDebug && $code == 500) {
+ $method = 'error500';
}
$this->template = $template;
$this->method = $method;
@@ -147,7 +143,12 @@ class ExceptionRenderer {
if (!$request = Router::getRequest(true)) {
$request = new CakeRequest();
}
- $response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
+ $response = new CakeResponse();
+
+ if (method_exists($exception, 'responseHeader')) {
+ $response->header($exception->responseHeader());
+ }
+
try {
$controller = new CakeErrorController($request, $response);
} catch (Exception $e) {
@@ -183,7 +184,7 @@ class ExceptionRenderer {
$this->controller->set(array(
'code' => $code,
'url' => h($url),
- 'name' => $error->getMessage(),
+ 'name' => h($error->getMessage()),
'error' => $error,
'_serialize' => array('code', 'url', 'name')
));
@@ -199,13 +200,13 @@ class ExceptionRenderer {
*/
public function error400($error) {
$message = $error->getMessage();
- if (Configure::read('debug') == 0 && $error instanceof CakeException) {
+ if (!Configure::read('debug') && $error instanceof CakeException) {
$message = __d('cake', 'Not Found');
}
$url = $this->controller->request->here();
$this->controller->response->statusCode($error->getCode());
$this->controller->set(array(
- 'name' => $message,
+ 'name' => h($message),
'url' => h($url),
'error' => $error,
'_serialize' => array('name', 'url')
@@ -221,14 +222,14 @@ class ExceptionRenderer {
*/
public function error500($error) {
$message = $error->getMessage();
- if (Configure::read('debug') == 0) {
+ if (!Configure::read('debug')) {
$message = __d('cake', 'An Internal Error Has Occurred.');
}
$url = $this->controller->request->here();
$code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
$this->controller->response->statusCode($code);
$this->controller->set(array(
- 'name' => $message,
+ 'name' => h($message),
'message' => h($url),
'error' => $error,
'_serialize' => array('name', 'message')
@@ -249,7 +250,7 @@ class ExceptionRenderer {
$this->controller->set(array(
'code' => $code,
'url' => h($url),
- 'name' => $error->getMessage(),
+ 'name' => h($error->getMessage()),
'error' => $error,
'_serialize' => array('code', 'url', 'name', 'error')
));
diff --git a/lib/Cake/Error/exceptions.php b/lib/Cake/Error/exceptions.php
index 94952f12e..3d0757106 100644
--- a/lib/Cake/Error/exceptions.php
+++ b/lib/Cake/Error/exceptions.php
@@ -18,6 +18,43 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+/**
+ * Base class that all Exceptions extend.
+ *
+ * @package Cake.Error
+ */
+class CakeBaseException extends RuntimeException {
+
+/**
+ * Array of headers to be passed to CakeResponse::header()
+ *
+ * @var array
+ */
+ protected $_responseHeaders = null;
+
+/**
+ * Get/set the response header to be used
+ *
+ * See also CakeResponse::header()
+ *
+ * @param string|array $header. An array of header strings or a single header string
+ * - an associative array of "header name" => "header value"
+ * - an array of string headers is also accepted
+ * @param string $value. The header value.
+ * @return array
+ */
+ public function responseHeader($header = null, $value = null) {
+ if ($header) {
+ if (is_array($header)) {
+ return $this->_responseHeaders = $header;
+ }
+ $this->_responseHeaders = array($header => $value);
+ }
+ return $this->_responseHeaders;
+ }
+
+}
+
/**
* Parent class for all of the HTTP related exceptions in CakePHP.
* All HTTP status/error related exceptions should extend this class so
@@ -26,7 +63,7 @@
* @package Cake.Error
*/
if (!class_exists('HttpException')) {
- class HttpException extends RuntimeException {
+ class HttpException extends CakeBaseException {
}
}
@@ -168,7 +205,7 @@ class InternalErrorException extends HttpException {
*
* @package Cake.Error
*/
-class CakeException extends RuntimeException {
+class CakeException extends CakeBaseException {
/**
* Array of attributes that are passed in from the constructor, and
diff --git a/lib/Cake/Event/CakeEvent.php b/lib/Cake/Event/CakeEvent.php
index c70d4f816..a51b0e61d 100644
--- a/lib/Cake/Event/CakeEvent.php
+++ b/lib/Cake/Event/CakeEvent.php
@@ -17,9 +17,9 @@
*/
/**
- * Represent the transport class of events across the system, it receives a name, and subject and an optional
+ * Represents the transport class of events across the system, it receives a name, and subject and an optional
* payload. The name can be any string that uniquely identifies the event across the application, while the subject
- * represents the object that the event is applying to.
+ * represents the object that the event applies to.
*
* @package Cake.Event
*/
diff --git a/lib/Cake/Event/CakeEventListener.php b/lib/Cake/Event/CakeEventListener.php
index c4915949d..d1dd7de81 100644
--- a/lib/Cake/Event/CakeEventListener.php
+++ b/lib/Cake/Event/CakeEventListener.php
@@ -18,15 +18,15 @@
/**
* Objects implementing this interface should declare the `implementedEvents` function
- * to hint the event manager what methods should be called when an event is triggered.
+ * to notify the event manager what methods should be called when an event is triggered.
*
* @package Cake.Event
*/
interface CakeEventListener {
/**
- * Returns a list of events this object is implementing, when the class is registered
- * in an event manager, each individual method will be associated to the respective event.
+ * Returns a list of events this object is implementing. When the class is registered
+ * in an event manager, each individual method will be associated with the respective event.
*
* ## Example:
*
diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php
index aacd537c9..fde456a8c 100644
--- a/lib/Cake/Event/CakeEventManager.php
+++ b/lib/Cake/Event/CakeEventManager.php
@@ -19,9 +19,9 @@
App::uses('CakeEventListener', 'Event');
/**
- * The event manager is responsible for keeping track of event listeners and pass the correct
- * data to them, and fire them in the correct order, when associated events are triggered. You
- * can create multiple instances of this objects to manage local events or keep a single instance
+ * The event manager is responsible for keeping track of event listeners, passing the correct
+ * data to them, and firing them in the correct order, when associated events are triggered. You
+ * can create multiple instances of this object to manage local events or keep a single instance
* and pass it around to manage all events in your app.
*
* @package Cake.Event
@@ -29,7 +29,7 @@ App::uses('CakeEventListener', 'Event');
class CakeEventManager {
/**
- * The default priority queue value for new attached listeners
+ * The default priority queue value for new, attached listeners
*
* @var int
*/
@@ -50,7 +50,7 @@ class CakeEventManager {
protected $_listeners = array();
/**
- * Internal flag to distinguish a common manager from the sigleton
+ * Internal flag to distinguish a common manager from the singleton
*
* @var boolean
*/
@@ -62,7 +62,7 @@ class CakeEventManager {
* other managers were created. Usually for creating hook systems or inter-class
* communication
*
- * If called with a first params, it will be set as the globally available instance
+ * If called with the first parameter, it will be set as the globally available instance
*
* @param CakeEventManager $manager
* @return CakeEventManager the global event manager
@@ -83,15 +83,15 @@ class CakeEventManager {
* Adds a new listener to an event. Listeners
*
* @param callback|CakeEventListener $callable PHP valid callback type or instance of CakeEventListener to be called
- * when the event named with $eventKey is triggered. If a CakeEventListener instances is passed, then the `implementedEvents`
+ * when the event named with $eventKey is triggered. If a CakeEventListener instance is passed, then the `implementedEvents`
* method will be called on the object to register the declared events individually as methods to be managed by this class.
* It is possible to define multiple event handlers per event name.
*
- * @param string $eventKey The event unique identifier name to with the callback will be associated. If $callable
+ * @param string $eventKey The event unique identifier name with which the callback will be associated. If $callable
* is an instance of CakeEventListener this argument will be ignored
*
* @param array $options used to set the `priority` and `passParams` flags to the listener.
- * Priorities are handled like queues, and multiple attachments into the same priority queue will be treated in
+ * Priorities are handled like queues, and multiple attachments added to the same priority queue will be treated in
* the order of insertion. `passParams` means that the event data property will be converted to function arguments
* when the listener is called. If $called is an instance of CakeEventListener, this parameter will be ignored
*
@@ -145,7 +145,7 @@ class CakeEventManager {
* Auxiliary function to extract and return a PHP callback type out of the callable definition
* from the return value of the `implementedEvents` method on a CakeEventListener
*
- * @param array $function the array taken from a handler definition for a event
+ * @param array $function the array taken from a handler definition for an event
* @param CakeEventListener $object The handler object
* @return callback
*/
@@ -256,7 +256,7 @@ class CakeEventManager {
}
/**
- * Returns a list of all listeners for a eventKey in the order they should be called
+ * Returns a list of all listeners for an eventKey in the order they should be called
*
* @param string $eventKey
* @return array
diff --git a/lib/Cake/I18n/I18n.php b/lib/Cake/I18n/I18n.php
index 862414b7c..2c05ba359 100644
--- a/lib/Cake/I18n/I18n.php
+++ b/lib/Cake/I18n/I18n.php
@@ -405,7 +405,7 @@ class I18n {
$header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
extract($header);
- if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && $version == 0) {
+ if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && !$version) {
for ($n = 0; $n < $count; $n++) {
$r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
$msgid = substr($data, $r["offs"], $r["len"]);
@@ -585,19 +585,19 @@ class I18n {
$string = $string[1];
if (substr($string, 0, 2) === $this->_escape . 'x') {
$delimiter = $this->_escape . 'x';
- return join('', array_map('chr', array_map('hexdec',array_filter(explode($delimiter, $string)))));
+ return implode('', array_map('chr', array_map('hexdec',array_filter(explode($delimiter, $string)))));
}
if (substr($string, 0, 2) === $this->_escape . 'd') {
$delimiter = $this->_escape . 'd';
- return join('', array_map('chr', array_filter(explode($delimiter, $string))));
+ return implode('', array_map('chr', array_filter(explode($delimiter, $string))));
}
if ($string[0] === $this->_escape && isset($string[1]) && is_numeric($string[1])) {
$delimiter = $this->_escape;
- return join('', array_map('chr', array_filter(explode($delimiter, $string))));
+ return implode('', array_map('chr', array_filter(explode($delimiter, $string))));
}
if (substr($string, 0, 3) === 'U00') {
$delimiter = 'U00';
- return join('', array_map('chr', array_map('hexdec', array_filter(explode($delimiter, $string)))));
+ return implode('', array_map('chr', array_map('hexdec', array_filter(explode($delimiter, $string)))));
}
if (preg_match('/U([0-9a-fA-F]{4})/', $string, $match)) {
return Multibyte::ascii(array(hexdec($match[1])));
diff --git a/lib/Cake/I18n/L10n.php b/lib/Cake/I18n/L10n.php
index 275cb4c5f..bf105d637 100644
--- a/lib/Cake/I18n/L10n.php
+++ b/lib/Cake/I18n/L10n.php
@@ -85,47 +85,53 @@ class L10n {
/**
* Maps ISO 639-3 to I10n::_l10nCatalog
+ * The terminological codes (first one per language) should be used if possible.
+ * They are the ones building the path in `/APP/Locale/[code]/`
+ * The bibliographic codes are aliases.
*
* @var array
*/
protected $_l10nMap = array(
/* Afrikaans */ 'afr' => 'af',
- /* Albanian */ 'alb' => 'sq',
+ /* Albanian */ 'sqi' => 'sq',
+ /* Albanian - bibliographic */ 'alb' => 'sq',
/* Arabic */ 'ara' => 'ar',
- /* Armenian - Armenia */ 'hye' => 'hy',
+ /* Armenian/Armenia */ 'hye' => 'hy',
+ /* Basque */ 'eus' => 'eu',
/* Basque */ 'baq' => 'eu',
/* Tibetan */ 'bod' => 'bo',
+ /* Tibetan - bibliographic */ 'tib' => 'bo',
/* Bosnian */ 'bos' => 'bs',
/* Bulgarian */ 'bul' => 'bg',
/* Byelorussian */ 'bel' => 'be',
/* Catalan */ 'cat' => 'ca',
- /* Chinese */ 'chi' => 'zh',
/* Chinese */ 'zho' => 'zh',
+ /* Chinese - bibliographic */ 'chi' => 'zh',
/* Croatian */ 'hrv' => 'hr',
- /* Czech */ 'cze' => 'cs',
/* Czech */ 'ces' => 'cs',
+ /* Czech - bibliographic */ 'cze' => 'cs',
/* Danish */ 'dan' => 'da',
- /* Dutch (Standard) */ 'dut' => 'nl',
/* Dutch (Standard) */ 'nld' => 'nl',
+ /* Dutch (Standard) - bibliographic */ 'dut' => 'nl',
/* English */ 'eng' => 'en',
/* Estonian */ 'est' => 'et',
/* Faeroese */ 'fao' => 'fo',
- /* Farsi */ 'fas' => 'fa',
- /* Farsi */ 'per' => 'fa',
+ /* Farsi/Persian */ 'fas' => 'fa',
+ /* Farsi/Persian - bibliographic */ 'per' => 'fa',
/* Finnish */ 'fin' => 'fi',
- /* French (Standard) */ 'fre' => 'fr',
/* French (Standard) */ 'fra' => 'fr',
+ /* French (Standard) - bibliographic */ 'fre' => 'fr',
/* Gaelic (Scots) */ 'gla' => 'gd',
/* Galician */ 'glg' => 'gl',
/* German (Standard) */ 'deu' => 'de',
- /* German (Standard) */ 'ger' => 'de',
+ /* German (Standard) - bibliographic */ 'ger' => 'de',
/* Greek */ 'gre' => 'el',
/* Greek */ 'ell' => 'el',
/* Hebrew */ 'heb' => 'he',
/* Hindi */ 'hin' => 'hi',
/* Hungarian */ 'hun' => 'hu',
- /* Icelandic */ 'ice' => 'is',
/* Icelandic */ 'isl' => 'is',
+ /* Icelandic - bibliographic */ 'ice' => 'is',
/* Indonesian */ 'ind' => 'id',
/* Irish */ 'gle' => 'ga',
/* Italian */ 'ita' => 'it',
@@ -133,10 +139,10 @@ class L10n {
/* Korean */ 'kor' => 'ko',
/* Latvian */ 'lav' => 'lv',
/* Lithuanian */ 'lit' => 'lt',
- /* Macedonian */ 'mac' => 'mk',
/* Macedonian */ 'mkd' => 'mk',
- /* Malaysian */ 'may' => 'ms',
+ /* Macedonian - bibliographic */ 'mac' => 'mk',
/* Malaysian */ 'msa' => 'ms',
+ /* Malaysian - bibliographic */ 'may' => 'ms',
/* Maltese */ 'mlt' => 'mt',
/* Norwegian */ 'nor' => 'no',
/* Norwegian Bokmal */ 'nob' => 'nb',
@@ -144,14 +150,13 @@ class L10n {
/* Polish */ 'pol' => 'pl',
/* Portuguese (Portugal) */ 'por' => 'pt',
/* Rhaeto-Romanic */ 'roh' => 'rm',
- /* Romanian */ 'rum' => 'ro',
/* Romanian */ 'ron' => 'ro',
+ /* Romanian - bibliographic */ 'rum' => 'ro',
/* Russian */ 'rus' => 'ru',
/* Sami (Lappish) */ 'smi' => 'sz',
- /* Serbian */ 'scc' => 'sr',
/* Serbian */ 'srp' => 'sr',
- /* Slovak */ 'slo' => 'sk',
/* Slovak */ 'slk' => 'sk',
+ /* Slovak - bibliographic */ 'slo' => 'sk',
/* Slovenian */ 'slv' => 'sl',
/* Sorbian */ 'wen' => 'sb',
/* Spanish (Spain - Traditional) */ 'spa' => 'es',
@@ -165,6 +170,7 @@ class L10n {
/* Venda */ 'ven' => 've',
/* Vietnamese */ 'vie' => 'vi',
/* Welsh */ 'cym' => 'cy',
+ /* Welsh - bibliographic */ 'wel' => 'cy',
/* Xhosa */ 'xho' => 'xh',
/* Yiddish */ 'yid' => 'yi',
/* Zulu */ 'zul' => 'zu'
@@ -203,7 +209,7 @@ class L10n {
'bo-in' => array('language' => 'Tibetan (India)', 'locale' => 'bo_in', 'localeFallback' => 'bod', 'charset' => 'utf-8', 'direction' => 'ltr'),
'bs' => array('language' => 'Bosnian', 'locale' => 'bos', 'localeFallback' => 'bos', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ca' => array('language' => 'Catalan', 'locale' => 'cat', 'localeFallback' => 'cat', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'cs' => array('language' => 'Czech', 'locale' => 'cze', 'localeFallback' => 'cze', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'cs' => array('language' => 'Czech', 'locale' => 'ces', 'localeFallback' => 'ces', 'charset' => 'utf-8', 'direction' => 'ltr'),
'da' => array('language' => 'Danish', 'locale' => 'dan', 'localeFallback' => 'dan', 'charset' => 'utf-8', 'direction' => 'ltr'),
'de' => array('language' => 'German (Standard)', 'locale' => 'deu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
'de-at' => array('language' => 'German (Austria)', 'locale' => 'de_at', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
@@ -245,16 +251,16 @@ class L10n {
'es-uy' => array('language' => 'Spanish (Uruguay)', 'locale' => 'es_uy', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'es-ve' => array('language' => 'Spanish (Venezuela)', 'locale' => 'es_ve', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'et' => array('language' => 'Estonian', 'locale' => 'est', 'localeFallback' => 'est', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'eu' => array('language' => 'Basque', 'locale' => 'baq', 'localeFallback' => 'baq', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'eu' => array('language' => 'Basque', 'locale' => 'eus', 'localeFallback' => 'eus', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fa' => array('language' => 'Farsi', 'locale' => 'per', 'localeFallback' => 'per', 'charset' => 'utf-8', 'direction' => 'rtl'),
'fi' => array('language' => 'Finnish', 'locale' => 'fin', 'localeFallback' => 'fin', 'charset' => 'utf-8', 'direction' => 'ltr'),
'fo' => array('language' => 'Faeroese', 'locale' => 'fao', 'localeFallback' => 'fao', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr' => array('language' => 'French (Standard)', 'locale' => 'fre', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr' => array('language' => 'French (Standard)', 'locale' => 'fra', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ga' => array('language' => 'Irish', 'locale' => 'gle', 'localeFallback' => 'gle', 'charset' => 'utf-8', 'direction' => 'ltr'),
'gd' => array('language' => 'Gaelic (Scots)', 'locale' => 'gla', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
'gd-ie' => array('language' => 'Gaelic (Irish)', 'locale' => 'gd_ie', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
@@ -266,7 +272,7 @@ class L10n {
'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'),
'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
'in' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'is' => array('language' => 'Icelandic', 'locale' => 'ice', 'localeFallback' => 'ice', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'),
'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'),
@@ -276,14 +282,14 @@ class L10n {
'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'),
'lt' => array('language' => 'Lithuanian', 'locale' => 'lit', 'localeFallback' => 'lit', 'charset' => 'utf-8', 'direction' => 'ltr'),
'lv' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ms' => array('language' => 'Malaysian', 'locale' => 'may', 'localeFallback' => 'may', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'ms' => array('language' => 'Malaysian', 'locale' => 'msa', 'localeFallback' => 'msa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'mt' => array('language' => 'Maltese', 'locale' => 'mlt', 'localeFallback' => 'mlt', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'n' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'n' => array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
'nb' => array('language' => 'Norwegian Bokmal', 'locale' => 'nob', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
'nn' => array('language' => 'Norwegian Nynorsk', 'locale' => 'nno', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
'no' => array('language' => 'Norwegian', 'locale' => 'nor', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
'p' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'),
@@ -291,15 +297,15 @@ class L10n {
'pt' => array('language' => 'Portuguese (Portugal)', 'locale' => 'por', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
'pt-br' => array('language' => 'Portuguese (Brazil)', 'locale' => 'pt_br', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
'rm' => array('language' => 'Rhaeto-Romanic', 'locale' => 'roh', 'localeFallback' => 'roh', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ro' => array('language' => 'Romanian', 'locale' => 'rum', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'ro' => array('language' => 'Romanian', 'locale' => 'ron', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ru' => array('language' => 'Russian', 'locale' => 'rus', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ru-mo' => array('language' => 'Russian (Moldavia)', 'locale' => 'ru_mo', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sb' => array('language' => 'Sorbian', 'locale' => 'wen', 'localeFallback' => 'wen', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sk' => array('language' => 'Slovak', 'locale' => 'slo', 'localeFallback' => 'slo', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'sk' => array('language' => 'Slovak', 'locale' => 'slk', 'localeFallback' => 'slk', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sl' => array('language' => 'Slovenian', 'locale' => 'slv', 'localeFallback' => 'slv', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sq' => array('language' => 'Albanian', 'locale' => 'alb', 'localeFallback' => 'alb', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sr' => array('language' => 'Serbian', 'locale' => 'scc', 'localeFallback' => 'scc', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'sq' => array('language' => 'Albanian', 'locale' => 'sqi', 'localeFallback' => 'sqi', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'sr' => array('language' => 'Serbian', 'locale' => 'srp', 'localeFallback' => 'srp', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sv' => array('language' => 'Swedish', 'locale' => 'swe', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sv-fi' => array('language' => 'Swedish (Finland)', 'locale' => 'sv_fi', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sx' => array('language' => 'Sutu', 'locale' => 'sx', 'localeFallback' => 'sx', 'charset' => 'utf-8', 'direction' => 'ltr'),
@@ -315,11 +321,11 @@ class L10n {
'cy' => array('language' => 'Welsh', 'locale' => 'cym', 'localeFallback' => 'cym', 'charset' => 'utf-8', 'direction' => 'ltr'),
'xh' => array('language' => 'Xhosa', 'locale' => 'xho', 'localeFallback' => 'xho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'yi' => array('language' => 'Yiddish', 'locale' => 'yid', 'localeFallback' => 'yid', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh' => array('language' => 'Chinese', 'locale' => 'chi', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'chi', 'charset' => 'GB2312', 'direction' => 'ltr'),
- 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh' => array('language' => 'Chinese', 'locale' => 'zho', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'zho', 'charset' => 'GB2312', 'direction' => 'ltr'),
+ 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zu' => array('language' => 'Zulu', 'locale' => 'zul', 'localeFallback' => 'zul', 'charset' => 'utf-8', 'direction' => 'ltr')
);
diff --git a/lib/Cake/I18n/Multibyte.php b/lib/Cake/I18n/Multibyte.php
index eb4847aa4..f68e5f06a 100644
--- a/lib/Cake/I18n/Multibyte.php
+++ b/lib/Cake/I18n/Multibyte.php
@@ -18,261 +18,6 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
-if (!function_exists('mb_stripos')) {
-
-/**
- * Find position of first occurrence of a case-insensitive string.
- *
- * @param string $haystack The string from which to get the position of the first occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param integer $offset The position in $haystack to start searching.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return integer|boolean The numeric position of the first occurrence of $needle in the $haystack string, or false
- * if $needle is not found.
- */
- function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) {
- return Multibyte::stripos($haystack, $needle, $offset);
- }
-
-}
-
-if (!function_exists('mb_stristr')) {
-
-/**
- * Finds first occurrence of a string within another, case insensitive.
- *
- * @param string $haystack The string from which to get the first occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param boolean $part Determines which portion of $haystack this function returns.
- * If set to true, it returns all of $haystack from the beginning to the first occurrence of $needle.
- * If set to false, it returns all of $haystack from the first occurrence of $needle to the end,
- * Default value is false.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string|boolean The portion of $haystack, or false if $needle is not found.
- */
- function mb_stristr($haystack, $needle, $part = false, $encoding = null) {
- return Multibyte::stristr($haystack, $needle, $part);
- }
-
-}
-
-if (!function_exists('mb_strlen')) {
-
-/**
- * Get string length.
- *
- * @param string $string The string being checked for length.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return integer The number of characters in string $string having character encoding encoding.
- * A multi-byte character is counted as 1.
- */
- function mb_strlen($string, $encoding = null) {
- return Multibyte::strlen($string);
- }
-
-}
-
-if (!function_exists('mb_strpos')) {
-
-/**
- * Find position of first occurrence of a string.
- *
- * @param string $haystack The string being checked.
- * @param string $needle The position counted from the beginning of haystack.
- * @param integer $offset The search offset. If it is not specified, 0 is used.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return integer|boolean The numeric position of the first occurrence of $needle in the $haystack string.
- * If $needle is not found, it returns false.
- */
- function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) {
- return Multibyte::strpos($haystack, $needle, $offset);
- }
-
-}
-
-if (!function_exists('mb_strrchr')) {
-
-/**
- * Finds the last occurrence of a character in a string within another.
- *
- * @param string $haystack The string from which to get the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param boolean $part Determines which portion of $haystack this function returns.
- * If set to true, it returns all of $haystack from the beginning to the last occurrence of $needle.
- * If set to false, it returns all of $haystack from the last occurrence of $needle to the end,
- * Default value is false.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string|boolean The portion of $haystack. or false if $needle is not found.
- */
- function mb_strrchr($haystack, $needle, $part = false, $encoding = null) {
- return Multibyte::strrchr($haystack, $needle, $part);
- }
-
-}
-
-if (!function_exists('mb_strrichr')) {
-
-/**
- * Finds the last occurrence of a character in a string within another, case insensitive.
- *
- * @param string $haystack The string from which to get the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param boolean $part Determines which portion of $haystack this function returns.
- * If set to true, it returns all of $haystack from the beginning to the last occurrence of $needle.
- * If set to false, it returns all of $haystack from the last occurrence of $needle to the end,
- * Default value is false.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string|boolean The portion of $haystack. or false if $needle is not found.
- */
- function mb_strrichr($haystack, $needle, $part = false, $encoding = null) {
- return Multibyte::strrichr($haystack, $needle, $part);
- }
-
-}
-
-if (!function_exists('mb_strripos')) {
-
-/**
- * Finds position of last occurrence of a string within another, case insensitive
- *
- * @param string $haystack The string from which to get the position of the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param integer $offset The position in $haystack to start searching.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return integer|boolean The numeric position of the last occurrence of $needle in the $haystack string,
- * or false if $needle is not found.
- */
- function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) {
- return Multibyte::strripos($haystack, $needle, $offset);
- }
-
-}
-
-if (!function_exists('mb_strrpos')) {
-
-/**
- * Find position of last occurrence of a string in a string.
- *
- * @param string $haystack The string being checked, for the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param integer $offset May be specified to begin searching an arbitrary number of characters into the string.
- * Negative values will stop searching at an arbitrary point prior to the end of the string.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return integer|boolean The numeric position of the last occurrence of $needle in the $haystack string.
- * If $needle is not found, it returns false.
- */
- function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) {
- return Multibyte::strrpos($haystack, $needle, $offset);
- }
-
-}
-
-if (!function_exists('mb_strstr')) {
-
-/**
- * Finds first occurrence of a string within another
- *
- * @param string $haystack The string from which to get the first occurrence of $needle.
- * @param string $needle The string to find in $haystack
- * @param boolean $part Determines which portion of $haystack this function returns.
- * If set to true, it returns all of $haystack from the beginning to the first occurrence of $needle.
- * If set to false, it returns all of $haystack from the first occurrence of $needle to the end,
- * Default value is FALSE.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string|boolean The portion of $haystack, or true if $needle is not found.
- */
- function mb_strstr($haystack, $needle, $part = false, $encoding = null) {
- return Multibyte::strstr($haystack, $needle, $part);
- }
-
-}
-
-if (!function_exists('mb_strtolower')) {
-
-/**
- * Make a string lowercase
- *
- * @param string $string The string being lowercased.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string with all alphabetic characters converted to lowercase.
- */
- function mb_strtolower($string, $encoding = null) {
- return Multibyte::strtolower($string);
- }
-
-}
-
-if (!function_exists('mb_strtoupper')) {
-
-/**
- * Make a string uppercase
- *
- * @param string $string The string being uppercased.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string with all alphabetic characters converted to uppercase.
- */
- function mb_strtoupper($string, $encoding = null) {
- return Multibyte::strtoupper($string);
- }
-
-}
-
-if (!function_exists('mb_substr_count')) {
-
-/**
- * Count the number of substring occurrences
- *
- * @param string $haystack The string being checked.
- * @param string $needle The string being found.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return integer The number of times the $needle substring occurs in the $haystack string.
- */
- function mb_substr_count($haystack, $needle, $encoding = null) {
- return Multibyte::substrCount($haystack, $needle);
- }
-
-}
-
-if (!function_exists('mb_substr')) {
-
-/**
- * Get part of string
- *
- * @param string $string The string being checked.
- * @param integer $start The first position used in $string.
- * @param integer $length The maximum length of the returned string.
- * @param string $encoding Character encoding name to use. If it is omitted, internal character encoding is used.
- * @return string The portion of $string specified by the $string and $length parameters.
- */
- function mb_substr($string, $start, $length = null, $encoding = null) {
- return Multibyte::substr($string, $start, $length);
- }
-
-}
-
-if (!function_exists('mb_encode_mimeheader')) {
-
-/**
- * Encode string for MIME header
- *
- * @param string $str The string being encoded
- * @param string $charset specifies the name of the character set in which str is represented in.
- * The default value is determined by the current NLS setting (mbstring.language).
- * @param string $transfer_encoding specifies the scheme of MIME encoding.
- * It should be either "B" (Base64) or "Q" (Quoted-Printable). Falls back to "B" if not given.
- * @param string $linefeed specifies the EOL (end-of-line) marker with which
- * mb_encode_mimeheader() performs line-folding
- * (a ยป RFC term, the act of breaking a line longer than a certain length into multiple lines.
- * The length is currently hard-coded to 74 characters). Falls back to "\r\n" (CRLF) if not given.
- * @param integer $indent [definition unknown and appears to have no affect]
- * @return string A converted version of the string represented in ASCII.
- */
- function mb_encode_mimeheader($str, $charset = 'UTF-8', $transferEncoding = 'B', $linefeed = "\r\n", $indent = 1) {
- return Multibyte::mimeEncode($str, $charset, $linefeed);
- }
-
-}
-
/**
* Multibyte handling methods.
*
@@ -1124,7 +869,7 @@ class Multibyte {
public static function checkMultibyte($string) {
$length = strlen($string);
- for ($i = 0; $i < $length; $i++ ) {
+ for ($i = 0; $i < $length; $i++) {
$value = ord(($string[$i]));
if ($value > 128) {
return true;
diff --git a/lib/Cake/Log/Engine/FileLog.php b/lib/Cake/Log/Engine/FileLog.php
index 68e4526db..b7cc2b556 100644
--- a/lib/Cake/Log/Engine/FileLog.php
+++ b/lib/Cake/Log/Engine/FileLog.php
@@ -18,6 +18,7 @@
*/
App::uses('BaseLog', 'Log/Engine');
+App::uses('Hash', 'Utility');
/**
* File Storage stream for Logging. Writes logs to different files
diff --git a/lib/Cake/Model/Behavior/AclBehavior.php b/lib/Cake/Model/Behavior/AclBehavior.php
index d0f0a4ca3..e35f0a0d5 100644
--- a/lib/Cake/Model/Behavior/AclBehavior.php
+++ b/lib/Cake/Model/Behavior/AclBehavior.php
@@ -18,6 +18,7 @@
* @since CakePHP v 1.2.0.4487
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('ModelBehavior', 'Model');
App::uses('AclNode', 'Model');
App::uses('Hash', 'Utility');
diff --git a/lib/Cake/Model/Behavior/ContainableBehavior.php b/lib/Cake/Model/Behavior/ContainableBehavior.php
index 799f6e238..92df83695 100644
--- a/lib/Cake/Model/Behavior/ContainableBehavior.php
+++ b/lib/Cake/Model/Behavior/ContainableBehavior.php
@@ -18,6 +18,7 @@
* @since CakePHP(tm) v 1.2.0.5669
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('ModelBehavior', 'Model');
/**
* Behavior to allow for dynamic and atomic manipulation of a Model's associations
@@ -174,7 +175,7 @@ class ContainableBehavior extends ModelBehavior {
}
if ($this->settings[$Model->alias]['recursive']) {
- $query['recursive'] = (isset($query['recursive'])) ? $query['recursive'] : $containments['depth'];
+ $query['recursive'] = (isset($query['recursive'])) ? max($query['recursive'], $containments['depth']) : $containments['depth'];
}
$autoFields = ($this->settings[$Model->alias]['autoFields']
diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php
index 01a2c0d53..3700446ac 100644
--- a/lib/Cake/Model/Behavior/TranslateBehavior.php
+++ b/lib/Cake/Model/Behavior/TranslateBehavior.php
@@ -13,6 +13,7 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('ModelBehavior', 'Model');
App::uses('I18n', 'I18n');
App::uses('I18nModel', 'Model');
@@ -128,7 +129,7 @@ class TranslateBehavior extends ModelBehavior {
'conditions' => array(
$Model->escapeField() => $db->identifier($RuntimeModel->escapeField('foreign_key')),
$RuntimeModel->escapeField('model') => $Model->name,
- $RuntimeModel->escapeField('locale') => $locale
+ $RuntimeModel->escapeField('locale') => $locale
)
);
$conditionFields = $this->_checkConditions($Model, $query);
@@ -193,7 +194,7 @@ class TranslateBehavior extends ModelBehavior {
*/
protected function _checkConditions(Model $Model, $query) {
$conditionFields = array();
- if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions'])) ) {
+ if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions']))) {
return $conditionFields;
}
foreach ($query['conditions'] as $col => $val) {
@@ -337,7 +338,7 @@ class TranslateBehavior extends ModelBehavior {
* @return boolean true.
*/
public function beforeSave(Model $Model, $options = array()) {
- if (isset($options['validate']) && $options['validate'] == false) {
+ if (isset($options['validate']) && !$options['validate']) {
unset($this->runtime[$Model->alias]['beforeSave']);
}
if (isset($this->runtime[$Model->alias]['beforeSave'])) {
@@ -409,7 +410,6 @@ class TranslateBehavior extends ModelBehavior {
if (!isset($this->runtime[$Model->alias]['beforeValidate']) && !isset($this->runtime[$Model->alias]['beforeSave'])) {
return true;
}
- $locale = $this->_getLocale($Model);
if (isset($this->runtime[$Model->alias]['beforeValidate'])) {
$tempData = $this->runtime[$Model->alias]['beforeValidate'];
} else {
@@ -420,21 +420,10 @@ class TranslateBehavior extends ModelBehavior {
$conditions = array('model' => $Model->alias, 'foreign_key' => $Model->id);
$RuntimeModel = $this->translateModel($Model);
- $fields = array_merge(
- $this->settings[$Model->alias],
- $this->runtime[$Model->alias]['fields']
- );
if ($created) {
- // set each field value to an empty string
- foreach ($fields as $key => $field) {
- if (!is_numeric($key)) {
- $field = $key;
- }
- if (!isset($tempData[$field])) {
- $tempData[$field] = '';
- }
- }
+ $tempData = $this->_prepareTranslations($Model, $tempData);
}
+ $locale = $this->_getLocale($Model);
foreach ($tempData as $field => $value) {
unset($conditions['content']);
@@ -451,7 +440,10 @@ class TranslateBehavior extends ModelBehavior {
}
$translations = $RuntimeModel->find('list', array(
'conditions' => $conditions,
- 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id')
+ 'fields' => array(
+ $RuntimeModel->alias . '.locale',
+ $RuntimeModel->alias . '.id'
+ )
));
foreach ($value as $_locale => $_value) {
$RuntimeModel->create();
@@ -470,6 +462,37 @@ class TranslateBehavior extends ModelBehavior {
}
}
+/**
+ * Prepares the data to be saved for translated records.
+ * Add blank fields, and populates data for multi-locale saves.
+ *
+ * @param array $data The sparse data that was provided.
+ * @return array The fully populated data to save.
+ */
+ protected function _prepareTranslations(Model $Model, $data) {
+ $fields = array_merge($this->settings[$Model->alias], $this->runtime[$Model->alias]['fields']);
+ $locales = array();
+ foreach ($data as $key => $value) {
+ if (is_array($value)) {
+ $locales = array_merge($locales, array_keys($value));
+ }
+ }
+ $locales = array_unique($locales);
+ $hasLocales = count($locales) > 0;
+
+ foreach ($fields as $key => $field) {
+ if (!is_numeric($key)) {
+ $field = $key;
+ }
+ if ($hasLocales && !isset($data[$field])) {
+ $data[$field] = array_fill_keys($locales, '');
+ } elseif (!isset($data[$field])) {
+ $data[$field] = '';
+ }
+ }
+ return $data;
+ }
+
/**
* afterDelete Callback
*
@@ -478,10 +501,7 @@ class TranslateBehavior extends ModelBehavior {
*/
public function afterDelete(Model $Model) {
$RuntimeModel = $this->translateModel($Model);
- $conditions = array(
- 'model' => $Model->alias,
- 'foreign_key' => $Model->id
- );
+ $conditions = array('model' => $Model->alias, 'foreign_key' => $Model->id);
$RuntimeModel->deleteAll($conditions);
}
@@ -549,10 +569,7 @@ class TranslateBehavior extends ModelBehavior {
}
$associations = array();
$RuntimeModel = $this->translateModel($Model);
- $default = array(
- 'className' => $RuntimeModel->alias,
- 'foreignKey' => 'foreign_key'
- );
+ $default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key');
foreach ($fields as $key => $value) {
if (is_numeric($key)) {
diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php
index 6895fe9d0..a2da711a3 100644
--- a/lib/Cake/Model/Behavior/TreeBehavior.php
+++ b/lib/Cake/Model/Behavior/TreeBehavior.php
@@ -18,6 +18,7 @@
* @since CakePHP v 1.2.0.4487
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('ModelBehavior', 'Model');
/**
* Tree Behavior.
@@ -354,17 +355,16 @@ class TreeBehavior extends ModelBehavior {
$recursive = $overrideRecursive;
}
- if ($keyPath == null && $valuePath == null && $Model->hasField($Model->displayField)) {
+ $fields = null;
+ if (!$keyPath && !$valuePath && $Model->hasField($Model->displayField)) {
$fields = array($Model->primaryKey, $Model->displayField, $left, $right);
- } else {
- $fields = null;
}
- if ($keyPath == null) {
+ if (!$keyPath) {
$keyPath = '{n}.' . $Model->alias . '.' . $Model->primaryKey;
}
- if ($valuePath == null) {
+ if (!$valuePath) {
$valuePath = array('%s%s', '{n}.tree_prefix', '{n}.' . $Model->alias . '.' . $Model->displayField);
} elseif (is_string($valuePath)) {
@@ -644,9 +644,8 @@ class TreeBehavior extends ModelBehavior {
$db = ConnectionManager::getDataSource($Model->useDbConfig);
foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
$path = $this->getPath($Model, $array[$Model->alias][$Model->primaryKey]);
- if ($path == null || count($path) < 2) {
- $parentId = null;
- } else {
+ $parentId = null;
+ if (count($path) > 1) {
$parentId = $path[count($path) - 2][$Model->alias][$Model->primaryKey];
}
$Model->updateAll(array($parent => $db->value($parentId, $parent)), array($Model->escapeField() => $array[$Model->alias][$Model->primaryKey]));
@@ -799,7 +798,7 @@ class TreeBehavior extends ModelBehavior {
$scope, 'OR' => array($Model->escapeField($left) => $i, $Model->escapeField($right) => $i)
)));
if ($count != 1) {
- if ($count == 0) {
+ if (!$count) {
$errors[] = array('index', $i, 'missing');
} else {
$errors[] = array('index', $i, 'duplicate');
diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php
index 2fda5f75e..4208cfbd7 100644
--- a/lib/Cake/Model/CakeSchema.php
+++ b/lib/Cake/Model/CakeSchema.php
@@ -254,44 +254,50 @@ class CakeSchema extends Object {
continue;
}
+ if (!is_object($Object) || $Object->useTable === false) {
+ continue;
+ }
$db = $Object->getDataSource();
- if (is_object($Object) && $Object->useTable !== false) {
- $fulltable = $table = $db->fullTableName($Object, false, false);
- if ($prefix && strpos($table, $prefix) !== 0) {
+
+ $fulltable = $table = $db->fullTableName($Object, false, false);
+ if ($prefix && strpos($table, $prefix) !== 0) {
+ continue;
+ }
+ if (!in_array($fulltable, $currentTables)) {
+ continue;
+ }
+
+ $table = $this->_noPrefixTable($prefix, $table);
+
+ $key = array_search($fulltable, $currentTables);
+ if (empty($tables[$table])) {
+ $tables[$table] = $this->_columns($Object);
+ $tables[$table]['indexes'] = $db->index($Object);
+ $tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
+ unset($currentTables[$key]);
+ }
+ if (empty($Object->hasAndBelongsToMany)) {
+ continue;
+ }
+ foreach ($Object->hasAndBelongsToMany as $Assoc => $assocData) {
+ if (isset($assocData['with'])) {
+ $class = $assocData['with'];
+ }
+ if (!is_object($Object->$class)) {
continue;
}
- $table = $this->_noPrefixTable($prefix, $table);
+ $withTable = $db->fullTableName($Object->$class, false, false);
+ if ($prefix && strpos($withTable, $prefix) !== 0) {
+ continue;
+ }
+ if (in_array($withTable, $currentTables)) {
+ $key = array_search($withTable, $currentTables);
+ $noPrefixWith = $this->_noPrefixTable($prefix, $withTable);
- if (in_array($fulltable, $currentTables)) {
- $key = array_search($fulltable, $currentTables);
- if (empty($tables[$table])) {
- $tables[$table] = $this->_columns($Object);
- $tables[$table]['indexes'] = $db->index($Object);
- $tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
- unset($currentTables[$key]);
- }
- if (!empty($Object->hasAndBelongsToMany)) {
- foreach ($Object->hasAndBelongsToMany as $assocData) {
- if (isset($assocData['with'])) {
- $class = $assocData['with'];
- }
- if (is_object($Object->$class)) {
- $withTable = $db->fullTableName($Object->$class, false, false);
- if ($prefix && strpos($withTable, $prefix) !== 0) {
- continue;
- }
- if (in_array($withTable, $currentTables)) {
- $key = array_search($withTable, $currentTables);
- $noPrefixWith = $this->_noPrefixTable($prefix, $withTable);
-
- $tables[$noPrefixWith] = $this->_columns($Object->$class);
- $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class);
- $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable);
- unset($currentTables[$key]);
- }
- }
- }
- }
+ $tables[$noPrefixWith] = $this->_columns($Object->$class);
+ $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class);
+ $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable);
+ unset($currentTables[$key]);
}
}
}
@@ -412,28 +418,28 @@ class CakeSchema extends Object {
}
$col = "\t\t'{$field}' => array('type' => '" . $value['type'] . "', ";
unset($value['type']);
- $col .= join(', ', $this->_values($value));
+ $col .= implode(', ', $this->_values($value));
} elseif ($field == 'indexes') {
$col = "\t\t'indexes' => array(\n\t\t\t";
$props = array();
foreach ((array)$value as $key => $index) {
- $props[] = "'{$key}' => array(" . join(', ', $this->_values($index)) . ")";
+ $props[] = "'{$key}' => array(" . implode(', ', $this->_values($index)) . ")";
}
- $col .= join(",\n\t\t\t", $props) . "\n\t\t";
+ $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'";
}
- $col .= join(', ', $props);
+ $col .= implode(', ', $props);
}
$col .= ")";
$cols[] = $col;
}
- $out .= join(",\n", $cols);
+ $out .= implode(",\n", $cols);
}
- $out .= "\n\t);\n";
+ $out .= "\n\t);\n\n";
return $out;
}
@@ -574,7 +580,7 @@ class CakeSchema extends Object {
if (is_array($values)) {
foreach ($values as $key => $val) {
if (is_array($val)) {
- $vals[] = "'{$key}' => array('" . implode("', '", $val) . "')";
+ $vals[] = "'{$key}' => array('" . implode("', '", $val) . "')";
} elseif (!is_numeric($key)) {
$val = var_export($val, true);
if ($val === 'NULL') {
@@ -597,7 +603,7 @@ class CakeSchema extends Object {
$db = $Obj->getDataSource();
$fields = $Obj->schema(true);
- $columns = array();
+ $columns = $props = array();
foreach ($fields as $name => $value) {
if ($Obj->primaryKey == $name) {
$value['key'] = 'primary';
diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php
index af457cdba..a8fc74530 100644
--- a/lib/Cake/Model/Datasource/CakeSession.php
+++ b/lib/Cake/Model/Datasource/CakeSession.php
@@ -131,7 +131,7 @@ class CakeSession {
self::$time = time();
$checkAgent = Configure::read('Session.checkAgent');
- if (($checkAgent === true || $checkAgent === null) && env('HTTP_USER_AGENT') != null) {
+ if (($checkAgent === true || $checkAgent === null) && env('HTTP_USER_AGENT')) {
self::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
}
self::_setPath($base);
@@ -218,8 +218,7 @@ class CakeSession {
if (empty($name)) {
return false;
}
- $result = Hash::get($_SESSION, $name);
- return isset($result);
+ return Hash::get($_SESSION, $name) !== null;
}
/**
@@ -248,7 +247,7 @@ class CakeSession {
public static function delete($name) {
if (self::check($name)) {
self::_overwrite($_SESSION, Hash::remove($_SESSION, $name));
- return (self::check($name) == false);
+ return !self::check($name);
}
self::_setError(2, __d('cake_dev', "%s doesn't exist", $name));
return false;
@@ -283,9 +282,8 @@ class CakeSession {
protected static function _error($errorNumber) {
if (!is_array(self::$error) || !array_key_exists($errorNumber, self::$error)) {
return false;
- } else {
- return self::$error[$errorNumber];
}
+ return self::$error[$errorNumber];
}
/**
@@ -662,7 +660,7 @@ class CakeSession {
*/
public static function renew() {
if (session_id()) {
- if (session_id() != '' || isset($_COOKIE[session_name()])) {
+ if (session_id() || isset($_COOKIE[session_name()])) {
setcookie(Configure::read('Session.cookie'), '', time() - 42000, self::$path);
}
session_regenerate_id(true);
diff --git a/lib/Cake/Model/Datasource/Database/Mysql.php b/lib/Cake/Model/Datasource/Database/Mysql.php
index f96dfa420..2f274e9eb 100644
--- a/lib/Cake/Model/Datasource/Database/Mysql.php
+++ b/lib/Cake/Model/Datasource/Database/Mysql.php
@@ -108,6 +108,7 @@ class Mysql extends DboSource {
'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'),
+ 'biginteger' => array('name' => 'bigint', 'limit' => '20'),
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@@ -118,6 +119,13 @@ class Mysql extends DboSource {
'boolean' => array('name' => 'tinyint', 'limit' => '1')
);
+/**
+ * Mapping of collation names to character set names
+ *
+ * @var array
+ */
+ protected $_charsets = array();
+
/**
* Connects to the database using options in the given configuration array.
*
@@ -155,6 +163,7 @@ class Mysql extends DboSource {
));
}
+ $this->_charsets = array();
$this->_useAlias = (bool)version_compare($this->getVersion(), "4.1", ">=");
return $this->connected;
@@ -177,7 +186,7 @@ class Mysql extends DboSource {
*/
public function listSources($data = null) {
$cache = parent::listSources();
- if ($cache != null) {
+ if ($cache) {
return $cache;
}
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']));
@@ -261,15 +270,24 @@ class Mysql extends DboSource {
* @return string Character set name
*/
public function getCharsetName($name) {
- if ((bool)version_compare($this->getVersion(), "5", ">=")) {
- $r = $this->_execute('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?', array($name));
- $cols = $r->fetch(PDO::FETCH_ASSOC);
-
- if (isset($cols['CHARACTER_SET_NAME'])) {
- return $cols['CHARACTER_SET_NAME'];
- }
+ if ((bool)version_compare($this->getVersion(), "5", "<")) {
+ return false;
}
- return false;
+ if (isset($this->_charsets[$name])) {
+ return $this->_charsets[$name];
+ }
+ $r = $this->_execute(
+ 'SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?',
+ array($name)
+ );
+ $cols = $r->fetch(PDO::FETCH_ASSOC);
+
+ if (isset($cols['CHARACTER_SET_NAME'])) {
+ $this->_charsets[$name] = $cols['CHARACTER_SET_NAME'];
+ } else {
+ $this->_charsets[$name] = false;
+ }
+ return $this->_charsets[$name];
}
/**
@@ -282,7 +300,7 @@ class Mysql extends DboSource {
public function describe($model) {
$key = $this->fullTableName($model, false);
$cache = parent::describe($key);
- if ($cache != null) {
+ if ($cache) {
return $cache;
}
$table = $this->fullTableName($model);
@@ -334,7 +352,7 @@ class Mysql extends DboSource {
return parent::update($model, $fields, $values, $conditions);
}
- if ($values == null) {
+ if (!$values) {
$combined = $fields;
} else {
$combined = array_combine($fields, $values);
@@ -425,17 +443,22 @@ class Mysql extends DboSource {
$table = $this->fullTableName($model);
$old = version_compare($this->getVersion(), '4.1', '<=');
if ($table) {
- $indices = $this->_execute('SHOW INDEX FROM ' . $table);
+ $indexes = $this->_execute('SHOW INDEX FROM ' . $table);
// @codingStandardsIgnoreStart
// MySQL columns don't match the cakephp conventions.
- while ($idx = $indices->fetch(PDO::FETCH_OBJ)) {
+ while ($idx = $indexes->fetch(PDO::FETCH_OBJ)) {
if ($old) {
$idx = (object)current((array)$idx);
}
if (!isset($index[$idx->Key_name]['column'])) {
$col = array();
$index[$idx->Key_name]['column'] = $idx->Column_name;
- $index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0);
+
+ if ($idx->Index_type === 'FULLTEXT') {
+ $index[$idx->Key_name]['type'] = strtolower($idx->Index_type);
+ } else {
+ $index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0);
+ }
} else {
if (!empty($index[$idx->Key_name]['column']) && !is_array($index[$idx->Key_name]['column'])) {
$col[] = $index[$idx->Key_name]['column'];
@@ -445,7 +468,7 @@ class Mysql extends DboSource {
}
}
// @codingStandardsIgnoreEnd
- $indices->closeCursor();
+ $indexes->closeCursor();
}
return $index;
}
@@ -555,31 +578,18 @@ class Mysql extends DboSource {
if (isset($indexes['drop'])) {
foreach ($indexes['drop'] as $name => $value) {
$out = 'DROP ';
- if ($name == 'PRIMARY') {
+ if ($name === 'PRIMARY') {
$out .= 'PRIMARY KEY';
} else {
- $out .= 'KEY ' . $name;
+ $out .= 'KEY ' . $this->startQuote . $name . $this->endQuote;
}
$alter[] = $out;
}
}
if (isset($indexes['add'])) {
- foreach ($indexes['add'] as $name => $value) {
- $out = 'ADD ';
- if ($name == 'PRIMARY') {
- $out .= 'PRIMARY ';
- $name = null;
- } else {
- if (!empty($value['unique'])) {
- $out .= 'UNIQUE ';
- }
- }
- if (is_array($value['column'])) {
- $out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
- } else {
- $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')';
- }
- $alter[] = $out;
+ $add = $this->buildIndex($indexes['add']);
+ foreach ($add as $index) {
+ $alter[] = 'ADD ' . $index;
}
}
return $alter;
@@ -645,9 +655,12 @@ class Mysql extends DboSource {
if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
return $col;
}
- if (($col === 'tinyint' && $limit == 1) || $col === 'boolean') {
+ if (($col === 'tinyint' && $limit === 1) || $col === 'boolean') {
return 'boolean';
}
+ if (strpos($col, 'bigint') !== false || $col === 'bigint') {
+ return 'biginteger';
+ }
if (strpos($col, 'int') !== false) {
return 'integer';
}
diff --git a/lib/Cake/Model/Datasource/Database/Postgres.php b/lib/Cake/Model/Datasource/Database/Postgres.php
index cca94a664..eb7b94b93 100644
--- a/lib/Cake/Model/Datasource/Database/Postgres.php
+++ b/lib/Cake/Model/Datasource/Database/Postgres.php
@@ -59,6 +59,7 @@ class Postgres extends DboSource {
'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'),
'integer' => array('name' => 'integer', 'formatter' => 'intval'),
+ 'biginteger' => array('name' => 'bigint', 'limit' => '20'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@@ -148,7 +149,7 @@ class Postgres extends DboSource {
public function listSources($data = null) {
$cache = parent::listSources();
- if ($cache != null) {
+ if ($cache) {
return $cache;
}
@@ -158,17 +159,17 @@ class Postgres extends DboSource {
if (!$result) {
return array();
- } else {
- $tables = array();
-
- foreach ($result as $item) {
- $tables[] = $item->name;
- }
-
- $result->closeCursor();
- parent::listSources($tables);
- return $tables;
}
+
+ $tables = array();
+
+ foreach ($result as $item) {
+ $tables[] = $item->name;
+ }
+
+ $result->closeCursor();
+ parent::listSources($tables);
+ return $tables;
}
/**
@@ -286,13 +287,34 @@ class Postgres extends DboSource {
if (is_object($table)) {
$table = $this->fullTableName($table, false, false);
}
- if (isset($this->_sequenceMap[$table]) && isset($this->_sequenceMap[$table][$field])) {
+ if (!isset($this->_sequenceMap[$table])) {
+ $this->describe($table);
+ }
+ if (isset($this->_sequenceMap[$table][$field])) {
return $this->_sequenceMap[$table][$field];
} else {
return "{$table}_{$field}_seq";
}
}
+/**
+ * Reset a sequence based on the MAX() value of $column. Useful
+ * for resetting sequences after using insertMulti().
+ *
+ * @param string $table The name of the table to update.
+ * @param string $column The column to use when reseting the sequence value, the
+ * sequence name will be fetched using Postgres::getSequence();
+ * @return boolean success.
+ */
+ public function resetSequence($table, $column) {
+ $tableName = $this->fullTableName($table, false, false);
+ $fullTable = $this->fullTableName($table);
+
+ $sequence = $this->value($this->getSequence($tableName, $column));
+ $this->execute("SELECT setval($sequence, (SELECT MAX(id) FROM $fullTable))");
+ return true;
+ }
+
/**
* Deletes all the records in a table and drops all associated auto-increment sequences
*
@@ -640,6 +662,8 @@ class Postgres extends DboSource {
return 'datetime';
case (strpos($col, 'time') === 0):
return 'time';
+ case ($col == 'bigint'):
+ return 'biginteger';
case (strpos($col, 'int') !== false && $col != 'interval'):
return 'integer';
case (strpos($col, 'char') !== false || $col == 'uuid'):
@@ -671,7 +695,7 @@ class Postgres extends DboSource {
if ($col == 'uuid') {
return 36;
}
- if ($limit != null) {
+ if ($limit) {
return intval($limit);
}
return null;
@@ -801,7 +825,19 @@ class Postgres extends DboSource {
if (!isset($col['length']) && !isset($col['limit'])) {
unset($column['length']);
}
- $out = preg_replace('/integer\([0-9]+\)/', 'integer', parent::buildColumn($column));
+ $out = parent::buildColumn($column);
+
+ $out = preg_replace(
+ '/integer\([0-9]+\)/',
+ 'integer',
+ $out
+ );
+ $out = preg_replace(
+ '/bigint\([0-9]+\)/',
+ 'bigint',
+ $out
+ );
+
$out = str_replace('integer serial', 'serial', $out);
if (strpos($out, 'timestamp DEFAULT')) {
if (isset($column['null']) && $column['null']) {
diff --git a/lib/Cake/Model/Datasource/Database/Sqlite.php b/lib/Cake/Model/Datasource/Database/Sqlite.php
index d30cc67df..87b0c36e9 100644
--- a/lib/Cake/Model/Datasource/Database/Sqlite.php
+++ b/lib/Cake/Model/Datasource/Database/Sqlite.php
@@ -70,6 +70,7 @@ class Sqlite extends DboSource {
'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'),
'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'),
+ 'biginteger' => array('name' => 'bigint', 'limit' => 20),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
@@ -138,7 +139,7 @@ class Sqlite extends DboSource {
*/
public function listSources($data = null) {
$cache = parent::listSources();
- if ($cache != null) {
+ if ($cache) {
return $cache;
}
@@ -146,14 +147,14 @@ class Sqlite extends DboSource {
if (!$result || empty($result)) {
return array();
- } else {
- $tables = array();
- foreach ($result as $table) {
- $tables[] = $table[0]['name'];
- }
- parent::listSources($tables);
- return $tables;
}
+
+ $tables = array();
+ foreach ($result as $table) {
+ $tables[] = $table[0]['name'];
+ }
+ parent::listSources($tables);
+ return $tables;
}
/**
@@ -165,7 +166,7 @@ class Sqlite extends DboSource {
public function describe($model) {
$table = $this->fullTableName($model, false, false);
$cache = parent::describe($table);
- if ($cache != null) {
+ if ($cache) {
return $cache;
}
$fields = array();
@@ -251,9 +252,22 @@ class Sqlite extends DboSource {
$limit = null;
@list($col, $limit) = explode('(', $col);
- if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) {
+ $standard = array(
+ 'text',
+ 'integer',
+ 'float',
+ 'boolean',
+ 'timestamp',
+ 'date',
+ 'datetime',
+ 'time'
+ );
+ if (in_array($col, $standard)) {
return $col;
}
+ if ($col === 'bigint') {
+ return 'biginteger';
+ }
if (strpos($col, 'char') !== false) {
return 'string';
}
@@ -448,7 +462,7 @@ class Sqlite extends DboSource {
$out .= 'UNIQUE ';
}
if (is_array($value['column'])) {
- $value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column']));
+ $value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
} else {
$value['column'] = $this->name($value['column']);
}
@@ -513,10 +527,10 @@ class Sqlite extends DboSource {
case 'schema':
extract($data);
if (is_array($columns)) {
- $columns = "\t" . join(",\n\t", array_filter($columns));
+ $columns = "\t" . implode(",\n\t", array_filter($columns));
}
if (is_array($indexes)) {
- $indexes = "\t" . join("\n\t", array_filter($indexes));
+ $indexes = "\t" . implode("\n\t", array_filter($indexes));
}
return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
default:
diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php
index 035f120ea..6771a1ab6 100644
--- a/lib/Cake/Model/Datasource/Database/Sqlserver.php
+++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php
@@ -86,16 +86,17 @@ class Sqlserver extends DboSource {
*/
public $columns = array(
'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
- 'string' => array('name' => 'nvarchar', 'limit' => '255'),
- 'text' => array('name' => 'nvarchar', 'limit' => 'MAX'),
- 'integer' => array('name' => 'int', 'formatter' => 'intval'),
- 'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
- 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
+ 'string' => array('name' => 'nvarchar', 'limit' => '255'),
+ 'text' => array('name' => 'nvarchar', 'limit' => 'MAX'),
+ 'integer' => array('name' => 'int', 'formatter' => 'intval'),
+ 'biginteger' => array('name' => 'bigint'),
+ 'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
+ 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
- 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
- 'binary' => array('name' => 'varbinary'),
- 'boolean' => array('name' => 'bit')
+ 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
+ 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
+ 'binary' => array('name' => 'varbinary'),
+ 'boolean' => array('name' => 'bit')
);
/**
@@ -186,7 +187,7 @@ class Sqlserver extends DboSource {
public function describe($model) {
$table = $this->fullTableName($model, false);
$cache = parent::describe($table);
- if ($cache != null) {
+ if ($cache) {
return $cache;
}
$fields = array();
@@ -402,6 +403,9 @@ class Sqlserver extends DboSource {
if ($col == 'bit') {
return 'boolean';
}
+ if (strpos($col, 'bigint') !== false) {
+ return 'biginteger';
+ }
if (strpos($col, 'int') !== false) {
return 'integer';
}
@@ -618,7 +622,7 @@ class Sqlserver extends DboSource {
*/
public function insertMulti($table, $fields, $values) {
$primaryKey = $this->_getPrimaryKey($table);
- $hasPrimaryKey = $primaryKey != null && (
+ $hasPrimaryKey = $primaryKey && (
(is_array($fields) && in_array($primaryKey, $fields)
|| (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
);
@@ -644,7 +648,7 @@ class Sqlserver extends DboSource {
*/
public function buildColumn($column) {
$result = parent::buildColumn($column);
- $result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', $result);
+ $result = preg_replace('/(bigint|int|integer)\([0-9]+\)/i', '$1', $result);
$result = preg_replace('/(bit)\([0-9]+\)/i', '$1', $result);
if (strpos($result, 'DEFAULT NULL') !== false) {
if (isset($column['default']) && $column['default'] === '') {
@@ -731,7 +735,7 @@ class Sqlserver extends DboSource {
*/
protected function _execute($sql, $params = array(), $prepareOptions = array()) {
$this->_lastAffected = false;
- if (strncasecmp($sql, 'SELECT', 6) == 0 || preg_match('/^EXEC(?:UTE)?\s/mi', $sql) > 0) {
+ if (strncasecmp($sql, 'SELECT', 6) === 0 || preg_match('/^EXEC(?:UTE)?\s/mi', $sql) > 0) {
$prepareOptions += array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
return parent::_execute($sql, $params, $prepareOptions);
}
diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php
index 623b7a01f..a03e965af 100644
--- a/lib/Cake/Model/Datasource/DboSource.php
+++ b/lib/Cake/Model/Datasource/DboSource.php
@@ -600,7 +600,7 @@ class DboSource extends DataSource {
} else {
if (isset($args[1]) && $args[1] === true) {
return $this->fetchAll($args[0], true);
- } elseif (isset($args[1]) && !is_array($args[1]) ) {
+ } elseif (isset($args[1]) && !is_array($args[1])) {
return $this->fetchAll($args[0], false);
} elseif (isset($args[1]) && is_array($args[1])) {
if (isset($args[2])) {
@@ -671,7 +671,7 @@ class DboSource extends DataSource {
if ($this->hasResult()) {
$first = $this->fetchRow();
- if ($first != null) {
+ if ($first) {
$out[] = $first;
}
while ($item = $this->fetchResult()) {
@@ -984,7 +984,7 @@ class DboSource extends DataSource {
public function create(Model $model, $fields = null, $values = null) {
$id = null;
- if ($fields == null) {
+ if (!$fields) {
unset($fields, $values);
$fields = array_keys($model->data);
$values = array_values($model->data);
@@ -1054,7 +1054,7 @@ class DboSource extends DataSource {
if ($model->recursive == -1) {
$_associations = array();
- } elseif ($model->recursive == 0) {
+ } elseif ($model->recursive === 0) {
unset($_associations[2], $_associations[3]);
}
@@ -1408,10 +1408,9 @@ class DboSource extends DataSource {
}
}
if (!isset($data[$association])) {
- if ($merge[0][$association] != null) {
+ $data[$association] = array();
+ if ($merge[0][$association]) {
$data[$association] = $merge[0][$association];
- } else {
- $data[$association] = array();
}
} else {
if (is_array($merge[0][$association])) {
@@ -1767,7 +1766,7 @@ class DboSource extends DataSource {
case 'schema':
foreach (array('columns', 'indexes', 'tableParameters') as $var) {
if (is_array(${$var})) {
- ${$var} = "\t" . join(",\n\t", array_filter(${$var}));
+ ${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
} else {
${$var} = '';
}
@@ -1821,7 +1820,7 @@ class DboSource extends DataSource {
* @return boolean Success
*/
public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
- if ($values == null) {
+ if (!$values) {
$combined = $fields;
} else {
$combined = array_combine($fields, $values);
@@ -2514,7 +2513,7 @@ class DboSource extends DataSource {
$data = $this->_parseKey($model, trim($key), $value);
}
- if ($data != null) {
+ if ($data) {
$out[] = $data;
$data = null;
}
@@ -2925,6 +2924,19 @@ class DboSource extends DataSource {
return $this->commit();
}
+/**
+ * Reset a sequence based on the MAX() value of $column. Useful
+ * for resetting sequences after using insertMulti().
+ *
+ * This method should be implemented by datasources that require sequences to be used.
+ *
+ * @param string $table The name of the table to update.
+ * @param string $column The column to use when reseting the sequence value.
+ * @return boolean success.
+ */
+ public function resetSequence($table, $column) {
+ }
+
/**
* Returns an array of the indexes in given datasource name.
*
@@ -3071,7 +3083,7 @@ class DboSource extends DataSource {
}
$out = $this->_buildFieldParameters($out, $column, 'beforeDefault');
- if (isset($column['key']) && $column['key'] === 'primary' && $type === 'integer') {
+ if (isset($column['key']) && $column['key'] === 'primary' && ($type === 'integer' || $type === 'biginteger')) {
$out .= ' ' . $this->columns['primary_key']['name'];
} elseif (isset($column['key']) && $column['key'] === 'primary') {
$out .= ' NOT NULL';
@@ -3117,7 +3129,7 @@ class DboSource extends DataSource {
}
/**
- * Format indexes for create table
+ * Format indexes for create table.
*
* @param array $indexes
* @param string $table
@@ -3133,6 +3145,8 @@ class DboSource extends DataSource {
} else {
if (!empty($value['unique'])) {
$out .= 'UNIQUE ';
+ } elseif (!empty($value['type']) && strtoupper($value['type']) === 'FULLTEXT') {
+ $out .= 'FULLTEXT ';
}
$name = $this->startQuote . $name . $this->endQuote;
}
diff --git a/lib/Cake/Model/I18nModel.php b/lib/Cake/Model/I18nModel.php
index 9b185064b..329f7cb50 100644
--- a/lib/Cake/Model/I18nModel.php
+++ b/lib/Cake/Model/I18nModel.php
@@ -12,6 +12,7 @@
* @since CakePHP(tm) v 1.2.0.4525
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('AppModel', 'Model');
/**
* A model used by TranslateBehavior to access the translation tables.
diff --git a/lib/Cake/Model/Model.php b/lib/Cake/Model/Model.php
index 2104739ac..0d8847447 100644
--- a/lib/Cake/Model/Model.php
+++ b/lib/Cake/Model/Model.php
@@ -235,6 +235,13 @@ class Model extends Object implements CakeEventListener {
*/
public $tablePrefix = null;
+/**
+ * Plugin model belongs to.
+ *
+ * @var string
+ */
+ public $plugin = null;
+
/**
* Name of the model.
*
@@ -669,12 +676,16 @@ class Model extends Object implements CakeEventListener {
extract(array_merge(
array(
'id' => $this->id, 'table' => $this->useTable, 'ds' => $this->useDbConfig,
- 'name' => $this->name, 'alias' => $this->alias
+ 'name' => $this->name, 'alias' => $this->alias, 'plugin' => $this->plugin
),
$id
));
}
+ if ($this->plugin === null) {
+ $this->plugin = (isset($plugin) ? $plugin : $this->plugin);
+ }
+
if ($this->name === null) {
$this->name = (isset($name) ? $name : get_class($this));
}
@@ -720,7 +731,7 @@ class Model extends Object implements CakeEventListener {
$this->useTable = Inflector::tableize($this->name);
}
- if ($this->displayField == null) {
+ if (!$this->displayField) {
unset($this->displayField);
}
$this->table = $this->useTable;
@@ -1393,7 +1404,7 @@ class Model extends Object implements CakeEventListener {
$this->schema();
}
- if ($this->_schema != null) {
+ if ($this->_schema) {
return isset($this->_schema[$name]);
}
return false;
@@ -1447,7 +1458,7 @@ class Model extends Object implements CakeEventListener {
* or false if none $field exist.
*/
public function getVirtualField($field = null) {
- if ($field == null) {
+ if (!$field) {
return empty($this->virtualFields) ? false : $this->virtualFields;
}
if ($this->isVirtualField($field)) {
@@ -1503,7 +1514,7 @@ class Model extends Object implements CakeEventListener {
public function read($fields = null, $id = null) {
$this->validationErrors = array();
- if ($id != null) {
+ if ($id) {
$this->id = $id;
}
@@ -1519,9 +1530,8 @@ class Model extends Object implements CakeEventListener {
'fields' => $fields
));
return $this->data;
- } else {
- return false;
}
+ return false;
}
/**
@@ -1874,7 +1884,7 @@ class Model extends Object implements CakeEventListener {
if ($keepExisting && !empty($links)) {
foreach ($links as $link) {
$oldJoin = $link[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
- if (! in_array($oldJoin, $newJoins) ) {
+ if (!in_array($oldJoin, $newJoins)) {
$conditions[$associationForeignKey] = $oldJoin;
$db->delete($this->{$join}, $conditions);
} else {
@@ -2220,6 +2230,7 @@ class Model extends Object implements CakeEventListener {
} else {
$data = array_merge(array($key => $this->{$association}->id), $data, array($key => $this->{$association}->id));
}
+ $options = $this->_addToWhiteList($key, $options);
} else {
$validationErrors[$association] = $this->{$association}->validationErrors;
}
@@ -2250,6 +2261,7 @@ class Model extends Object implements CakeEventListener {
$validates = $this->{$association}->create(null) !== null;
$saved = false;
if ($validates) {
+ $options = $this->{$association}->_addToWhiteList($key, $options);
if ($options['deep']) {
$saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
} else {
@@ -2270,6 +2282,7 @@ class Model extends Object implements CakeEventListener {
$values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
}
}
+ $options = $this->{$association}->_addToWhiteList($key, $options);
$_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false)));
if (in_array(false, $_return, true)) {
$validationErrors[$association] = $this->{$association}->validationErrors;
@@ -2302,6 +2315,29 @@ class Model extends Object implements CakeEventListener {
return false;
}
+/**
+ * Helper method for saveAll() and friends, to add foreign key to fieldlist
+ *
+ * @param string $key fieldname to be added to list
+ * @param array $options
+ * @return array $options
+ */
+ protected function _addToWhiteList($key, $options) {
+ if (empty($options['fieldList']) && $this->whitelist && !in_array($key, $this->whitelist)) {
+ $options['fieldList'][$this->alias] = $this->whitelist;
+ $options['fieldList'][$this->alias][] = $key;
+ return $options;
+ }
+ if (!empty($options['fieldList'][$this->alias]) && is_array($options['fieldList'][$this->alias])) {
+ $options['fieldList'][$this->alias][] = $key;
+ return $options;
+ }
+ if (!empty($options['fieldList']) && is_array($options['fieldList'])) {
+ $options['fieldList'][] = $key;
+ }
+ return $options;
+ }
+
/**
* Validates a single record, as well as all its directly associated records.
*
@@ -2566,7 +2602,7 @@ class Model extends Object implements CakeEventListener {
* @return boolean True if such a record exists
*/
public function hasAny($conditions = null) {
- return ($this->find('count', array('conditions' => $conditions, 'recursive' => -1)) != false);
+ return (bool)$this->find('count', array('conditions' => $conditions, 'recursive' => -1));
}
/**
@@ -2731,7 +2767,7 @@ class Model extends Object implements CakeEventListener {
*/
protected function _findCount($state, $query, $results = array()) {
if ($state === 'before') {
- if (!empty($query['type']) && isset($this->findMethods[$query['type']]) && $query['type'] !== 'count' ) {
+ if (!empty($query['type']) && isset($this->findMethods[$query['type']]) && $query['type'] !== 'count') {
$query['operation'] = 'count';
$query = $this->{'_find' . ucfirst($query['type'])}('before', $query);
}
@@ -2987,7 +3023,7 @@ class Model extends Object implements CakeEventListener {
if (!empty($this->id)) {
$fields[$this->alias . '.' . $this->primaryKey . ' !='] = $this->id;
}
- return ($this->find('count', array('conditions' => $fields, 'recursive' => -1)) == 0);
+ return !$this->find('count', array('conditions' => $fields, 'recursive' => -1));
}
/**
@@ -3158,7 +3194,7 @@ class Model extends Object implements CakeEventListener {
public function setDataSource($dataSource = null) {
$oldConfig = $this->useDbConfig;
- if ($dataSource != null) {
+ if ($dataSource) {
$this->useDbConfig = $dataSource;
}
$db = ConnectionManager::getDataSource($this->useDbConfig);
@@ -3204,7 +3240,7 @@ class Model extends Object implements CakeEventListener {
* @return array Associations
*/
public function getAssociated($type = null) {
- if ($type == null) {
+ if (!$type) {
$associated = array();
foreach ($this->_associations as $assoc) {
if (!empty($this->{$assoc})) {
diff --git a/lib/Cake/Model/Permission.php b/lib/Cake/Model/Permission.php
index b7c92d1a7..8744e9f6a 100644
--- a/lib/Cake/Model/Permission.php
+++ b/lib/Cake/Model/Permission.php
@@ -81,7 +81,7 @@ class Permission extends AppModel {
* @return boolean Success (true if ARO has access to action in ACO, false otherwise)
*/
public function check($aro, $aco, $action = "*") {
- if ($aro == null || $aco == null) {
+ if (!$aro || !$aco) {
return false;
}
@@ -89,12 +89,12 @@ class Permission extends AppModel {
$aroPath = $this->Aro->node($aro);
$acoPath = $this->Aco->node($aco);
- if (empty($aroPath) || empty($acoPath)) {
+ if (!$aroPath || !$acoPath) {
trigger_error(__d('cake_dev', "DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
return false;
}
- if ($acoPath == null || $acoPath == array()) {
+ if (!$acoPath) {
trigger_error(__d('cake_dev', "DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
return false;
}
@@ -146,7 +146,6 @@ class Permission extends AppModel {
return false;
case 0:
continue;
- break;
case 1:
return true;
}
@@ -171,7 +170,7 @@ class Permission extends AppModel {
$permKeys = $this->getAcoKeys($this->schema());
$save = array();
- if ($perms == false) {
+ if (!$perms) {
trigger_error(__d('cake_dev', 'DbAcl::allow() - Invalid node'), E_USER_WARNING);
return false;
}
@@ -198,7 +197,7 @@ class Permission extends AppModel {
}
list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']);
- if ($perms['link'] != null && !empty($perms['link'])) {
+ if ($perms['link'] && !empty($perms['link'])) {
$save['id'] = $perms['link'][0][$this->alias]['id'];
} else {
unset($save['id']);
diff --git a/lib/Cake/Model/Validator/CakeValidationRule.php b/lib/Cake/Model/Validator/CakeValidationRule.php
index 3ce7c2fcd..a0c693fb0 100644
--- a/lib/Cake/Model/Validator/CakeValidationRule.php
+++ b/lib/Cake/Model/Validator/CakeValidationRule.php
@@ -273,7 +273,7 @@ class CakeValidationRule {
$this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams);
} elseif (is_string($validator['rule'])) {
$this->_valid = preg_match($this->_rule, $data[$field]);
- } elseif (Configure::read('debug') > 0) {
+ } else {
trigger_error(__d('cake_dev', 'Could not find validation handler %s for %s', $this->_rule, $field), E_USER_WARNING);
return false;
}
diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php
index 903fa72ca..426906135 100644
--- a/lib/Cake/Network/CakeRequest.php
+++ b/lib/Cake/Network/CakeRequest.php
@@ -366,17 +366,17 @@ class CakeRequest implements ArrayAccess {
* @return string The client IP.
*/
public function clientIp($safe = true) {
- if (!$safe && env('HTTP_X_FORWARDED_FOR') != null) {
+ if (!$safe && env('HTTP_X_FORWARDED_FOR')) {
$ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR'));
} else {
- if (env('HTTP_CLIENT_IP') != null) {
+ if (env('HTTP_CLIENT_IP')) {
$ipaddr = env('HTTP_CLIENT_IP');
} else {
$ipaddr = env('REMOTE_ADDR');
}
}
- if (env('HTTP_CLIENTADDRESS') != null) {
+ if (env('HTTP_CLIENTADDRESS')) {
$tmpipaddr = env('HTTP_CLIENTADDRESS');
if (!empty($tmpipaddr)) {
@@ -696,8 +696,50 @@ class CakeRequest implements ArrayAccess {
* @return array An array of prefValue => array(content/types)
*/
public function parseAccept() {
+ return $this->_parseAcceptWithQualifier($this->header('accept'));
+ }
+
+/**
+ * Get the languages accepted by the client, or check if a specific language is accepted.
+ *
+ * Get the list of accepted languages:
+ *
+ * {{{ CakeRequest::acceptLanguage(); }}}
+ *
+ * Check if a specific language is accepted:
+ *
+ * {{{ CakeRequest::acceptLanguage('es-es'); }}}
+ *
+ * @param string $language The language to test.
+ * @return If a $language is provided, a boolean. Otherwise the array of accepted languages.
+ */
+ public static function acceptLanguage($language = null) {
+ $raw = self::_parseAcceptWithQualifier(self::header('Accept-Language'));
$accept = array();
- $header = explode(',', $this->header('accept'));
+ foreach ($raw as $qualifier => $languages) {
+ foreach ($languages as &$lang) {
+ if (strpos($lang, '_')) {
+ $lang = str_replace('_', '-', $lang);
+ }
+ $lang = strtolower($lang);
+ }
+ $accept = array_merge($accept, $languages);
+ }
+ if ($language === null) {
+ return $accept;
+ }
+ return in_array(strtolower($language), $accept);
+ }
+
+/**
+ * Parse Accept* headers with qualifier options
+ *
+ * @param string $header
+ * @return array
+ */
+ protected static function _parseAcceptWithQualifier($header) {
+ $accept = array();
+ $header = explode(',', $header);
foreach (array_filter($header) as $value) {
$prefPos = strpos($value, ';');
if ($prefPos !== false) {
@@ -719,31 +761,13 @@ class CakeRequest implements ArrayAccess {
}
/**
- * Get the languages accepted by the client, or check if a specific language is accepted.
+ * Provides a read accessor for `$this->query`. Allows you
+ * to use a syntax similar to `CakeSession` for reading url query data.
*
- * Get the list of accepted languages:
- *
- * {{{ CakeRequest::acceptLanguage(); }}}
- *
- * Check if a specific language is accepted:
- *
- * {{{ CakeRequest::acceptLanguage('es-es'); }}}
- *
- * @param string $language The language to test.
- * @return If a $language is provided, a boolean. Otherwise the array of accepted languages.
+ * @return mixed The value being read
*/
- public static function acceptLanguage($language = null) {
- $accepts = preg_split('/[;,]/', self::header('Accept-Language'));
- foreach ($accepts as &$accept) {
- $accept = strtolower($accept);
- if (strpos($accept, '_') !== false) {
- $accept = str_replace('_', '-', $accept);
- }
- }
- if ($language === null) {
- return $accepts;
- }
- return in_array($language, $accepts);
+ public function query($name) {
+ return Hash::get($this->query, $name);
}
/**
@@ -805,6 +829,38 @@ class CakeRequest implements ArrayAccess {
return $input;
}
+/**
+ * Only allow certain HTTP request methods, if the request method does not match
+ * a 405 error will be shown and the required "Allow" response header will be set.
+ *
+ * Example:
+ *
+ * $this->request->onlyAllow('post', 'delete');
+ * or
+ * $this->request->onlyAllow(array('post', 'delete'));
+ *
+ * If the request would be GET, response header "Allow: POST, DELETE" will be set
+ * and a 405 error will be returned
+ *
+ * @param string|array $methods Allowed HTTP request methods
+ * @return boolean true
+ * @throws MethodNotAllowedException
+ */
+ public function onlyAllow($methods) {
+ if (!is_array($methods)) {
+ $methods = func_get_args();
+ }
+ foreach ($methods as $method) {
+ if ($this->is($method)) {
+ return true;
+ }
+ }
+ $allowed = strtoupper(implode(', ', $methods));
+ $e = new MethodNotAllowedException();
+ $e->responseHeader('Allow', $allowed);
+ throw $e;
+ }
+
/**
* Read data from php://input, mocked in tests.
*
diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php
index 79be981ac..d85b91af9 100644
--- a/lib/Cake/Network/CakeResponse.php
+++ b/lib/Cake/Network/CakeResponse.php
@@ -17,6 +17,8 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('File', 'Utility');
+
/**
* CakeResponse is responsible for managing the response text, status and headers of a HTTP response.
*
@@ -115,10 +117,10 @@ class CakeResponse {
'7z' => 'application/x-7z-compressed',
'hdf' => 'application/x-hdf',
'hqx' => 'application/mac-binhex40',
- 'ico' => 'image/vnd.microsoft.icon',
+ 'ico' => 'image/x-icon',
'ips' => 'application/x-ipscript',
'ipx' => 'application/x-ipix',
- 'js' => 'text/javascript',
+ 'js' => 'application/javascript',
'latex' => 'application/x-latex',
'lha' => 'application/octet-stream',
'lsp' => 'application/x-lisp',
@@ -171,6 +173,7 @@ class CakeResponse {
'texinfo' => 'application/x-texinfo',
'tr' => 'application/x-troff',
'tsp' => 'application/dsptype',
+ 'ttc' => 'font/ttf',
'ttf' => 'font/ttf',
'unv' => 'application/i-deas',
'ustar' => 'application/x-ustar',
@@ -237,6 +240,12 @@ class CakeResponse {
'ogv' => 'video/ogg',
'webm' => 'video/webm',
'mp4' => 'video/mp4',
+ 'm4v' => 'video/mp4',
+ 'f4v' => 'video/mp4',
+ 'f4p' => 'video/mp4',
+ 'm4a' => 'audio/mp4',
+ 'f4a' => 'audio/mp4',
+ 'f4b' => 'audio/mp4',
'gif' => 'image/gif',
'ief' => 'image/ief',
'jpe' => 'image/jpeg',
@@ -265,7 +274,7 @@ class CakeResponse {
'mime' => 'www/mime',
'pdb' => 'chemical/x-pdb',
'xyz' => 'chemical/x-pdb',
- 'javascript' => 'text/javascript',
+ 'javascript' => 'application/javascript',
'form' => 'application/x-www-form-urlencoded',
'file' => 'multipart/form-data',
'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'),
@@ -276,6 +285,19 @@ class CakeResponse {
'wml' => 'text/vnd.wap.wml',
'wmlscript' => 'text/vnd.wap.wmlscript',
'wbmp' => 'image/vnd.wap.wbmp',
+ 'woff' => 'application/x-font-woff',
+ 'webp' => 'image/webp',
+ 'appcache' => 'text/cache-manifest',
+ 'manifest' => 'text/cache-manifest',
+ 'htc' => 'text/x-component',
+ 'rdf' => 'application/xml',
+ 'crx' => 'application/x-chrome-extension',
+ 'oex' => 'application/x-opera-extension',
+ 'xpi' => 'application/x-xpinstall',
+ 'safariextz' => 'application/octet-stream',
+ 'webapp' => 'application/x-web-app-manifest+json',
+ 'vcf' => 'text/x-vcard',
+ 'vtt' => 'text/vtt',
);
/**
@@ -314,6 +336,13 @@ class CakeResponse {
*/
protected $_body = null;
+/**
+ * File object for file to be read out as response
+ *
+ * @var File
+ */
+ protected $_file = null;
+
/**
* The charset the response body is encoded with
*
@@ -355,9 +384,10 @@ class CakeResponse {
if (isset($options['type'])) {
$this->type($options['type']);
}
- if (isset($options['charset'])) {
- $this->charset($options['charset']);
+ if (!isset($options['charset'])) {
+ $options['charset'] = Configure::read('App.encoding');
}
+ $this->charset($options['charset']);
}
/**
@@ -380,7 +410,12 @@ class CakeResponse {
foreach ($this->_headers as $header => $value) {
$this->_sendHeader($header, $value);
}
- $this->_sendContent($this->_body);
+ if ($this->_file) {
+ $this->_sendFile($this->_file);
+ $this->_file = null;
+ } else {
+ $this->_sendContent($this->_body);
+ }
}
/**
@@ -712,7 +747,7 @@ class CakeResponse {
* @return void
*/
public function cache($since, $time = '+1 day') {
- if (!is_integer($time)) {
+ if (!is_int($time)) {
$time = strtotime($time);
}
$this->header(array(
@@ -755,7 +790,7 @@ class CakeResponse {
unset($this->_cacheDirectives['public']);
$this->maxAge($time);
}
- if ($time == null) {
+ if (!$time) {
$this->_setCacheControl();
}
return (bool)$public;
@@ -974,7 +1009,7 @@ class CakeResponse {
protected function _getUTCDate($time = null) {
if ($time instanceof DateTime) {
$result = clone $time;
- } elseif (is_integer($time)) {
+ } elseif (is_int($time)) {
$result = new DateTime(date('Y-m-d H:i:s', $time));
} else {
$result = new DateTime($time);
@@ -1036,7 +1071,7 @@ class CakeResponse {
* @return int
*/
public function length($bytes = null) {
- if ($bytes !== null ) {
+ if ($bytes !== null) {
$this->_headers['Content-Length'] = $bytes;
}
if (isset($this->_headers['Content-Length'])) {
@@ -1052,12 +1087,11 @@ class CakeResponse {
* is marked as so accordingly so the client can be informed of that.
*
* In order to mark a response as not modified, you need to set at least
- * the Last-Modified response header or a response etag to be compared
- * with the request itself
+ * the Last-Modified etag response header before calling this method. Otherwise
+ * a comparison will not be possible.
*
- * @return boolean whether the response was marked as not modified or
- * not
- **/
+ * @return boolean whether the response was marked as not modified or not.
+ */
public function checkNotModified(CakeRequest $request) {
$etags = preg_split('/\s*,\s*/', $request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY);
$modifiedSince = $request->header('If-Modified-Since');
@@ -1154,4 +1188,138 @@ class CakeResponse {
$this->_cookies[$options['name']] = $options;
}
+/**
+ * Setup for display or download the given file
+ *
+ * @param string $path Path to file
+ * @param array $options Options
+ * ### Options keys
+ * - name: Alternate download name
+ * - download: If `true` sets download header and forces file to be downloaded rather than displayed in browser
+ * @return void
+ * @throws NotFoundException
+ */
+ public function file($path, $options = array()) {
+ $options += array(
+ 'name' => null,
+ 'download' => null
+ );
+
+ if (!is_file($path)) {
+ $path = APP . $path;
+ }
+
+ $file = new File($path);
+ if (!$file->exists() || !$file->readable()) {
+ if (Configure::read('debug')) {
+ throw new NotFoundException(__d('cake_dev', 'The requested file %s was not found or not readable', $path));
+ }
+ throw new NotFoundException(__d('cake', 'The requested file was not found'));
+ }
+
+ $extension = strtolower($file->ext());
+ $download = $options['download'];
+ if ((!$extension || $this->type($extension) === false) && is_null($download)) {
+ $download = true;
+ }
+
+ $fileSize = $file->size();
+ if ($download) {
+ $agent = env('HTTP_USER_AGENT');
+
+ if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent)) {
+ $contentType = 'application/octetstream';
+ } elseif (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
+ $contentType = 'application/force-download';
+ }
+
+ if (!empty($contentType)) {
+ $this->type($contentType);
+ }
+ if (is_null($options['name'])) {
+ $name = $file->name;
+ } else {
+ $name = $options['name'];
+ }
+ $this->download($name);
+ $this->header('Accept-Ranges', 'bytes');
+
+ $httpRange = env('HTTP_RANGE');
+ if (isset($httpRange)) {
+ list($toss, $range) = explode('=', $httpRange);
+
+ $size = $fileSize - 1;
+ $length = $fileSize - $range;
+
+ $this->header(array(
+ 'Content-Length' => $length,
+ 'Content-Range' => 'bytes ' . $range . $size . '/' . $fileSize
+ ));
+
+ $this->statusCode(206);
+ $file->open('rb', true);
+ $file->offset($range);
+ } else {
+ $this->header('Content-Length', $fileSize);
+ }
+ } else {
+ $this->header('Content-Length', $fileSize);
+ }
+ $this->_clearBuffer();
+
+ $this->_file = $file;
+ }
+
+/**
+ * Reads out a file, and echos the content to the client.
+ *
+ * @param File $file File object
+ * @return boolean True is whole file is echoed successfully or false if client connection is lost in between
+ */
+ protected function _sendFile($file) {
+ $compress = $this->outputCompressed();
+ $file->open('rb');
+ while (!feof($file->handle)) {
+ if (!$this->_isActive()) {
+ $file->close();
+ return false;
+ }
+ set_time_limit(0);
+ echo fread($file->handle, 8192);
+ if (!$compress) {
+ $this->_flushBuffer();
+ }
+ }
+ $file->close();
+ return true;
+ }
+
+/**
+ * Returns true if connection is still active
+ *
+ * @return boolean
+ */
+ protected function _isActive() {
+ return connection_status() === CONNECTION_NORMAL && !connection_aborted();
+ }
+
+/**
+ * Clears the contents of the topmost output buffer and discards them
+ *
+ * @return boolean
+ */
+ protected function _clearBuffer() {
+ return @ob_end_clean();
+ }
+
+/**
+ * Flushes the contents of the output buffer
+ *
+ * @return void
+ */
+ protected function _flushBuffer() {
+ @flush();
+ @ob_flush();
+ }
+
}
diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php
index aa0eb4fbd..1fa0cd0c9 100644
--- a/lib/Cake/Network/CakeSocket.php
+++ b/lib/Cake/Network/CakeSocket.php
@@ -41,11 +41,11 @@ class CakeSocket {
* @var array
*/
protected $_baseConfig = array(
- 'persistent' => false,
- 'host' => 'localhost',
- 'protocol' => 'tcp',
- 'port' => 80,
- 'timeout' => 30
+ 'persistent' => false,
+ 'host' => 'localhost',
+ 'protocol' => 'tcp',
+ 'port' => 80,
+ 'timeout' => 30
);
/**
@@ -76,6 +76,39 @@ class CakeSocket {
*/
public $lastError = array();
+/**
+ * True if the socket stream is encrypted after a CakeSocket::enableCrypto() call
+ *
+ * @var boolean
+ */
+ public $encrypted = false;
+
+/**
+ * Contains all the encryption methods available
+ *
+ * @var array
+ */
+ protected $_encryptMethods = array(
+ // @codingStandardsIgnoreStart
+ 'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
+ 'sslv3_client' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
+ 'sslv23_client' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
+ 'tls_client' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
+ 'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER,
+ 'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER,
+ 'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER,
+ 'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER
+ // @codingStandardsIgnoreEnd
+ );
+
+/**
+ * Used to capture connection warnings which can happen when there are
+ * SSL errors for example.
+ *
+ * @var array
+ */
+ protected $_connectionErrors = array();
+
/**
* Constructor.
*
@@ -96,26 +129,47 @@ class CakeSocket {
* @throws SocketException
*/
public function connect() {
- if ($this->connection != null) {
+ if ($this->connection) {
$this->disconnect();
}
$scheme = null;
- if (isset($this->config['request']) && $this->config['request']['uri']['scheme'] == 'https') {
+ if (isset($this->config['request']['uri']) && $this->config['request']['uri']['scheme'] == 'https') {
$scheme = 'ssl://';
}
- if ($this->config['persistent'] == true) {
- $this->connection = @pfsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
+ if (!empty($this->config['context'])) {
+ $context = stream_context_create($this->config['context']);
} else {
- $this->connection = @fsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
+ $context = stream_context_create();
}
+ $connectAs = STREAM_CLIENT_CONNECT;
+ if ($this->config['persistent']) {
+ $connectAs |= STREAM_CLIENT_PERSISTENT;
+ }
+
+ set_error_handler(array($this, '_connectionErrorHandler'));
+ $this->connection = stream_socket_client(
+ $scheme . $this->config['host'] . ':' . $this->config['port'],
+ $errNum,
+ $errStr,
+ $this->config['timeout'],
+ $connectAs,
+ $context
+ );
+ restore_error_handler();
+
if (!empty($errNum) || !empty($errStr)) {
$this->setLastError($errNum, $errStr);
throw new SocketException($errStr, $errNum);
}
+ if (!$this->connection && $this->_connectionErrors) {
+ $message = implode("\n", $this->_connectionErrors);
+ throw new SocketException($message, E_WARNING);
+ }
+
$this->connected = is_resource($this->connection);
if ($this->connected) {
stream_set_timeout($this->connection, $this->config['timeout']);
@@ -123,6 +177,31 @@ class CakeSocket {
return $this->connected;
}
+/**
+ * socket_stream_client() does not populate errNum, or $errStr when there are
+ * connection errors, as in the case of SSL verification failure.
+ *
+ * Instead we need to handle those errors manually.
+ *
+ * @param int $code
+ * @param string $message
+ */
+ protected function _connectionErrorHandler($code, $message) {
+ $this->_connectionErrors[] = $message;
+ }
+
+/**
+ * Get the connection context.
+ *
+ * @return null|array Null when there is no connnection, an array when there is.
+ */
+ public function context() {
+ if (!$this->connection) {
+ return;
+ }
+ return stream_context_get_options($this->connection);
+ }
+
/**
* Get the host name of the current connection.
*
@@ -277,4 +356,36 @@ class CakeSocket {
return true;
}
+/**
+ * Encrypts current stream socket, using one of the defined encryption methods
+ *
+ * @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls'
+ * @param string $clientOrServer can be one of 'client', 'server'. Default is 'client'
+ * @param boolean $enable enable or disable encryption. Default is true (enable)
+ * @return boolean True on success
+ * @throws InvalidArgumentException When an invalid encryption scheme is chosen.
+ * @throws SocketException When attempting to enable SSL/TLS fails
+ * @see stream_socket_enable_crypto
+ */
+ public function enableCrypto($type, $clientOrServer = 'client', $enable = true) {
+ if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) {
+ throw new InvalidArgumentException(__d('cake_dev', 'Invalid encryption scheme chosen'));
+ }
+ $enableCryptoResult = false;
+ try {
+ $enableCryptoResult = stream_socket_enable_crypto($this->connection, $enable, $this->_encryptMethods[$type . '_' . $clientOrServer]);
+ } catch (Exception $e) {
+ $this->setLastError(null, $e->getMessage());
+ throw new SocketException($e->getMessage());
+ }
+ if ($enableCryptoResult === true) {
+ $this->encrypted = $enable;
+ return true;
+ } else {
+ $errorMessage = __d('cake_dev', 'Unable to perform enableCrypto operation on CakeSocket');
+ $this->setLastError(null, $errorMessage);
+ throw new SocketException($errorMessage);
+ }
+ }
+
}
diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php
index 9bf4d434e..8f53cd217 100644
--- a/lib/Cake/Network/Email/CakeEmail.php
+++ b/lib/Cake/Network/Email/CakeEmail.php
@@ -946,13 +946,17 @@ class CakeEmail {
* $email->attachments(array('custom_name.png' => array(
* 'file' => 'path/to/file',
* 'mimetype' => 'image/png',
- * 'contentId' => 'abc123'
+ * 'contentId' => 'abc123',
+ * 'contentDisposition' => false
* ));
* }}}
*
* The `contentId` key allows you to specify an inline attachment. In your email text, you
* can use `
` to display the image inline.
*
+ * The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve
+ * attachment compatibility with outlook email clients.
+ *
* @param string|array $attachments String with the filename or array with filenames
* @return array|CakeEmail Either the array of attachments when getting or $this when setting.
* @throws SocketException
@@ -991,6 +995,7 @@ class CakeEmail {
* @param string|array $attachments String with the filename or array with filenames
* @return CakeEmail $this
* @throws SocketException
+ * @see CakeEmail::attachments()
*/
public function addAttachments($attachments) {
$current = $this->_attachments;
@@ -1355,7 +1360,12 @@ class CakeEmail {
$msg[] = '--' . $boundary;
$msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
$msg[] = 'Content-Transfer-Encoding: base64';
- $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"';
+ if (
+ !isset($fileInfo['contentDisposition']) ||
+ $fileInfo['contentDisposition']
+ ) {
+ $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"';
+ }
$msg[] = '';
$msg[] = $data;
$msg[] = '';
diff --git a/lib/Cake/Network/Email/SmtpTransport.php b/lib/Cake/Network/Email/SmtpTransport.php
index 363e477e8..eb3c13595 100644
--- a/lib/Cake/Network/Email/SmtpTransport.php
+++ b/lib/Cake/Network/Email/SmtpTransport.php
@@ -79,7 +79,8 @@ class SmtpTransport extends AbstractTransport {
'timeout' => 30,
'username' => null,
'password' => null,
- 'client' => null
+ 'client' => null,
+ 'tls' => false
);
$this->_config = $config + $default;
}
@@ -107,7 +108,15 @@ class SmtpTransport extends AbstractTransport {
try {
$this->_smtpSend("EHLO {$host}", '250');
+ if ($this->_config['tls']) {
+ $this->_smtpSend("STARTTLS", '220');
+ $this->_socket->enableCrypto('tls');
+ $this->_smtpSend("EHLO {$host}", '250');
+ }
} catch (SocketException $e) {
+ if ($this->_config['tls']) {
+ throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.'));
+ }
try {
$this->_smtpSend("HELO {$host}", '250');
} catch (SocketException $e2) {
@@ -132,6 +141,8 @@ class SmtpTransport extends AbstractTransport {
if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
}
+ } elseif ($authRequired == '504') {
+ throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS'));
} elseif ($authRequired != '503') {
throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.'));
}
diff --git a/lib/Cake/Network/Http/HttpResponse.php b/lib/Cake/Network/Http/HttpResponse.php
index dec507041..2b16a0ca3 100644
--- a/lib/Cake/Network/Http/HttpResponse.php
+++ b/lib/Cake/Network/Http/HttpResponse.php
@@ -12,437 +12,24 @@
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
- * @package Cake.Network.Http
* @since CakePHP(tm) v 2.0.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('HttpSocketResponse', 'Network/Http');
+
+if (class_exists('HttpResponse')) {
+ trigger_error(__d(
+ 'cake_dev',
+ "HttpResponse is deprecated due to naming conflicts. Use HttpSocketResponse instead."
+ ), E_USER_ERROR);
+}
/**
* HTTP Response from HttpSocket.
*
* @package Cake.Network.Http
+ * @deprecated This class is deprecated as it has naming conflicts with pecl/http
*/
-class HttpResponse implements ArrayAccess {
-
-/**
- * Body content
- *
- * @var string
- */
- public $body = '';
-
-/**
- * Headers
- *
- * @var array
- */
- public $headers = array();
-
-/**
- * Cookies
- *
- * @var array
- */
- public $cookies = array();
-
-/**
- * HTTP version
- *
- * @var string
- */
- public $httpVersion = 'HTTP/1.1';
-
-/**
- * Response code
- *
- * @var integer
- */
- public $code = 0;
-
-/**
- * Reason phrase
- *
- * @var string
- */
- public $reasonPhrase = '';
-
-/**
- * Pure raw content
- *
- * @var string
- */
- public $raw = '';
-
-/**
- * Constructor
- *
- * @param string $message
- */
- public function __construct($message = null) {
- if ($message !== null) {
- $this->parseResponse($message);
- }
- }
-
-/**
- * Body content
- *
- * @return string
- */
- public function body() {
- return (string)$this->body;
- }
-
-/**
- * Get header in case insensitive
- *
- * @param string $name Header name
- * @param array $headers
- * @return mixed String if header exists or null
- */
- public function getHeader($name, $headers = null) {
- if (!is_array($headers)) {
- $headers =& $this->headers;
- }
- if (isset($headers[$name])) {
- return $headers[$name];
- }
- foreach ($headers as $key => $value) {
- if (strcasecmp($key, $name) == 0) {
- return $value;
- }
- }
- return null;
- }
-
-/**
- * If return is 200 (OK)
- *
- * @return boolean
- */
- public function isOk() {
- return $this->code == 200;
- }
-
-/**
- * If return is a valid 3xx (Redirection)
- *
- * @return boolean
- */
- public function isRedirect() {
- return in_array($this->code, array(301, 302, 303, 307)) && !is_null($this->getHeader('Location'));
- }
-
-/**
- * Parses the given message and breaks it down in parts.
- *
- * @param string $message Message to parse
- * @return void
- * @throws SocketException
- */
- public function parseResponse($message) {
- if (!is_string($message)) {
- throw new SocketException(__d('cake_dev', 'Invalid response.'));
- }
-
- if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
- throw new SocketException(__d('cake_dev', 'Invalid HTTP response.'));
- }
-
- list(, $statusLine, $header) = $match;
- $this->raw = $message;
- $this->body = (string)substr($message, strlen($match[0]));
-
- if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) {
- $this->httpVersion = $match[1];
- $this->code = $match[2];
- $this->reasonPhrase = $match[3];
- }
-
- $this->headers = $this->_parseHeader($header);
- $transferEncoding = $this->getHeader('Transfer-Encoding');
- $decoded = $this->_decodeBody($this->body, $transferEncoding);
- $this->body = $decoded['body'];
-
- if (!empty($decoded['header'])) {
- $this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header']));
- }
-
- if (!empty($this->headers)) {
- $this->cookies = $this->parseCookies($this->headers);
- }
- }
-
-/**
- * Generic function to decode a $body with a given $encoding. Returns either an array with the keys
- * 'body' and 'header' or false on failure.
- *
- * @param string $body A string containing the body to decode.
- * @param string|boolean $encoding Can be false in case no encoding is being used, or a string representing the encoding.
- * @return mixed Array of response headers and body or false.
- */
- protected function _decodeBody($body, $encoding = 'chunked') {
- if (!is_string($body)) {
- return false;
- }
- if (empty($encoding)) {
- return array('body' => $body, 'header' => false);
- }
- $decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body';
-
- if (!is_callable(array(&$this, $decodeMethod))) {
- return array('body' => $body, 'header' => false);
- }
- return $this->{$decodeMethod}($body);
- }
-
-/**
- * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
- * a result.
- *
- * @param string $body A string containing the chunked body to decode.
- * @return mixed Array of response headers and body or false.
- * @throws SocketException
- */
- protected function _decodeChunkedBody($body) {
- if (!is_string($body)) {
- return false;
- }
-
- $decodedBody = null;
- $chunkLength = null;
-
- while ($chunkLength !== 0) {
- if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
- throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.'));
- }
-
- $chunkSize = 0;
- $hexLength = 0;
- $chunkExtensionName = '';
- $chunkExtensionValue = '';
- if (isset($match[0])) {
- $chunkSize = $match[0];
- }
- if (isset($match[1])) {
- $hexLength = $match[1];
- }
- if (isset($match[2])) {
- $chunkExtensionName = $match[2];
- }
- if (isset($match[3])) {
- $chunkExtensionValue = $match[3];
- }
-
- $body = substr($body, strlen($chunkSize));
- $chunkLength = hexdec($hexLength);
- $chunk = substr($body, 0, $chunkLength);
- if (!empty($chunkExtensionName)) {
- // @todo See if there are popular chunk extensions we should implement
- }
- $decodedBody .= $chunk;
- if ($chunkLength !== 0) {
- $body = substr($body, $chunkLength + strlen("\r\n"));
- }
- }
-
- $entityHeader = false;
- if (!empty($body)) {
- $entityHeader = $this->_parseHeader($body);
- }
- return array('body' => $decodedBody, 'header' => $entityHeader);
- }
-
-/**
- * Parses an array based header.
- *
- * @param array $header Header as an indexed array (field => value)
- * @return array Parsed header
- */
- protected function _parseHeader($header) {
- if (is_array($header)) {
- return $header;
- } elseif (!is_string($header)) {
- return false;
- }
-
- preg_match_all("/(.+):(.+)(?:(?_unescapeToken($field);
-
- if (!isset($header[$field])) {
- $header[$field] = $value;
- } else {
- $header[$field] = array_merge((array)$header[$field], (array)$value);
- }
- }
- return $header;
- }
-
-/**
- * Parses cookies in response headers.
- *
- * @param array $header Header array containing one ore more 'Set-Cookie' headers.
- * @return mixed Either false on no cookies, or an array of cookies received.
- * @todo Make this 100% RFC 2965 confirm
- */
- public function parseCookies($header) {
- $cookieHeader = $this->getHeader('Set-Cookie', $header);
- if (!$cookieHeader) {
- return false;
- }
-
- $cookies = array();
- foreach ((array)$cookieHeader as $cookie) {
- if (strpos($cookie, '";"') !== false) {
- $cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
- $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
- } else {
- $parts = preg_split('/\;[ \t]*/', $cookie);
- }
-
- list($name, $value) = explode('=', array_shift($parts), 2);
- $cookies[$name] = compact('value');
-
- foreach ($parts as $part) {
- if (strpos($part, '=') !== false) {
- list($key, $value) = explode('=', $part);
- } else {
- $key = $part;
- $value = true;
- }
-
- $key = strtolower($key);
- if (!isset($cookies[$name][$key])) {
- $cookies[$name][$key] = $value;
- }
- }
- }
- return $cookies;
- }
-
-/**
- * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
- *
- * @param string $token Token to unescape
- * @param array $chars
- * @return string Unescaped token
- * @todo Test $chars parameter
- */
- protected function _unescapeToken($token, $chars = null) {
- $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/';
- $token = preg_replace($regex, '\\1', $token);
- return $token;
- }
-
-/**
- * Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
- *
- * @param boolean $hex true to get them as HEX values, false otherwise
- * @param array $chars
- * @return array Escape chars
- * @todo Test $chars parameter
- */
- protected function _tokenEscapeChars($hex = true, $chars = null) {
- if (!empty($chars)) {
- $escape = $chars;
- } else {
- $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
- for ($i = 0; $i <= 31; $i++) {
- $escape[] = chr($i);
- }
- $escape[] = chr(127);
- }
-
- if ($hex == false) {
- return $escape;
- }
- foreach ($escape as $key => $char) {
- $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
- }
- return $escape;
- }
-
-/**
- * ArrayAccess - Offset Exists
- *
- * @param string $offset
- * @return boolean
- */
- public function offsetExists($offset) {
- return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies'));
- }
-
-/**
- * ArrayAccess - Offset Get
- *
- * @param string $offset
- * @return mixed
- */
- public function offsetGet($offset) {
- switch ($offset) {
- case 'raw':
- $firstLineLength = strpos($this->raw, "\r\n") + 2;
- if ($this->raw[$firstLineLength] === "\r") {
- $header = null;
- } else {
- $header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n";
- }
- return array(
- 'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n",
- 'header' => $header,
- 'body' => $this->body,
- 'response' => $this->raw
- );
- case 'status':
- return array(
- 'http-version' => $this->httpVersion,
- 'code' => $this->code,
- 'reason-phrase' => $this->reasonPhrase
- );
- case 'header':
- return $this->headers;
- case 'body':
- return $this->body;
- case 'cookies':
- return $this->cookies;
- }
- return null;
- }
-
-/**
- * ArrayAccess - Offset Set
- *
- * @param string $offset
- * @param mixed $value
- * @return void
- */
- public function offsetSet($offset, $value) {
- }
-
-/**
- * ArrayAccess - Offset Unset
- *
- * @param string $offset
- * @return void
- */
- public function offsetUnset($offset) {
- }
-
-/**
- * Instance as string
- *
- * @return string
- */
- public function __toString() {
- return $this->body();
- }
+class HttpResponse extends HttpSocketResponse {
}
diff --git a/lib/Cake/Network/Http/HttpSocket.php b/lib/Cake/Network/Http/HttpSocket.php
index bda8ec4c7..a0dae10f6 100644
--- a/lib/Cake/Network/Http/HttpSocket.php
+++ b/lib/Cake/Network/Http/HttpSocket.php
@@ -18,6 +18,7 @@
*/
App::uses('CakeSocket', 'Network');
App::uses('Router', 'Routing');
+App::uses('Hash', 'Utility');
/**
* Cake network socket connection class.
@@ -64,7 +65,7 @@ class HttpSocket extends CakeSocket {
),
'raw' => null,
'redirect' => false,
- 'cookies' => array()
+ 'cookies' => array(),
);
/**
@@ -79,7 +80,7 @@ class HttpSocket extends CakeSocket {
*
* @var string
*/
- public $responseClass = 'HttpResponse';
+ public $responseClass = 'HttpSocketResponse';
/**
* Configuration settings for the HttpSocket and the requests
@@ -92,6 +93,9 @@ class HttpSocket extends CakeSocket {
'protocol' => 'tcp',
'port' => 80,
'timeout' => 30,
+ 'ssl_verify_peer' => true,
+ 'ssl_verify_depth' => 5,
+ 'ssl_verify_host' => true,
'request' => array(
'uri' => array(
'scheme' => array('http', 'https'),
@@ -99,7 +103,7 @@ class HttpSocket extends CakeSocket {
'port' => array(80, 443)
),
'redirect' => false,
- 'cookies' => array()
+ 'cookies' => array(),
)
);
@@ -246,7 +250,7 @@ class HttpSocket extends CakeSocket {
* method and provide a more granular interface.
*
* @param string|array $request Either an URI string, or an array defining host/uri
- * @return mixed false on error, HttpResponse on success
+ * @return mixed false on error, HttpSocketResponse on success
* @throws SocketException
*/
public function request($request = array()) {
@@ -348,6 +352,8 @@ class HttpSocket extends CakeSocket {
return false;
}
+ $this->_configContext($this->request['uri']['host']);
+
$this->request['raw'] = '';
if ($this->request['line'] !== false) {
$this->request['raw'] = $this->request['line'];
@@ -395,6 +401,7 @@ class HttpSocket extends CakeSocket {
throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass));
}
$this->response = new $responseClass($response);
+
if (!empty($this->response->cookies)) {
if (!isset($this->config['request']['cookies'][$Host])) {
$this->config['request']['cookies'][$Host] = array();
@@ -643,6 +650,33 @@ class HttpSocket extends CakeSocket {
return true;
}
+/**
+ * Configure the socket's context. Adds in configuration
+ * that can not be declared in the class definition.
+ *
+ * @param string $host The host you're connecting to.
+ * @return void
+ */
+ protected function _configContext($host) {
+ foreach ($this->config as $key => $value) {
+ if (substr($key, 0, 4) !== 'ssl_') {
+ continue;
+ }
+ $contextKey = substr($key, 4);
+ if (empty($this->config['context']['ssl'][$contextKey])) {
+ $this->config['context']['ssl'][$contextKey] = $value;
+ }
+ unset($this->config[$key]);
+ }
+ if (empty($this->_context['ssl']['cafile'])) {
+ $this->config['context']['ssl']['cafile'] = CAKE . 'Config' . DS . 'cacert.pem';
+ }
+ if (!empty($this->config['context']['ssl']['verify_host'])) {
+ $this->config['context']['ssl']['CN_match'] = $host;
+ unset($this->config['context']['ssl']['verify_host']);
+ }
+ }
+
/**
* Takes a $uri array and turns it into a fully qualified URL string
*
@@ -944,7 +978,7 @@ class HttpSocket extends CakeSocket {
$escape[] = chr(127);
}
- if ($hex == false) {
+ if (!$hex) {
return $escape;
}
foreach ($escape as $key => $char) {
diff --git a/lib/Cake/Network/Http/HttpSocketResponse.php b/lib/Cake/Network/Http/HttpSocketResponse.php
new file mode 100644
index 000000000..9812894a7
--- /dev/null
+++ b/lib/Cake/Network/Http/HttpSocketResponse.php
@@ -0,0 +1,455 @@
+parseResponse($message);
+ }
+ }
+
+/**
+ * Body content
+ *
+ * @return string
+ */
+ public function body() {
+ return (string)$this->body;
+ }
+
+/**
+ * Get header in case insensitive
+ *
+ * @param string $name Header name
+ * @param array $headers
+ * @return mixed String if header exists or null
+ */
+ public function getHeader($name, $headers = null) {
+ if (!is_array($headers)) {
+ $headers =& $this->headers;
+ }
+ if (isset($headers[$name])) {
+ return $headers[$name];
+ }
+ foreach ($headers as $key => $value) {
+ if (strcasecmp($key, $name) === 0) {
+ return $value;
+ }
+ }
+ return null;
+ }
+
+/**
+ * If return is 200 (OK)
+ *
+ * @return boolean
+ */
+ public function isOk() {
+ return $this->code == 200;
+ }
+
+/**
+ * If return is a valid 3xx (Redirection)
+ *
+ * @return boolean
+ */
+ public function isRedirect() {
+ return in_array($this->code, array(301, 302, 303, 307)) && !is_null($this->getHeader('Location'));
+ }
+
+/**
+ * Parses the given message and breaks it down in parts.
+ *
+ * @param string $message Message to parse
+ * @return void
+ * @throws SocketException
+ */
+ public function parseResponse($message) {
+ if (!is_string($message)) {
+ throw new SocketException(__d('cake_dev', 'Invalid response.'));
+ }
+
+ if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
+ throw new SocketException(__d('cake_dev', 'Invalid HTTP response.'));
+ }
+
+ list(, $statusLine, $header) = $match;
+ $this->raw = $message;
+ $this->body = (string)substr($message, strlen($match[0]));
+
+ if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) {
+ $this->httpVersion = $match[1];
+ $this->code = $match[2];
+ $this->reasonPhrase = $match[3];
+ }
+
+ $this->headers = $this->_parseHeader($header);
+ $transferEncoding = $this->getHeader('Transfer-Encoding');
+ $decoded = $this->_decodeBody($this->body, $transferEncoding);
+ $this->body = $decoded['body'];
+
+ if (!empty($decoded['header'])) {
+ $this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header']));
+ }
+
+ if (!empty($this->headers)) {
+ $this->cookies = $this->parseCookies($this->headers);
+ }
+ }
+
+/**
+ * Generic function to decode a $body with a given $encoding. Returns either an array with the keys
+ * 'body' and 'header' or false on failure.
+ *
+ * @param string $body A string containing the body to decode.
+ * @param string|boolean $encoding Can be false in case no encoding is being used, or a string representing the encoding.
+ * @return mixed Array of response headers and body or false.
+ */
+ protected function _decodeBody($body, $encoding = 'chunked') {
+ if (!is_string($body)) {
+ return false;
+ }
+ if (empty($encoding)) {
+ return array('body' => $body, 'header' => false);
+ }
+ $decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body';
+
+ if (!is_callable(array(&$this, $decodeMethod))) {
+ return array('body' => $body, 'header' => false);
+ }
+ return $this->{$decodeMethod}($body);
+ }
+
+/**
+ * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
+ * a result.
+ *
+ * @param string $body A string containing the chunked body to decode.
+ * @return mixed Array of response headers and body or false.
+ * @throws SocketException
+ */
+ protected function _decodeChunkedBody($body) {
+ if (!is_string($body)) {
+ return false;
+ }
+
+ $decodedBody = null;
+ $chunkLength = null;
+
+ while ($chunkLength !== 0) {
+ if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
+ throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.'));
+ }
+
+ $chunkSize = 0;
+ $hexLength = 0;
+ $chunkExtensionName = '';
+ $chunkExtensionValue = '';
+ if (isset($match[0])) {
+ $chunkSize = $match[0];
+ }
+ if (isset($match[1])) {
+ $hexLength = $match[1];
+ }
+ if (isset($match[2])) {
+ $chunkExtensionName = $match[2];
+ }
+ if (isset($match[3])) {
+ $chunkExtensionValue = $match[3];
+ }
+
+ $body = substr($body, strlen($chunkSize));
+ $chunkLength = hexdec($hexLength);
+ $chunk = substr($body, 0, $chunkLength);
+ if (!empty($chunkExtensionName)) {
+ // @todo See if there are popular chunk extensions we should implement
+ }
+ $decodedBody .= $chunk;
+ if ($chunkLength !== 0) {
+ $body = substr($body, $chunkLength + strlen("\r\n"));
+ }
+ }
+
+ $entityHeader = false;
+ if (!empty($body)) {
+ $entityHeader = $this->_parseHeader($body);
+ }
+ return array('body' => $decodedBody, 'header' => $entityHeader);
+ }
+
+/**
+ * Parses an array based header.
+ *
+ * @param array $header Header as an indexed array (field => value)
+ * @return array Parsed header
+ */
+ protected function _parseHeader($header) {
+ if (is_array($header)) {
+ return $header;
+ } elseif (!is_string($header)) {
+ return false;
+ }
+
+ preg_match_all("/(.+):(.+)(?:(?_unescapeToken($field);
+
+ if (!isset($header[$field])) {
+ $header[$field] = $value;
+ } else {
+ $header[$field] = array_merge((array)$header[$field], (array)$value);
+ }
+ }
+ return $header;
+ }
+
+/**
+ * Parses cookies in response headers.
+ *
+ * @param array $header Header array containing one ore more 'Set-Cookie' headers.
+ * @return mixed Either false on no cookies, or an array of cookies received.
+ * @todo Make this 100% RFC 2965 confirm
+ */
+ public function parseCookies($header) {
+ $cookieHeader = $this->getHeader('Set-Cookie', $header);
+ if (!$cookieHeader) {
+ return false;
+ }
+
+ $cookies = array();
+ foreach ((array)$cookieHeader as $cookie) {
+ if (strpos($cookie, '";"') !== false) {
+ $cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
+ $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
+ } else {
+ $parts = preg_split('/\;[ \t]*/', $cookie);
+ }
+
+ list($name, $value) = explode('=', array_shift($parts), 2);
+ $cookies[$name] = compact('value');
+
+ foreach ($parts as $part) {
+ if (strpos($part, '=') !== false) {
+ list($key, $value) = explode('=', $part);
+ } else {
+ $key = $part;
+ $value = true;
+ }
+
+ $key = strtolower($key);
+ if (!isset($cookies[$name][$key])) {
+ $cookies[$name][$key] = $value;
+ }
+ }
+ }
+ return $cookies;
+ }
+
+/**
+ * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
+ *
+ * @param string $token Token to unescape
+ * @param array $chars
+ * @return string Unescaped token
+ * @todo Test $chars parameter
+ */
+ protected function _unescapeToken($token, $chars = null) {
+ $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/';
+ $token = preg_replace($regex, '\\1', $token);
+ return $token;
+ }
+
+/**
+ * Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
+ *
+ * @param boolean $hex true to get them as HEX values, false otherwise
+ * @param array $chars
+ * @return array Escape chars
+ * @todo Test $chars parameter
+ */
+ protected function _tokenEscapeChars($hex = true, $chars = null) {
+ if (!empty($chars)) {
+ $escape = $chars;
+ } else {
+ $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
+ for ($i = 0; $i <= 31; $i++) {
+ $escape[] = chr($i);
+ }
+ $escape[] = chr(127);
+ }
+
+ if (!$hex) {
+ return $escape;
+ }
+ foreach ($escape as $key => $char) {
+ $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
+ }
+ return $escape;
+ }
+
+/**
+ * ArrayAccess - Offset Exists
+ *
+ * @param string $offset
+ * @return boolean
+ */
+ public function offsetExists($offset) {
+ return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies'));
+ }
+
+/**
+ * ArrayAccess - Offset Get
+ *
+ * @param string $offset
+ * @return mixed
+ */
+ public function offsetGet($offset) {
+ switch ($offset) {
+ case 'raw':
+ $firstLineLength = strpos($this->raw, "\r\n") + 2;
+ if ($this->raw[$firstLineLength] === "\r") {
+ $header = null;
+ } else {
+ $header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n";
+ }
+ return array(
+ 'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n",
+ 'header' => $header,
+ 'body' => $this->body,
+ 'response' => $this->raw
+ );
+ case 'status':
+ return array(
+ 'http-version' => $this->httpVersion,
+ 'code' => $this->code,
+ 'reason-phrase' => $this->reasonPhrase
+ );
+ case 'header':
+ return $this->headers;
+ case 'body':
+ return $this->body;
+ case 'cookies':
+ return $this->cookies;
+ }
+ return null;
+ }
+
+/**
+ * ArrayAccess - Offset Set
+ *
+ * @param string $offset
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($offset, $value) {
+ }
+
+/**
+ * ArrayAccess - Offset Unset
+ *
+ * @param string $offset
+ * @return void
+ */
+ public function offsetUnset($offset) {
+ }
+
+/**
+ * Instance as string
+ *
+ * @return string
+ */
+ public function __toString() {
+ return $this->body();
+ }
+
+}
diff --git a/lib/Cake/Routing/Dispatcher.php b/lib/Cake/Routing/Dispatcher.php
index b10fe4ebb..3f891f32b 100644
--- a/lib/Cake/Routing/Dispatcher.php
+++ b/lib/Cake/Routing/Dispatcher.php
@@ -209,12 +209,6 @@ class Dispatcher implements CakeEventListener {
public function parseParams($event) {
$request = $event->data['request'];
Router::setRequestInfo($request);
- if (count(Router::$routes) == 0) {
- $namedExpressions = Router::getNamedExpressions();
- extract($namedExpressions);
- $this->_loadRoutes();
- }
-
$params = Router::parse($request->url);
$request->addParams($params);
@@ -269,13 +263,4 @@ class Dispatcher implements CakeEventListener {
return false;
}
-/**
- * Loads route configuration
- *
- * @return void
- */
- protected function _loadRoutes() {
- include APP . 'Config' . DS . 'routes.php';
- }
-
}
diff --git a/lib/Cake/Routing/Filter/AssetDispatcher.php b/lib/Cake/Routing/Filter/AssetDispatcher.php
index 11840ba8b..24aff7cd0 100644
--- a/lib/Cake/Routing/Filter/AssetDispatcher.php
+++ b/lib/Cake/Routing/Filter/AssetDispatcher.php
@@ -42,8 +42,6 @@ class AssetDispatcher extends DispatcherFilter {
*/
public function beforeDispatch($event) {
$url = $event->data['request']->url;
- $response = $event->data['response'];
-
if (strpos($url, '..') !== false || strpos($url, '.') === false) {
return;
}
@@ -53,43 +51,27 @@ class AssetDispatcher extends DispatcherFilter {
return $result;
}
- $pathSegments = explode('.', $url);
- $ext = array_pop($pathSegments);
- $parts = explode('/', $url);
- $assetFile = null;
-
- if ($parts[0] === 'theme') {
- $themeName = $parts[1];
- unset($parts[0], $parts[1]);
- $fileFragment = urldecode(implode(DS, $parts));
- $path = App::themePath($themeName) . 'webroot' . DS;
- if (file_exists($path . $fileFragment)) {
- $assetFile = $path . $fileFragment;
- }
- } else {
- $plugin = Inflector::camelize($parts[0]);
- if (CakePlugin::loaded($plugin)) {
- unset($parts[0]);
- $fileFragment = urldecode(implode(DS, $parts));
- $pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
- if (file_exists($pluginWebroot . $fileFragment)) {
- $assetFile = $pluginWebroot . $fileFragment;
- }
- }
+ $assetFile = $this->_getAssetFile($url);
+ if ($assetFile === null || !file_exists($assetFile)) {
+ return null;
}
- if ($assetFile !== null) {
- $event->stopPropagation();
- $response->modified(filemtime($assetFile));
- if (!$response->checkNotModified($event->data['request'])) {
- $this->_deliverAsset($response, $assetFile, $ext);
- }
+ $response = $event->data['response'];
+ $event->stopPropagation();
+
+ $response->modified(filemtime($assetFile));
+ if ($response->checkNotModified($event->data['request'])) {
return $response;
}
+
+ $pathSegments = explode('.', $url);
+ $ext = array_pop($pathSegments);
+ $this->_deliverAsset($response, $assetFile, $ext);
+ return $response;
}
/**
- * Checks if the client is requeting a filtered asset and runs the corresponding
+ * Checks if the client is requesting a filtered asset and runs the corresponding
* filter if any is configured
*
* @param CakeEvent $event containing the request and response object
@@ -111,15 +93,44 @@ class AssetDispatcher extends DispatcherFilter {
if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) {
$response->statusCode(404);
return $response;
- } elseif ($isCss) {
+ }
+
+ if ($isCss) {
include WWW_ROOT . DS . $filters['css'];
return $response;
- } elseif ($isJs) {
+ }
+
+ if ($isJs) {
include WWW_ROOT . DS . $filters['js'];
return $response;
}
}
+/**
+ * Builds asset file path based off url
+ *
+ * @param string $url
+ * @return string Absolute path for asset file
+ */
+ protected function _getAssetFile($url) {
+ $parts = explode('/', $url);
+ if ($parts[0] === 'theme') {
+ $themeName = $parts[1];
+ unset($parts[0], $parts[1]);
+ $fileFragment = urldecode(implode(DS, $parts));
+ $path = App::themePath($themeName) . 'webroot' . DS;
+ return $path . $fileFragment;
+ }
+
+ $plugin = Inflector::camelize($parts[0]);
+ if (CakePlugin::loaded($plugin)) {
+ unset($parts[0]);
+ $fileFragment = urldecode(implode(DS, $parts));
+ $pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
+ return $pluginWebroot . $fileFragment;
+ }
+ }
+
/**
* Sends an asset file to the client
*
diff --git a/lib/Cake/Routing/Route/CakeRoute.php b/lib/Cake/Routing/Route/CakeRoute.php
index 8fab212cf..a95c8ce8b 100644
--- a/lib/Cake/Routing/Route/CakeRoute.php
+++ b/lib/Cake/Routing/Route/CakeRoute.php
@@ -154,7 +154,8 @@ class CakeRoute {
if (preg_match('#\/\*\*$#', $route)) {
$parsed = preg_replace('#/\\\\\*\\\\\*$#', '(?:/(?P<_trailing_>.*))?', $parsed);
$this->_greedy = true;
- } elseif (preg_match('#\/\*$#', $route)) {
+ }
+ if (preg_match('#\/\*$#', $route)) {
$parsed = preg_replace('#/\\\\\*$#', '(?:/(?P<_args_>.*))?', $parsed);
$this->_greedy = true;
}
@@ -163,7 +164,7 @@ class CakeRoute {
$this->_compiledRoute = '#^' . $parsed . '[/]*$#';
$this->keys = $names;
- //remove defaults that are also keys. They can cause match failures
+ // Remove defaults that are also keys. They can cause match failures
foreach ($this->keys as $key) {
unset($this->defaults[$key]);
}
@@ -219,7 +220,7 @@ class CakeRoute {
if (isset($route[$key])) {
continue;
}
- if (is_integer($key)) {
+ if (is_int($key)) {
$route['pass'][] = $value;
continue;
}
diff --git a/lib/Cake/Routing/Route/RedirectRoute.php b/lib/Cake/Routing/Route/RedirectRoute.php
index bfb0f06c3..d890d2475 100644
--- a/lib/Cake/Routing/Route/RedirectRoute.php
+++ b/lib/Cake/Routing/Route/RedirectRoute.php
@@ -74,7 +74,7 @@ class RedirectRoute extends CakeRoute {
$this->response = new CakeResponse();
}
$redirect = $this->redirect;
- if (count($this->redirect) == 1 && !isset($this->redirect['controller'])) {
+ if (count($this->redirect) === 1 && !isset($this->redirect['controller'])) {
$redirect = $this->redirect[0];
}
if (isset($this->options['persist']) && is_array($redirect)) {
diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php
index 2a02570cd..33b098dc5 100644
--- a/lib/Cake/Routing/Router.php
+++ b/lib/Cake/Routing/Router.php
@@ -48,6 +48,13 @@ class Router {
*/
public static $routes = array();
+/**
+ * Have routes been loaded
+ *
+ * @var boolean
+ */
+ public static $initialized = false;
+
/**
* List of action prefixes used in connected routes.
* Includes admin prefix
@@ -284,6 +291,8 @@ class Router {
* @throws RouterException
*/
public static function connect($route, $defaults = array(), $options = array()) {
+ self::$initialized = true;
+
foreach (self::$_prefixes as $prefix) {
if (isset($defaults[$prefix])) {
if ($defaults[$prefix]) {
@@ -304,7 +313,12 @@ class Router {
}
$routeClass = self::$_routeClass;
if (isset($options['routeClass'])) {
- $routeClass = self::_validateRouteClass($options['routeClass']);
+ if (strpos($options['routeClass'], '.') === false) {
+ $routeClass = $options['routeClass'];
+ } else {
+ list($plugin, $routeClass) = pluginSplit($options['routeClass'], true);
+ }
+ $routeClass = self::_validateRouteClass($routeClass);
unset($options['routeClass']);
}
if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) {
@@ -420,7 +434,7 @@ class Router {
$options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options);
}
- if ($options['reset'] == true || self::$_namedConfig['rules'] === false) {
+ if ($options['reset'] || self::$_namedConfig['rules'] === false) {
self::$_namedConfig['rules'] = array();
}
@@ -515,6 +529,10 @@ class Router {
* @return array Parsed elements from URL
*/
public static function parse($url) {
+ if (!self::$initialized) {
+ self::_loadRoutes();
+ }
+
$ext = null;
$out = array();
@@ -743,6 +761,10 @@ class Router {
* @return string Full translated URL with base path.
*/
public static function url($url = null, $full = false) {
+ if (!self::$initialized) {
+ self::_loadRoutes();
+ }
+
$params = array('plugin' => null, 'controller' => null, 'action' => 'index');
if (is_bool($full)) {
@@ -829,12 +851,7 @@ class Router {
$output = self::_handleNoRoute($url);
}
} else {
- if (
- (strpos($url, '://') !== false ||
- (strpos($url, 'javascript:') === 0) ||
- (strpos($url, 'mailto:') === 0)) ||
- (!strncmp($url, '#', 1))
- ) {
+ if (preg_match('/:\/\/|^(javascript|mailto|tel|sms):|\#/i', $url)) {
return $url;
}
if (substr($url, 0, 1) === '/') {
@@ -928,9 +945,9 @@ class Router {
if (!empty($named)) {
foreach ($named as $name => $value) {
if (is_array($value)) {
- $flattend = Hash::flatten($value, '][');
+ $flattend = Hash::flatten($value, '%5D%5B');
foreach ($flattend as $namedKey => $namedValue) {
- $output .= '/' . $name . "[$namedKey]" . self::$_namedConfig['separator'] . rawurlencode($namedValue);
+ $output .= '/' . $name . "%5B{$namedKey}%5D" . self::$_namedConfig['separator'] . rawurlencode($namedValue);
}
} else {
$output .= '/' . $name . self::$_namedConfig['separator'] . rawurlencode($value);
@@ -1073,7 +1090,7 @@ class Router {
* @return string base url with plugin name removed if present
*/
public static function stripPlugin($base, $plugin = null) {
- if ($plugin != null) {
+ if ($plugin) {
$base = preg_replace('/(?:' . $plugin . ')/', '', $base);
$base = str_replace('//', '', $base);
$pos1 = strrpos($base, '/');
@@ -1117,6 +1134,10 @@ class Router {
* @return array Array of extensions Router is configured to parse.
*/
public static function extensions() {
+ if (!self::$initialized) {
+ self::_loadRoutes();
+ }
+
return self::$_validExtensions;
}
@@ -1138,6 +1159,16 @@ class Router {
return self::$_validExtensions = array_merge(self::$_validExtensions, $extensions);
}
+/**
+ * Loads route configuration
+ *
+ * @return void
+ */
+ protected static function _loadRoutes() {
+ self::$initialized = true;
+ include APP . 'Config' . DS . 'routes.php';
+ }
+
}
//Save the initial state
diff --git a/lib/Cake/Test/Case/BasicsTest.php b/lib/Cake/Test/Case/BasicsTest.php
index 0998dfa77..6d67fd8be 100644
--- a/lib/Cake/Test/Case/BasicsTest.php
+++ b/lib/Cake/Test/Case/BasicsTest.php
@@ -825,6 +825,18 @@ EXPECTED;
########## DEBUG ##########
'
this-is-a-test
'
###########################
+EXPECTED;
+ $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 8);
+ $this->assertEquals($expected, $result);
+
+ ob_start();
+ debug(false, false, false);
+ $result = ob_get_clean();
+ $expected = <<
assertEquals($expected, $result);
diff --git a/lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php
index de4c50d92..5c9335e04 100644
--- a/lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php
+++ b/lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php
@@ -73,7 +73,8 @@ class RegisEngineTest extends CakeTestCase {
'server' => '127.0.0.1',
'port' => 6379,
'timeout' => 0,
- 'persistent' => true
+ 'persistent' => true,
+ 'password' => false,
);
$this->assertEquals($expecting, $settings);
}
diff --git a/lib/Cake/Test/Case/Configure/IniReaderTest.php b/lib/Cake/Test/Case/Configure/IniReaderTest.php
index 5bbbe57c1..a7e47037a 100644
--- a/lib/Cake/Test/Case/Configure/IniReaderTest.php
+++ b/lib/Cake/Test/Case/Configure/IniReaderTest.php
@@ -261,6 +261,7 @@ three.four = value four
is_null = null
bool_false = false
bool_true = true
+
[Asset]
timestamp = force
INI;
diff --git a/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php b/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php
index 22eed1920..554917c68 100644
--- a/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php
+++ b/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php
@@ -88,7 +88,7 @@ class CommandListShellTest extends CakeTestCase {
$expected = "/\[.*TestPluginTwo.*\] example, welcome/";
$this->assertRegExp($expected, $output);
- $expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, test, testsuite, upgrade/";
+ $expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, server, test, testsuite, upgrade/";
$this->assertRegExp($expected, $output);
$expected = "/\[.*app.*\] sample/";
diff --git a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php
index 7d2175389..34441aa7a 100644
--- a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php
+++ b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php
@@ -362,6 +362,40 @@ class SchemaShellTest extends CakeTestCase {
CakePlugin::unload();
}
+/**
+ * test generate with specific models
+ *
+ * @return void
+ */
+ public function testGenerateModels() {
+ App::build(array(
+ 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
+ ), App::RESET);
+ CakePlugin::load('TestPlugin');
+
+ $this->db->cacheSources = false;
+ $this->Shell->params = array(
+ 'plugin' => 'TestPlugin',
+ 'connection' => 'test',
+ 'models' => 'TestPluginComment',
+ 'force' => false,
+ 'overwrite' => true
+ );
+ $this->Shell->startup();
+ $this->Shell->Schema->path = TMP . 'tests' . DS;
+
+ $this->Shell->generate();
+ $this->file = new File(TMP . 'tests' . DS . 'schema.php');
+ $contents = $this->file->read();
+
+ $this->assertRegExp('/class TestPluginSchema/', $contents);
+ $this->assertRegExp('/public \$test_plugin_comments/', $contents);
+ $this->assertNotRegExp('/public \$authors/', $contents);
+ $this->assertNotRegExp('/public \$auth_users/', $contents);
+ $this->assertNotRegExp('/public \$posts/', $contents);
+ CakePlugin::unload();
+ }
+
/**
* Test schema run create with no table args.
*
@@ -463,6 +497,35 @@ class SchemaShellTest extends CakeTestCase {
CakePlugin::unload();
}
+/**
+ * test that underscored names also result in CamelCased class names
+ *
+ * @return void
+ */
+ public function testName() {
+ App::build(array(
+ 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
+ ));
+ CakePlugin::load('TestPlugin');
+ $this->Shell->params = array(
+ 'plugin' => 'TestPlugin',
+ 'connection' => 'test',
+ 'name' => 'custom_name',
+ 'force' => false,
+ 'overwrite' => true,
+ );
+ $this->Shell->startup();
+ if (file_exists($this->Shell->Schema->path . DS . 'custom_name.php')) {
+ unlink($this->Shell->Schema->path . DS . 'custom_name.php');
+ }
+ $this->Shell->generate();
+
+ $contents = file_get_contents($this->Shell->Schema->path . DS . 'custom_name.php');
+ $this->assertRegExp('/class CustomNameSchema/', $contents);
+ unlink($this->Shell->Schema->path . DS . 'custom_name.php');
+ CakePlugin::unload();
+ }
+
/**
* test that using Plugin.name with write.
*
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php
index 4d11cbe60..d241ce16f 100644
--- a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php
+++ b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php
@@ -191,9 +191,9 @@ class ControllerTaskTest extends CakeTestCase {
*/
public function testDoHelpersTrailingSpace() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' Javascript, Ajax, CustomOne '));
+ $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' Text, Number, CustomOne '));
$result = $this->Task->doHelpers();
- $expected = array('Javascript', 'Ajax', 'CustomOne');
+ $expected = array('Text', 'Number', 'CustomOne');
$this->assertEquals($expected, $result);
}
@@ -204,9 +204,9 @@ class ControllerTaskTest extends CakeTestCase {
*/
public function testDoHelpersTrailingCommas() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' Javascript, Ajax, CustomOne, , '));
+ $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' Text, Number, CustomOne, , '));
$result = $this->Task->doHelpers();
- $expected = array('Javascript', 'Ajax', 'CustomOne');
+ $expected = array('Text', 'Number', 'CustomOne');
$this->assertEquals($expected, $result);
}
@@ -257,11 +257,11 @@ class ControllerTaskTest extends CakeTestCase {
public function testConfirmController() {
$controller = 'Posts';
$scaffold = false;
- $helpers = array('Ajax', 'Time');
+ $helpers = array('Js', 'Time');
$components = array('Acl', 'Auth');
$this->Task->expects($this->at(4))->method('out')->with("Controller Name:\n\t$controller");
- $this->Task->expects($this->at(5))->method('out')->with("Helpers:\n\tAjax, Time");
+ $this->Task->expects($this->at(5))->method('out')->with("Helpers:\n\tJs, Time");
$this->Task->expects($this->at(6))->method('out')->with("Components:\n\tAcl, Auth");
$this->Task->confirmController($controller, $scaffold, $helpers, $components);
}
@@ -272,7 +272,7 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testBake() {
- $helpers = array('Ajax', 'Time');
+ $helpers = array('Js', 'Time');
$components = array('Acl', 'Auth');
$this->Task->expects($this->any())->method('createFile')->will($this->returnValue(true));
@@ -282,7 +282,7 @@ class ControllerTaskTest extends CakeTestCase {
$this->assertContains(' * @property AuthComponent $Auth', $result);
$this->assertContains('class ArticlesController extends AppController', $result);
$this->assertContains("public \$components = array('Acl', 'Auth')", $result);
- $this->assertContains("public \$helpers = array('Ajax', 'Time')", $result);
+ $this->assertContains("public \$helpers = array('Js', 'Time')", $result);
$this->assertContains("--actions--", $result);
$result = $this->Task->bake('Articles', 'scaffold', $helpers, $components);
@@ -350,7 +350,8 @@ class ControllerTaskTest extends CakeTestCase {
$this->assertContains('function view($id = null)', $result);
$this->assertContains("throw new NotFoundException(__('Invalid bake article'));", $result);
- $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result);
+ $this->assertContains("\$options = array('conditions' => array('BakeArticle.' . \$this->BakeArticle->primaryKey => \$id));", $result);
+ $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->find('first', \$options));", $result);
$this->assertContains('function add()', $result);
$this->assertContains("if (\$this->request->is('post'))", $result);
@@ -389,7 +390,7 @@ class ControllerTaskTest extends CakeTestCase {
$this->assertContains('function view($id = null)', $result);
$this->assertContains("throw new NotFoundException(__('Invalid bake article'));", $result);
- $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result);
+ $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->find('first', \$options));", $result);
$this->assertContains('function add()', $result);
$this->assertContains("if (\$this->request->is('post'))", $result);
@@ -402,6 +403,7 @@ class ControllerTaskTest extends CakeTestCase {
$this->assertContains("\$this->set(compact('bakeTags'))", $result);
$this->assertContains('function delete($id = null)', $result);
+ $this->assertContains("\$this->request->onlyAllow('post', 'delete')", $result);
$this->assertContains('if ($this->BakeArticle->delete())', $result);
$this->assertContains("\$this->flash(__('Bake article deleted'), array('action' => 'index'))", $result);
}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php
index 1f4eb6108..02b6b049f 100644
--- a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php
+++ b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php
@@ -308,10 +308,10 @@ class ExtractTaskTest extends CakeTestCase {
$this->Task->execute();
$result = file_get_contents($this->path . DS . 'default.pot');
- $pattern = preg_quote('#Model' . DS . 'PersisterOne.php:validation for field title#', '\\');
+ $pattern = preg_quote('#Model/PersisterOne.php:validation for field title#', '\\');
$this->assertRegExp($pattern, $result);
- $pattern = preg_quote('#Model' . DS . 'PersisterOne.php:validation for field body#', '\\');
+ $pattern = preg_quote('#Model/PersisterOne.php:validation for field body#', '\\');
$this->assertRegExp($pattern, $result);
$pattern = '#msgid "Post title is required"#';
@@ -354,10 +354,10 @@ class ExtractTaskTest extends CakeTestCase {
$this->Task->execute();
$result = file_get_contents($this->path . DS . 'test_plugin.pot');
- $pattern = preg_quote('#Plugin' . DS . 'TestPlugin' . DS . 'Model' . DS . 'TestPluginPost.php:validation for field title#', '\\');
+ $pattern = preg_quote('#Plugin/TestPlugin/Model/TestPluginPost.php:validation for field title#', '\\');
$this->assertRegExp($pattern, $result);
- $pattern = preg_quote('#Plugin' . DS . 'TestPlugin' . DS . 'Model' . DS . 'TestPluginPost.php:validation for field body#', '\\');
+ $pattern = preg_quote('#Plugin/TestPlugin/Model/TestPluginPost.php:validation for field body#', '\\');
$this->assertRegExp($pattern, $result);
$pattern = '#msgid "Post title is required"#';
@@ -393,10 +393,10 @@ class ExtractTaskTest extends CakeTestCase {
$this->Task->execute();
$result = file_get_contents($this->path . DS . 'test_plugin.pot');
- $pattern = preg_quote('#Model' . DS . 'TestPluginPost.php:validation for field title#', '\\');
+ $pattern = preg_quote('#Model/TestPluginPost.php:validation for field title#', '\\');
$this->assertRegExp($pattern, $result);
- $pattern = preg_quote('#Model' . DS . 'TestPluginPost.php:validation for field body#', '\\');
+ $pattern = preg_quote('#Model/TestPluginPost.php:validation for field body#', '\\');
$this->assertRegExp($pattern, $result);
$pattern = '#msgid "Post title is required"#';
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php
index 2e3c5d9d1..9f7479d29 100644
--- a/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php
+++ b/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php
@@ -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('23', 'y', '17', 'n'));
+ ->will($this->onConsecutiveCalls('24', 'y', '18', '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', '23', 'n'));
+ ->will($this->onConsecutiveCalls('999999', '24', 'n'));
$this->Task->expects($this->at(10))->method('out')
->with($this->stringContains('make a valid'));
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php
index 8fd1b33f0..b9fbe469b 100644
--- a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php
+++ b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php
@@ -249,6 +249,24 @@ class ProjectTaskTest extends CakeTestCase {
$this->assertNotRegExp('/76859309657453542496749683645/', $contents, 'Default CipherSeed left behind. %s');
}
+/**
+ * test generation of cache prefix
+ *
+ * @return void
+ */
+ public function testCachePrefixGeneration() {
+ $this->_setupTestProject();
+
+ $path = $this->Task->path . 'bake_test_app' . DS;
+ $result = $this->Task->cachePrefix($path);
+ $this->assertTrue($result);
+
+ $File = new File($path . 'Config' . DS . 'core.php');
+ $contents = $File->read();
+ $this->assertRegExp('/\$prefix = \'.+\';/', $contents, '$prefix is not defined');
+ $this->assertNotRegExp('/\$prefix = \'myapp_\';/', $contents, 'Default cache prefix left behind. %s');
+ }
+
/**
* Test that index.php is generated correctly.
*
diff --git a/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php
index 7eb5fa8b4..6fad8069e 100644
--- a/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php
+++ b/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php
@@ -694,7 +694,7 @@ class TestTaskTest extends CakeTestCase {
public function testTestCaseFileNamePlugin() {
$this->Task->path = DS . 'my' . DS . 'path' . DS . 'tests' . DS;
- CakePlugin::load('TestTest', array('path' => APP . 'Plugin' . DS . 'TestTest' . DS ));
+ CakePlugin::load('TestTest', array('path' => APP . 'Plugin' . DS . 'TestTest' . DS));
$this->Task->plugin = 'TestTest';
$result = $this->Task->testCaseFileName('Model', 'Post');
$expected = APP . 'Plugin' . DS . 'TestTest' . DS . 'Test' . DS . 'Case' . DS . 'Model' . DS . 'PostTest.php';
diff --git a/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php b/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php
index 92543b396..00f74bcf5 100644
--- a/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php
@@ -118,7 +118,7 @@ class PhpAclTest extends CakeTestCase {
$this->Acl->Aro->addAlias(array('Role/25' => 'Role/IT'));
$this->Acl->allow('Role/IT', '/rules/debugging/*');
- $this->assertEquals(array(array('Role/IT', )), $this->Acl->Aro->roles($user));
+ $this->assertEquals(array(array('Role/IT')), $this->Acl->Aro->roles($user));
$this->assertTrue($this->Acl->check($user, '/rules/debugging/stats/pageload'));
$this->assertTrue($this->Acl->check($user, '/rules/debugging/sql/queries'));
// Role/default is allowed users dashboard, but not Role/IT
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php
new file mode 100644
index 000000000..d36379e89
--- /dev/null
+++ b/lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php
@@ -0,0 +1,209 @@
+Collection = $this->getMock('ComponentCollection');
+ $this->auth = new BlowfishAuthenticate($this->Collection, array(
+ 'fields' => array('username' => 'user', 'password' => 'password'),
+ 'userModel' => 'User'
+ ));
+ $password = Security::hash('password', 'blowfish');
+ $User = ClassRegistry::init('User');
+ $User->updateAll(array('password' => $User->getDataSource()->value($password)));
+ $this->response = $this->getMock('CakeResponse');
+
+ $hash = Security::hash('password', 'blowfish');
+ $this->skipIf(strpos($hash, '$2a$') === false, 'Skipping blowfish tests as hashing is not working');
+ }
+
+/**
+ * test applying settings in the constructor
+ *
+ * @return void
+ */
+ public function testConstructor() {
+ $Object = new BlowfishAuthenticate($this->Collection, array(
+ 'userModel' => 'AuthUser',
+ 'fields' => array('username' => 'user', 'password' => 'password')
+ ));
+ $this->assertEquals('AuthUser', $Object->settings['userModel']);
+ $this->assertEquals(array('username' => 'user', 'password' => 'password'), $Object->settings['fields']);
+ }
+
+/**
+ * testAuthenticateNoData method
+ *
+ * @return void
+ */
+ public function testAuthenticateNoData() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array();
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateNoUsername method
+ *
+ * @return void
+ */
+ public function testAuthenticateNoUsername() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array('password' => 'foobar'));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateNoPassword method
+ *
+ * @return void
+ */
+ public function testAuthenticateNoPassword() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array('user' => 'mariano'));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticatePasswordIsFalse method
+ *
+ * @return void
+ */
+ public function testAuthenticatePasswordIsFalse() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array(
+ 'User' => array(
+ 'user' => 'mariano',
+ 'password' => null
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateInjection method
+ *
+ * @return void
+ */
+ public function testAuthenticateInjection() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array(
+ 'user' => '> 1',
+ 'password' => "' OR 1 = 1"
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateSuccess method
+ *
+ * @return void
+ */
+ public function testAuthenticateSuccess() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array(
+ 'user' => 'mariano',
+ 'password' => 'password'
+ ));
+ $result = $this->auth->authenticate($request, $this->response);
+ $expected = array(
+ 'id' => 1,
+ 'user' => 'mariano',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31',
+ );
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testAuthenticateScopeFail method
+ *
+ * @return void
+ */
+ public function testAuthenticateScopeFail() {
+ $this->auth->settings['scope'] = array('user' => 'nate');
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array(
+ 'user' => 'mariano',
+ 'password' => 'password'
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testPluginModel method
+ *
+ * @return void
+ */
+ public function testPluginModel() {
+ Cache::delete('object_map', '_cake_core_');
+ App::build(array(
+ 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
+ ), App::RESET);
+ CakePlugin::load('TestPlugin');
+
+ $PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser');
+ $user['id'] = 1;
+ $user['username'] = 'gwoo';
+ $user['password'] = Security::hash('password', 'blowfish');
+ $PluginModel->save($user, false);
+
+ $this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser';
+ $this->auth->settings['fields']['username'] = 'username';
+
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('TestPluginAuthUser' => array(
+ 'username' => 'gwoo',
+ 'password' => 'password'
+ ));
+
+ $result = $this->auth->authenticate($request, $this->response);
+ $expected = array(
+ 'id' => 1,
+ 'username' => 'gwoo',
+ 'created' => '2007-03-17 01:16:23'
+ );
+ $this->assertEquals(self::date(), $result['updated']);
+ unset($result['updated']);
+ $this->assertEquals($expected, $result);
+ CakePlugin::unload();
+ }
+}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
index a65e04f28..4d2470a3b 100644
--- a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
@@ -99,6 +99,21 @@ class FormAuthenticateTest extends CakeTestCase {
$this->assertFalse($this->auth->authenticate($request, $this->response));
}
+/**
+ * test authenticate password is false method
+ *
+ * @return void
+ */
+ public function testAuthenticatePasswordIsFalse() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array(
+ 'User' => array(
+ 'user' => 'mariano',
+ 'password' => null
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
/**
* test the authenticate method
*
diff --git a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php
index 59c1aa6c6..d55c62c35 100644
--- a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php
@@ -907,6 +907,30 @@ class AuthComponentTest extends CakeTestCase {
$this->Auth->startup($Controller);
}
+/**
+ * Throw ForbiddenException if AuthComponent::$unauthorizedRedirect set to false
+ * @expectedException ForbiddenException
+ * @return void
+ */
+ public function testForbiddenException() {
+ $url = '/party/on';
+ $this->Auth->request = $CakeRequest = new CakeRequest($url);
+ $this->Auth->request->addParams(Router::parse($url));
+ $this->Auth->authorize = array('Controller');
+ $this->Auth->authorize = array('Controller');
+ $this->Auth->unauthorizedRedirect = false;
+ $this->Auth->login(array('username' => 'baker', 'password' => 'cake'));
+
+ $CakeResponse = new CakeResponse();
+ $Controller = $this->getMock(
+ 'Controller',
+ array('on', 'redirect'),
+ array($CakeRequest, $CakeResponse)
+ );
+
+ $this->Auth->startup($Controller);
+ }
+
/**
* Test that no redirects or authorization tests occur on the loginAction
*
diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php
index 7c4be8972..67e0e397f 100644
--- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php
@@ -538,6 +538,60 @@ class CookieComponentTest extends CakeTestCase {
$this->assertNull($this->Cookie->read('value'));
}
+/**
+ * testCheck method
+ *
+ * @return void
+ */
+ public function testCheck() {
+ $this->Cookie->write('CookieComponentTestCase', 'value');
+ $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
+
+ $this->assertFalse($this->Cookie->check('NotExistingCookieComponentTestCase'));
+ }
+
+/**
+ * testCheckingSavedEmpty method
+ *
+ * @return void
+ */
+ public function testCheckingSavedEmpty() {
+ $this->Cookie->write('CookieComponentTestCase', 0);
+ $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
+
+ $this->Cookie->write('CookieComponentTestCase', '0');
+ $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
+
+ $this->Cookie->write('CookieComponentTestCase', false);
+ $this->assertTrue($this->Cookie->check('CookieComponentTestCase'));
+
+ $this->Cookie->write('CookieComponentTestCase', null);
+ $this->assertFalse($this->Cookie->check('CookieComponentTestCase'));
+ }
+
+/**
+ * testCheckKeyWithSpaces method
+ *
+ * @return void
+ */
+ public function testCheckKeyWithSpaces() {
+ $this->Cookie->write('CookieComponent Test', "test");
+ $this->assertTrue($this->Cookie->check('CookieComponent Test'));
+ $this->Cookie->delete('CookieComponent Test');
+
+ $this->Cookie->write('CookieComponent Test.Test Case', "test");
+ $this->assertTrue($this->Cookie->check('CookieComponent Test.Test Case'));
+ }
+
+/**
+ * testCheckEmpty
+ *
+ * @return void
+ */
+ public function testCheckEmpty() {
+ $this->assertFalse($this->Cookie->check());
+ }
+
/**
* test that deleting a top level keys kills the child elements too.
*
diff --git a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php
index 1908e926e..a32b8f69b 100644
--- a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php
@@ -353,12 +353,18 @@ class PaginatorComponentTest extends CakeTestCase {
$Controller->request->query = array();
$Controller->constructClasses();
- $results = Hash::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(array(1, 2, 3), $results);
-
+ $Controller->Paginator->settings = array(
+ 'order' => array('PaginatorControllerComment.id' => 'ASC')
+ );
$results = Hash::extract($Controller->Paginator->paginate('PaginatorControllerComment'), '{n}.PaginatorControllerComment.id');
$this->assertEquals(array(1, 2, 3, 4, 5, 6), $results);
+ $Controller->Paginator->settings = array(
+ 'order' => array('PaginatorControllerPost.id' => 'ASC')
+ );
+ $results = Hash::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
+ $this->assertEquals(array(1, 2, 3), $results);
+
$Controller->modelClass = null;
$Controller->uses[0] = 'Plugin.PaginatorControllerPost';
@@ -473,6 +479,9 @@ class PaginatorComponentTest extends CakeTestCase {
$Controller->constructClasses();
$Controller->request->params['named'] = array('page' => '-1', 'contain' => array('PaginatorControllerComment'));
+ $Controller->Paginator->settings = array(
+ 'order' => array('PaginatorControllerPost.id' => 'ASC')
+ );
$result = $Controller->Paginator->paginate('PaginatorControllerPost');
$this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
$this->assertEquals(array(1, 2, 3), Hash::extract($result, '{n}.PaginatorControllerPost.id'));
@@ -483,7 +492,8 @@ class PaginatorComponentTest extends CakeTestCase {
'PaginatorControllerPost' => array(
'contain' => array('PaginatorControllerComment'),
'maxLimit' => 10,
- 'paramType' => 'named'
+ 'paramType' => 'named',
+ 'order' => array('PaginatorControllerPost.id' => 'ASC')
),
);
$result = $Controller->Paginator->paginate('PaginatorControllerPost');
@@ -710,6 +720,28 @@ class PaginatorComponentTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * test mergeOptions with customFind key
+ *
+ * @return void
+ */
+ public function testMergeOptionsCustomFindKey() {
+ $this->request->params['named'] = array(
+ 'page' => 10,
+ 'limit' => 10
+ );
+ $this->Paginator->settings = array(
+ 'page' => 1,
+ 'limit' => 20,
+ 'maxLimit' => 100,
+ 'paramType' => 'named',
+ 'findType' => 'myCustomFind'
+ );
+ $result = $this->Paginator->mergeOptions('Post');
+ $expected = array('page' => 10, 'limit' => 10, 'maxLimit' => 100, 'paramType' => 'named', 'findType' => 'myCustomFind');
+ $this->assertEquals($expected, $result);
+ }
+
/**
* test merging options from the querystring.
*
@@ -1012,7 +1044,7 @@ class PaginatorComponentTest extends CakeTestCase {
* @return void
*/
public function testPaginateCustomFind() {
- $Controller =& new Controller($this->request);
+ $Controller = new Controller($this->request);
$Controller->uses = array('PaginatorCustomPost');
$Controller->constructClasses();
$data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
@@ -1052,7 +1084,7 @@ class PaginatorComponentTest extends CakeTestCase {
* @return void
*/
public function testPaginateCustomFindFieldsArray() {
- $Controller =& new Controller($this->request);
+ $Controller = new Controller($this->request);
$Controller->uses = array('PaginatorCustomPost');
$Controller->constructClasses();
$data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
@@ -1078,6 +1110,38 @@ class PaginatorComponentTest extends CakeTestCase {
$this->assertTrue($result['nextPage']);
$this->assertFalse($result['prevPage']);
}
+/**
+ * test paginate() and custom find with customFind key, to make sure the correct count is returned.
+ *
+ * @return void
+ */
+ public function testPaginateCustomFindWithCustomFindKey() {
+ $Controller = new Controller($this->request);
+ $Controller->uses = array('PaginatorCustomPost');
+ $Controller->constructClasses();
+ $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
+ $Controller->PaginatorCustomPost->create($data);
+ $result = $Controller->PaginatorCustomPost->save();
+ $this->assertTrue(!empty($result));
+
+ $Controller->paginate = array(
+ 'conditions' => array('PaginatorCustomPost.published' => 'Y'),
+ 'findType' => 'list',
+ 'limit' => 2
+ );
+ $result = $Controller->paginate();
+ $expected = array(
+ 1 => 'First Post',
+ 2 => 'Second Post',
+ );
+ $this->assertEquals($expected, $result);
+ $result = $Controller->params['paging']['PaginatorCustomPost'];
+ $this->assertEquals(2, $result['current']);
+ $this->assertEquals(3, $result['count']);
+ $this->assertEquals(2, $result['pageCount']);
+ $this->assertTrue($result['nextPage']);
+ $this->assertFalse($result['prevPage']);
+ }
/**
* test paginate() and custom find with fields array, to make sure the correct count is returned.
@@ -1085,7 +1149,7 @@ class PaginatorComponentTest extends CakeTestCase {
* @return void
*/
public function testPaginateCustomFindGroupBy() {
- $Controller =& new Controller($this->request);
+ $Controller = new Controller($this->request);
$Controller->uses = array('PaginatorCustomPost');
$Controller->constructClasses();
$data = array('author_id' => 2, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
@@ -1150,7 +1214,7 @@ class PaginatorComponentTest extends CakeTestCase {
* @return void
*/
public function testPaginateCustomFindCount() {
- $Controller =& new Controller($this->request);
+ $Controller = new Controller($this->request);
$Controller->uses = array('PaginatorCustomPost');
$Controller->constructClasses();
$data = array('author_id' => 2, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php
index fb6c431e6..ca29f63b5 100644
--- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php
@@ -21,6 +21,7 @@ App::uses('RequestHandlerComponent', 'Controller/Component');
App::uses('CakeRequest', 'Network');
App::uses('CakeResponse', 'Network');
App::uses('Router', 'Routing');
+App::uses('JsonView', 'View');
/**
* RequestHandlerTestController class
@@ -70,6 +71,14 @@ class RequestHandlerTestController extends Controller {
}
+/**
+ * CustomJsonView class
+ *
+ * @package Cake.Test.Case.Controller.Component
+ */
+class CustomJsonView extends JsonView {
+
+}
/**
* RequestHandlerComponentTest class
@@ -137,12 +146,14 @@ class RequestHandlerComponentTest extends CakeTestCase {
*/
public function testConstructorSettings() {
$settings = array(
- 'ajaxLayout' => 'test_ajax'
+ 'ajaxLayout' => 'test_ajax',
+ 'viewClassMap' => array('json' => 'MyPlugin.MyJson')
);
$Collection = new ComponentCollection();
$Collection->init($this->Controller);
$RequestHandler = new RequestHandlerComponent($Collection, $settings);
$this->assertEquals('test_ajax', $RequestHandler->ajaxLayout);
+ $this->assertEquals(array('json' => 'MyPlugin.MyJson'), $RequestHandler->settings['viewClassMap']);
}
/**
@@ -178,7 +189,7 @@ class RequestHandlerComponentTest extends CakeTestCase {
* @return void
*/
public function testInitializeContentTypeWithjQueryAccept() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01';
+ $_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, */*; q=0.01';
$this->assertNull($this->RequestHandler->ext);
Router::parseExtensions('json');
@@ -193,7 +204,7 @@ class RequestHandlerComponentTest extends CakeTestCase {
* @return void
*/
public function testInitializeContentTypeWithjQueryAcceptAndMultiplesExtensions() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01';
+ $_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, */*; q=0.01';
$this->assertNull($this->RequestHandler->ext);
Router::parseExtensions('rss', 'json');
@@ -221,7 +232,7 @@ class RequestHandlerComponentTest extends CakeTestCase {
* @return void
*/
public function testInitializeNoContentTypeWithMultipleAcceptedTypes() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, application/xml, */*; q=0.01';
+ $_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, application/xml, */*; q=0.01';
$this->assertNull($this->RequestHandler->ext);
Router::parseExtensions('xml', 'json');
@@ -264,6 +275,33 @@ class RequestHandlerComponentTest extends CakeTestCase {
call_user_func_array(array('Router', 'parseExtensions'), $extensions);
}
+/**
+ * testViewClassMap method
+ *
+ * @return void
+ */
+ public function testViewClassMap() {
+ $this->RequestHandler->settings = array('viewClassMap' => array('json' => 'CustomJson'));
+ $this->RequestHandler->initialize($this->Controller);
+ $result = $this->RequestHandler->viewClassMap();
+ $expected = array(
+ 'json' => 'CustomJson',
+ 'xml' => 'Xml'
+ );
+ $this->assertEquals($expected, $result);
+
+ $result = $this->RequestHandler->viewClassMap('xls', 'Excel.Excel');
+ $expected = array(
+ 'json' => 'CustomJson',
+ 'xml' => 'Xml',
+ 'xls' => 'Excel.Excel'
+ );
+ $this->assertEquals($expected, $result);
+
+ $this->RequestHandler->renderAs($this->Controller, 'json');
+ $this->assertEquals('CustomJson', $this->Controller->viewClass);
+ }
+
/**
* testDisabling method
*
@@ -630,7 +668,7 @@ class RequestHandlerComponentTest extends CakeTestCase {
$this->assertEquals('text/vnd.wap.wml', $result);
$result = $this->RequestHandler->mapAlias(array('xml', 'js', 'json'));
- $expected = array('application/xml', 'text/javascript', 'application/json');
+ $expected = array('application/xml', 'application/javascript', 'application/json');
$this->assertEquals($expected, $result);
}
diff --git a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
index 84f78036b..fb92b8614 100644
--- a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
@@ -1372,4 +1372,18 @@ class SecurityComponentTest extends CakeTestCase {
$this->assertTrue(isset($result['4']));
$this->assertTrue(isset($result['5']));
}
+
+/**
+ * Test unlocked actions
+ *
+ * @return void
+ */
+ public function testUnlockedActions() {
+ $_SERVER['REQUEST_METHOD'] = 'POST';
+ $this->Controller->request->data = array('data');
+ $this->Controller->Security->unlockedActions = 'index';
+ $this->Controller->Security->blackHoleCallback = null;
+ $result = $this->Controller->Security->startup($this->Controller);
+ $this->assertNull($result);
+ }
}
diff --git a/lib/Cake/Test/Case/Core/AppTest.php b/lib/Cake/Test/Case/Core/AppTest.php
index 0c66766cd..3ca29b3a1 100644
--- a/lib/Cake/Test/Case/Core/AppTest.php
+++ b/lib/Cake/Test/Case/Core/AppTest.php
@@ -749,7 +749,7 @@ class AppTest extends CakeTestCase {
$result = App::import('Vendor', 'css/TestAsset', array('ext' => 'css'));
$text = ob_get_clean();
$this->assertTrue($result);
- $this->assertEquals('this is the test asset css file', $text);
+ $this->assertEquals('/* this is the test asset css file */', trim($text));
$result = App::import('Vendor', 'TestPlugin.sample/SamplePlugin');
$this->assertTrue($result);
@@ -808,7 +808,7 @@ class AppTest extends CakeTestCase {
$this->assertFalse(class_exists('TestUtilityClass', false));
App::uses('TestUtilityClass', 'Utility');
- $this->assertTrue(class_exists('CustomLibClass'));
+ $this->assertTrue(class_exists('TestUtilityClass'));
}
/**
diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php
index 7351f83f1..5dd1fe0b6 100644
--- a/lib/Cake/Test/Case/Core/ConfigureTest.php
+++ b/lib/Cake/Test/Case/Core/ConfigureTest.php
@@ -177,6 +177,60 @@ class ConfigureTest extends CakeTestCase {
$this->assertTrue($result === null);
}
+/**
+ * testCheck method
+ *
+ * @return void
+ */
+ public function testCheck() {
+ Configure::write('ConfigureTestCase', 'value');
+ $this->assertTrue(Configure::check('ConfigureTestCase'));
+
+ $this->assertFalse(Configure::check('NotExistingConfigureTestCase'));
+ }
+
+/**
+ * testCheckingSavedEmpty method
+ *
+ * @return void
+ */
+ public function testCheckingSavedEmpty() {
+ $this->assertTrue(Configure::write('ConfigureTestCase', 0));
+ $this->assertTrue(Configure::check('ConfigureTestCase'));
+
+ $this->assertTrue(Configure::write('ConfigureTestCase', '0'));
+ $this->assertTrue(Configure::check('ConfigureTestCase'));
+
+ $this->assertTrue(Configure::write('ConfigureTestCase', false));
+ $this->assertTrue(Configure::check('ConfigureTestCase'));
+
+ $this->assertTrue(Configure::write('ConfigureTestCase', null));
+ $this->assertFalse(Configure::check('ConfigureTestCase'));
+ }
+
+/**
+ * testCheckKeyWithSpaces method
+ *
+ * @return void
+ */
+ public function testCheckKeyWithSpaces() {
+ $this->assertTrue(Configure::write('Configure Test', "test"));
+ $this->assertTrue(Configure::check('Configure Test'));
+ Configure::delete('Configure Test');
+
+ $this->assertTrue(Configure::write('Configure Test.Test Case', "test"));
+ $this->assertTrue(Configure::check('Configure Test.Test Case'));
+ }
+
+/**
+ * testCheckEmpty
+ *
+ * @return void
+ */
+ public function testCheckEmpty() {
+ $this->assertFalse(Configure::check());
+ }
+
/**
* testLoad method
*
diff --git a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php
index d11c66413..253e7536a 100644
--- a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php
+++ b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php
@@ -479,6 +479,27 @@ class ExceptionRendererTest extends CakeTestCase {
$this->assertRegExp('/An Internal Error Has Occurred<\/h2>/', $result);
}
+/**
+ * testExceptionResponseHeader method
+ *
+ * @return void
+ */
+ public function testExceptionResponseHeader() {
+ $exception = new MethodNotAllowedException('Only allowing POST and DELETE');
+ $exception->responseHeader(array('Allow: POST, DELETE'));
+ $ExceptionRenderer = new ExceptionRenderer($exception);
+
+ //Replace response object with mocked object add back the original headers which had been set in ExceptionRenderer constructor
+ $headers = $ExceptionRenderer->controller->response->header();
+ $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
+ $ExceptionRenderer->controller->response->header($headers);
+
+ $ExceptionRenderer->controller->response->expects($this->at(1))->method('_sendHeader')->with('Allow', 'POST, DELETE');
+ ob_start();
+ $ExceptionRenderer->render();
+ $result = ob_get_clean();
+ }
+
/**
* testMissingController method
*
@@ -792,7 +813,7 @@ class ExceptionRendererTest extends CakeTestCase {
$this->assertContains('Database Error
', $result);
$this->assertContains('There was an error in the SQL query', $result);
- $this->assertContains('SELECT * from poo_query < 5 and :seven', $result);
+ $this->assertContains(h('SELECT * from poo_query < 5 and :seven'), $result);
$this->assertContains("'seven' => (int) 7", $result);
}
}
diff --git a/lib/Cake/Test/Case/I18n/I18nTest.php b/lib/Cake/Test/Case/I18n/I18nTest.php
index 637494012..a6a65533f 100644
--- a/lib/Cake/Test/Case/I18n/I18nTest.php
+++ b/lib/Cake/Test/Case/I18n/I18nTest.php
@@ -1893,7 +1893,7 @@ class I18nTest extends CakeTestCase {
private function __domainPlural($domain = 'test_plugin') {
$plurals = array();
for ($number = 0; $number <= 25; $number++) {
- $plurals[] = sprintf(__dn($domain, '%d = 1', '%d = 0 or > 1', (float)$number), (float)$number );
+ $plurals[] = sprintf(__dn($domain, '%d = 1', '%d = 0 or > 1', (float)$number), (float)$number);
}
return $plurals;
}
@@ -1949,7 +1949,7 @@ class I18nTest extends CakeTestCase {
private function __pluralFromCore() {
$plurals = array();
for ($number = 0; $number <= 25; $number++) {
- $plurals[] = sprintf(__n('%d = 1 (from core)', '%d = 0 or > 1 (from core)', (float)$number), (float)$number );
+ $plurals[] = sprintf(__n('%d = 1 (from core)', '%d = 0 or > 1 (from core)', (float)$number), (float)$number);
}
return $plurals;
}
diff --git a/lib/Cake/Test/Case/I18n/L10nTest.php b/lib/Cake/Test/Case/I18n/L10nTest.php
index d52c3a60d..a80c270a9 100644
--- a/lib/Cake/Test/Case/I18n/L10nTest.php
+++ b/lib/Cake/Test/Case/I18n/L10nTest.php
@@ -125,8 +125,12 @@ class L10nTest extends CakeTestCase {
$expected = array('afr' => 'af', 'af' => 'afr');
$this->assertEquals($expected, $result);
+ $result = $localize->map(array('sqi', 'sq'));
+ $expected = array('sqi' => 'sq', 'sq' => 'sqi');
+ $this->assertEquals($expected, $result);
+
$result = $localize->map(array('alb', 'sq'));
- $expected = array('alb' => 'sq', 'sq' => 'alb');
+ $expected = array('alb' => 'sq', 'sq' => 'sqi');
$this->assertEquals($expected, $result);
$result = $localize->map(array('ara', 'ar'));
@@ -137,12 +141,12 @@ class L10nTest extends CakeTestCase {
$expected = array('hye' => 'hy', 'hy' => 'hye');
$this->assertEquals($expected, $result);
- $result = $localize->map(array('baq', 'eu'));
- $expected = array('baq' => 'eu', 'eu' => 'baq');
+ $result = $localize->map(array('eus', 'eu'));
+ $expected = array('eus' => 'eu', 'eu' => 'eus');
$this->assertEquals($expected, $result);
$result = $localize->map(array('baq', 'eu'));
- $expected = array('baq' => 'eu', 'eu' => 'baq');
+ $expected = array('baq' => 'eu', 'eu' => 'eus');
$this->assertEquals($expected, $result);
$result = $localize->map(array('bos', 'bs'));
@@ -162,11 +166,11 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('chi', 'zh'));
- $expected = array('chi' => 'zh', 'zh' => 'chi');
+ $expected = array('chi' => 'zh', 'zh' => 'zho');
$this->assertEquals($expected, $result);
$result = $localize->map(array('zho', 'zh'));
- $expected = array('zho' => 'zh', 'zh' => 'chi');
+ $expected = array('zho' => 'zh', 'zh' => 'zho');
$this->assertEquals($expected, $result);
$result = $localize->map(array('hrv', 'hr'));
@@ -174,11 +178,11 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('ces', 'cs'));
- $expected = array('ces' => 'cs', 'cs' => 'cze');
+ $expected = array('ces' => 'cs', 'cs' => 'ces');
$this->assertEquals($expected, $result);
$result = $localize->map(array('cze', 'cs'));
- $expected = array('cze' => 'cs', 'cs' => 'cze');
+ $expected = array('cze' => 'cs', 'cs' => 'ces');
$this->assertEquals($expected, $result);
$result = $localize->map(array('dan', 'da'));
@@ -186,17 +190,21 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('dut', 'nl'));
- $expected = array('dut' => 'nl', 'nl' => 'dut');
+ $expected = array('dut' => 'nl', 'nl' => 'nld');
$this->assertEquals($expected, $result);
$result = $localize->map(array('nld', 'nl'));
- $expected = array('nld' => 'nl', 'nl' => 'dut');
+ $expected = array('nld' => 'nl', 'nl' => 'nld');
$this->assertEquals($expected, $result);
$result = $localize->map(array('nld'));
$expected = array('nld' => 'nl');
$this->assertEquals($expected, $result);
+ $result = $localize->map(array('dut'));
+ $expected = array('dut' => 'nl');
+ $this->assertEquals($expected, $result);
+
$result = $localize->map(array('eng', 'en'));
$expected = array('eng' => 'en', 'en' => 'eng');
$this->assertEquals($expected, $result);
@@ -222,11 +230,11 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('fra', 'fr'));
- $expected = array('fra' => 'fr', 'fr' => 'fre');
+ $expected = array('fra' => 'fr', 'fr' => 'fra');
$this->assertEquals($expected, $result);
$result = $localize->map(array('fre', 'fr'));
- $expected = array('fre' => 'fr', 'fr' => 'fre');
+ $expected = array('fre' => 'fr', 'fr' => 'fra');
$this->assertEquals($expected, $result);
$result = $localize->map(array('gla', 'gd'));
@@ -266,11 +274,11 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('ice', 'is'));
- $expected = array('ice' => 'is', 'is' => 'ice');
+ $expected = array('ice' => 'is', 'is' => 'isl');
$this->assertEquals($expected, $result);
$result = $localize->map(array('isl', 'is'));
- $expected = array('isl' => 'is', 'is' => 'ice');
+ $expected = array('isl' => 'is', 'is' => 'isl');
$this->assertEquals($expected, $result);
$result = $localize->map(array('ind', 'id'));
@@ -302,19 +310,19 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('mac', 'mk'));
- $expected = array('mac' => 'mk', 'mk' => 'mac');
+ $expected = array('mac' => 'mk', 'mk' => 'mkd');
$this->assertEquals($expected, $result);
$result = $localize->map(array('mkd', 'mk'));
- $expected = array('mkd' => 'mk', 'mk' => 'mac');
+ $expected = array('mkd' => 'mk', 'mk' => 'mkd');
$this->assertEquals($expected, $result);
$result = $localize->map(array('may', 'ms'));
- $expected = array('may' => 'ms', 'ms' => 'may');
+ $expected = array('may' => 'ms', 'ms' => 'msa');
$this->assertEquals($expected, $result);
$result = $localize->map(array('msa', 'ms'));
- $expected = array('msa' => 'ms', 'ms' => 'may');
+ $expected = array('msa' => 'ms', 'ms' => 'msa');
$this->assertEquals($expected, $result);
$result = $localize->map(array('mlt', 'mt'));
@@ -346,11 +354,11 @@ class L10nTest extends CakeTestCase {
$this->assertEquals($expected, $result);
$result = $localize->map(array('ron', 'ro'));
- $expected = array('ron' => 'ro', 'ro' => 'rum');
+ $expected = array('ron' => 'ro', 'ro' => 'ron');
$this->assertEquals($expected, $result);
$result = $localize->map(array('rum', 'ro'));
- $expected = array('rum' => 'ro', 'ro' => 'rum');
+ $expected = array('rum' => 'ro', 'ro' => 'ron');
$this->assertEquals($expected, $result);
$result = $localize->map(array('rus', 'ru'));
@@ -361,20 +369,16 @@ class L10nTest extends CakeTestCase {
$expected = array('smi' => 'sz', 'sz' => 'smi');
$this->assertEquals($expected, $result);
- $result = $localize->map(array('scc', 'sr'));
- $expected = array('scc' => 'sr', 'sr' => 'scc');
- $this->assertEquals($expected, $result);
-
$result = $localize->map(array('srp', 'sr'));
- $expected = array('srp' => 'sr', 'sr' => 'scc');
+ $expected = array('srp' => 'sr', 'sr' => 'srp');
$this->assertEquals($expected, $result);
$result = $localize->map(array('slk', 'sk'));
- $expected = array('slk' => 'sk', 'sk' => 'slo');
+ $expected = array('slk' => 'sk', 'sk' => 'slk');
$this->assertEquals($expected, $result);
$result = $localize->map(array('slo', 'sk'));
- $expected = array('slo' => 'sk', 'sk' => 'slo');
+ $expected = array('slo' => 'sk', 'sk' => 'slk');
$this->assertEquals($expected, $result);
$result = $localize->map(array('slv', 'sl'));
@@ -505,7 +509,7 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('cs'));
$expected = array(
- 'cs' => array('language' => 'Czech', 'locale' => 'cze', 'localeFallback' => 'cze', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'cs' => array('language' => 'Czech', 'locale' => 'ces', 'localeFallback' => 'ces', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -583,7 +587,7 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('eu'));
$expected = array(
- 'eu' => array('language' => 'Basque', 'locale' => 'baq', 'localeFallback' => 'baq', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'eu' => array('language' => 'Basque', 'locale' => 'eus', 'localeFallback' => 'eus', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -607,12 +611,12 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('fr', 'fr-be', 'fr-ca', 'fr-ch', 'fr-fr', 'fr-lu'));
$expected = array(
- 'fr' => array('language' => 'French (Standard)', 'locale' => 'fre', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'fr' => array('language' => 'French (Standard)', 'locale' => 'fra', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fra', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -674,7 +678,7 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('is'));
$expected = array(
- 'is' => array('language' => 'Icelandic', 'locale' => 'ice', 'localeFallback' => 'ice', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -721,14 +725,14 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('mk', 'mk-mk'));
$expected = array(
- 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
$result = $localize->catalog(array('ms'));
$expected = array(
- 'ms' => array('language' => 'Malaysian', 'locale' => 'may', 'localeFallback' => 'may', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'ms' => array('language' => 'Malaysian', 'locale' => 'msa', 'localeFallback' => 'msa', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -740,22 +744,22 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('n', 'nl', 'nl-be'));
$expected = array(
- 'n' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'n' => array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
$result = $localize->catalog('nl');
- $expected = array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr');
+ $expected = array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr');
$this->assertEquals($expected, $result);
$result = $localize->catalog('nld');
- $expected = array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr');
+ $expected = array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr');
$this->assertEquals($expected, $result);
$result = $localize->catalog('dut');
- $expected = array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr');
+ $expected = array('language' => 'Dutch (Standard)', 'locale' => 'nld', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr');
$this->assertEquals($expected, $result);
$result = $localize->catalog(array('nb'));
@@ -793,8 +797,8 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('ro', 'ro-mo'));
$expected = array(
- 'ro' => array('language' => 'Romanian', 'locale' => 'rum', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'ro' => array('language' => 'Romanian', 'locale' => 'ron', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -806,7 +810,7 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('sk'));
$expected = array(
- 'sk' => array('language' => 'Slovak', 'locale' => 'slo', 'localeFallback' => 'slo', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'sk' => array('language' => 'Slovak', 'locale' => 'slk', 'localeFallback' => 'slk', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -818,13 +822,13 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('sq'));
$expected = array(
- 'sq' => array('language' => 'Albanian', 'locale' => 'alb', 'localeFallback' => 'alb', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'sq' => array('language' => 'Albanian', 'locale' => 'sqi', 'localeFallback' => 'sqi', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
$result = $localize->catalog(array('sr'));
$expected = array(
- 'sr' => array('language' => 'Serbian', 'locale' => 'scc', 'localeFallback' => 'scc', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'sr' => array('language' => 'Serbian', 'locale' => 'srp', 'localeFallback' => 'srp', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -916,11 +920,11 @@ class L10nTest extends CakeTestCase {
$result = $localize->catalog(array('zh', 'zh-cn', 'zh-hk', 'zh-sg', 'zh-tw'));
$expected = array(
- 'zh' => array('language' => 'Chinese', 'locale' => 'chi', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'chi', 'charset' => 'GB2312', 'direction' => 'ltr'),
- 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr')
+ 'zh' => array('language' => 'Chinese', 'locale' => 'zho', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'zho', 'charset' => 'GB2312', 'direction' => 'ltr'),
+ 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -936,7 +940,7 @@ class L10nTest extends CakeTestCase {
'es-do' => array('language' => 'Spanish (Dominican Republic)', 'locale' => 'es_do', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
'sz' => array('language' => 'Sami (Lappish)', 'locale' => 'smi', 'localeFallback' => 'smi', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ar-lb' => array('language' => 'Arabic (Lebanon)', 'locale' => 'ar_lb', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
'pt-br' => array('language' => 'Portuguese (Brazil)', 'locale' => 'pt_br', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr')
);
$this->assertEquals($expected, $result);
@@ -945,8 +949,8 @@ class L10nTest extends CakeTestCase {
$expected = array(
'eng' => array('language' => 'English', 'locale' => 'eng', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
'deu' => array('language' => 'German (Standard)', 'locale' => 'deu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zho' => array('language' => 'Chinese', 'locale' => 'chi', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'rum' => array('language' => 'Romanian', 'locale' => 'rum', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'zho' => array('language' => 'Chinese', 'locale' => 'zho', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
+ 'rum' => array('language' => 'Romanian', 'locale' => 'ron', 'localeFallback' => 'ron', 'charset' => 'utf-8', 'direction' => 'ltr'),
'zul' => array('language' => 'Zulu', 'locale' => 'zul', 'localeFallback' => 'zul', 'charset' => 'utf-8', 'direction' => 'ltr'),
'yid' => array('language' => 'Yiddish', 'locale' => 'yid', 'localeFallback' => 'yid', 'charset' => 'utf-8', 'direction' => 'ltr')
);
diff --git a/lib/Cake/Test/Case/Log/CakeLogTest.php b/lib/Cake/Test/Case/Log/CakeLogTest.php
index 1226dde7e..2f3e3d3dd 100644
--- a/lib/Cake/Test/Case/Log/CakeLogTest.php
+++ b/lib/Cake/Test/Case/Log/CakeLogTest.php
@@ -383,6 +383,11 @@ class CakeLogTest extends CakeTestCase {
CakeLog::drop('shops');
}
+/**
+ * Test that scopes are exclusive and don't bleed.
+ *
+ * @return void
+ */
public function testScopedLoggingExclusive() {
$this->_deleteLogs();
diff --git a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php
index d84f07e67..be60e0954 100644
--- a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php
+++ b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php
@@ -261,6 +261,30 @@ class ContainableBehaviorTest extends CakeTestCase {
$this->assertFalse(Set::matches('/Comment/User', $r));
}
+/**
+ * testContainFindList method
+ *
+ * @return void
+ */
+ public function testContainFindList() {
+ $this->Article->contain('Comment.User');
+ $result = $this->Article->find('list');
+ $expected = array(
+ 1 => 'First Article',
+ 2 => 'Second Article',
+ 3 => 'Third Article'
+ );
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Article->find('list', array('fields' => array('Article.id', 'User.id'), 'contain' => array('User')));
+ $expected = array(
+ 1 => '1',
+ 2 => '3',
+ 3 => '1'
+ );
+ $this->assertEquals($expected, $result);
+ }
+
/**
* Test that mixing contain() and the contain find option.
*
diff --git a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php
index 50d897d60..7dd762afb 100644
--- a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php
+++ b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php
@@ -590,6 +590,76 @@ class TranslateBehaviorTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * Test that all fields are create with partial data + multiple locales.
+ *
+ * @return void
+ */
+ public function testSavePartialFieldMultipleLocales() {
+ $this->loadFixtures('Translate', 'TranslatedItem');
+
+ $TestModel = new TranslatedItem();
+ $TestModel->locale = 'eng';
+ $data = array(
+ 'slug' => 'fifth_translated',
+ 'title' => array('eng' => 'Title #5', 'spa' => 'Leyenda #5'),
+ );
+ $TestModel->create($data);
+ $TestModel->save();
+ $TestModel->unbindTranslation();
+
+ $translations = array('title' => 'Title', 'content' => 'Content');
+ $TestModel->bindTranslation($translations, false);
+ $result = $TestModel->read(null, $TestModel->id);
+ $expected = array(
+ 'TranslatedItem' => array(
+ 'id' => '4',
+ 'translated_article_id' => null,
+ 'slug' => 'fifth_translated',
+ 'locale' => 'eng',
+ 'title' => 'Title #5',
+ 'content' => ''
+ ),
+ 'Title' => array(
+ 0 => array(
+ 'id' => '19',
+ 'locale' => 'eng',
+ 'model' => 'TranslatedItem',
+ 'foreign_key' => '4',
+ 'field' => 'title',
+ 'content' => 'Title #5'
+ ),
+ 1 => array(
+ 'id' => '20',
+ 'locale' => 'spa',
+ 'model' => 'TranslatedItem',
+ 'foreign_key' => '4',
+ 'field' => 'title',
+ 'content' => 'Leyenda #5'
+ )
+ ),
+ 'Content' => array(
+ 0 => array(
+ 'id' => '21',
+ 'locale' => 'eng',
+ 'model' => 'TranslatedItem',
+ 'foreign_key' => '4',
+ 'field' => 'content',
+ 'content' => ''
+ ),
+ 1 => array(
+ 'id' => '22',
+ 'locale' => 'spa',
+ 'model' => 'TranslatedItem',
+ 'foreign_key' => '4',
+ 'field' => 'content',
+ 'content' => ''
+ )
+ )
+ );
+ $this->assertEquals($expected, $result);
+ }
+
/**
* testSaveUpdate method
*
diff --git a/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php b/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php
index adcbf4c58..c30a3fc5a 100644
--- a/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php
+++ b/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php
@@ -664,8 +664,8 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$parent = $this->Tree->findByName('1. Root', array('id'));
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
- $expected = array(array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.1', )));
+ $expected = array(array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.1')));
$this->assertSame($expected, $result);
}
@@ -686,8 +686,8 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$parent = $this->Tree->findByName('1. Root', array('id'));
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
- $expected = array(array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )));
+ $expected = array(array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')));
$this->assertSame($expected, $result);
}
@@ -708,16 +708,16 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
$expected = array(
- array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.5', )),
- array($modelClass => array('name' => '1.3', )),
- array($modelClass => array('name' => '1.4', )),
- array($modelClass => array('name' => '1.6', )),
- array($modelClass => array('name' => '1.7', )),
- array($modelClass => array('name' => '1.8', )),
- array($modelClass => array('name' => '1.9', )),
- array($modelClass => array('name' => '1.10', )));
+ array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.5')),
+ array($modelClass => array('name' => '1.3')),
+ array($modelClass => array('name' => '1.4')),
+ array($modelClass => array('name' => '1.6')),
+ array($modelClass => array('name' => '1.7')),
+ array($modelClass => array('name' => '1.8')),
+ array($modelClass => array('name' => '1.9')),
+ array($modelClass => array('name' => '1.10')));
$this->assertSame($expected, $result);
}
@@ -738,16 +738,16 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
$expected = array(
- array($modelClass => array('name' => '1.5', )),
- array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.3', )),
- array($modelClass => array('name' => '1.4', )),
- array($modelClass => array('name' => '1.6', )),
- array($modelClass => array('name' => '1.7', )),
- array($modelClass => array('name' => '1.8', )),
- array($modelClass => array('name' => '1.9', )),
- array($modelClass => array('name' => '1.10', )));
+ array($modelClass => array('name' => '1.5')),
+ array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.3')),
+ array($modelClass => array('name' => '1.4')),
+ array($modelClass => array('name' => '1.6')),
+ array($modelClass => array('name' => '1.7')),
+ array($modelClass => array('name' => '1.8')),
+ array($modelClass => array('name' => '1.9')),
+ array($modelClass => array('name' => '1.10')));
$this->assertSame($expected, $result);
}
@@ -767,8 +767,8 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$parent = $this->Tree->findByName('1. Root', array('id'));
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
- $expected = array(array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.1', )));
+ $expected = array(array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.1')));
$this->assertSame($expected, $result);
}
@@ -788,8 +788,8 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$parent = $this->Tree->findByName('1. Root', array('id'));
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
- $expected = array(array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )));
+ $expected = array(array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')));
$this->assertSame($expected, $result);
}
@@ -810,16 +810,16 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
$expected = array(
- array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.3', )),
- array($modelClass => array('name' => '1.4', )),
- array($modelClass => array('name' => '1.6', )),
- array($modelClass => array('name' => '1.7', )),
- array($modelClass => array('name' => '1.8', )),
- array($modelClass => array('name' => '1.9', )),
- array($modelClass => array('name' => '1.10', )),
- array($modelClass => array('name' => '1.5', )));
+ array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.3')),
+ array($modelClass => array('name' => '1.4')),
+ array($modelClass => array('name' => '1.6')),
+ array($modelClass => array('name' => '1.7')),
+ array($modelClass => array('name' => '1.8')),
+ array($modelClass => array('name' => '1.9')),
+ array($modelClass => array('name' => '1.10')),
+ array($modelClass => array('name' => '1.5')));
$this->assertSame($expected, $result);
}
@@ -840,16 +840,16 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
$expected = array(
- array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.3', )),
- array($modelClass => array('name' => '1.4', )),
- array($modelClass => array('name' => '1.6', )),
- array($modelClass => array('name' => '1.7', )),
- array($modelClass => array('name' => '1.5', )),
- array($modelClass => array('name' => '1.8', )),
- array($modelClass => array('name' => '1.9', )),
- array($modelClass => array('name' => '1.10', )));
+ array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.3')),
+ array($modelClass => array('name' => '1.4')),
+ array($modelClass => array('name' => '1.6')),
+ array($modelClass => array('name' => '1.7')),
+ array($modelClass => array('name' => '1.5')),
+ array($modelClass => array('name' => '1.8')),
+ array($modelClass => array('name' => '1.9')),
+ array($modelClass => array('name' => '1.10')));
$this->assertSame($expected, $result);
}
@@ -870,16 +870,16 @@ class TreeBehaviorNumberTest extends CakeTestCase {
$this->Tree->id = $parent[$modelClass]['id'];
$result = $this->Tree->children(null, true, array('name'));
$expected = array(
- array($modelClass => array('name' => '1.1', )),
- array($modelClass => array('name' => '1.2', )),
- array($modelClass => array('name' => '1.3', )),
- array($modelClass => array('name' => '1.4', )),
- array($modelClass => array('name' => 'renamed', )),
- array($modelClass => array('name' => '1.6', )),
- array($modelClass => array('name' => '1.7', )),
- array($modelClass => array('name' => '1.8', )),
- array($modelClass => array('name' => '1.9', )),
- array($modelClass => array('name' => '1.10', )));
+ array($modelClass => array('name' => '1.1')),
+ array($modelClass => array('name' => '1.2')),
+ array($modelClass => array('name' => '1.3')),
+ array($modelClass => array('name' => '1.4')),
+ array($modelClass => array('name' => 'renamed')),
+ array($modelClass => array('name' => '1.6')),
+ array($modelClass => array('name' => '1.7')),
+ array($modelClass => array('name' => '1.8')),
+ array($modelClass => array('name' => '1.9')),
+ array($modelClass => array('name' => '1.10')));
$this->assertSame($expected, $result);
}
diff --git a/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php b/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php
index 21104eda5..d2df347aa 100644
--- a/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php
+++ b/lib/Cake/Test/Case/Model/BehaviorCollectionTest.php
@@ -66,15 +66,12 @@ class TestBehavior extends ModelBehavior {
switch ($settings['beforeFind']) {
case 'on':
return false;
- break;
case 'test':
return null;
- break;
case 'modify':
$query['fields'] = array($model->alias . '.id', $model->alias . '.name', $model->alias . '.mytime');
$query['recursive'] = -1;
return $query;
- break;
}
}
@@ -94,16 +91,12 @@ class TestBehavior extends ModelBehavior {
switch ($settings['afterFind']) {
case 'on':
return array();
- break;
case 'test':
return true;
- break;
case 'test2':
return null;
- break;
case 'modify':
return Hash::extract($results, "{n}.{$model->alias}");
- break;
}
}
@@ -121,14 +114,11 @@ class TestBehavior extends ModelBehavior {
switch ($settings['beforeSave']) {
case 'on':
return false;
- break;
case 'test':
return true;
- break;
case 'modify':
$model->data[$model->alias]['name'] .= ' modified before';
return true;
- break;
}
}
@@ -157,7 +147,6 @@ class TestBehavior extends ModelBehavior {
break;
case 'test2':
return false;
- break;
case 'modify':
$model->data[$model->alias]['name'] .= ' ' . $string;
break;
@@ -179,18 +168,14 @@ class TestBehavior extends ModelBehavior {
case 'on':
$model->invalidate('name');
return true;
- break;
case 'test':
return null;
- break;
case 'whitelist':
$this->_addToWhitelist($model, array('name'));
return true;
- break;
case 'stop':
$model->invalidate('name');
return false;
- break;
}
}
@@ -209,11 +194,9 @@ class TestBehavior extends ModelBehavior {
switch ($settings['afterValidate']) {
case 'on':
return false;
- break;
case 'test':
$model->data = array('foo');
return true;
- break;
}
}
@@ -232,17 +215,14 @@ class TestBehavior extends ModelBehavior {
switch ($settings['beforeDelete']) {
case 'on':
return false;
- break;
case 'test':
return null;
- break;
case 'test2':
echo 'beforeDelete success';
if ($cascade) {
echo ' (cascading) ';
}
return true;
- break;
}
}
diff --git a/lib/Cake/Test/Case/Model/CakeSchemaTest.php b/lib/Cake/Test/Case/Model/CakeSchemaTest.php
index 47effcc14..7863af19a 100644
--- a/lib/Cake/Test/Case/Model/CakeSchemaTest.php
+++ b/lib/Cake/Test/Case/Model/CakeSchemaTest.php
@@ -198,6 +198,7 @@ class TestAppSchema extends CakeSchema {
public $datatypes = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
'float_field' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => ''),
+ 'huge_int' => array('type' => 'biginteger'),
'bool' => array('type' => 'boolean', 'null' => false, 'default' => false),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
'tableParameters' => array()
@@ -762,6 +763,23 @@ class CakeSchemaTest extends CakeTestCase {
);
$result = $this->Schema->generateTable('posts', $posts);
$this->assertRegExp('/public \$posts/', $result);
+
+ $posts = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
+ 'author_id' => array('type' => 'integer', 'null' => false),
+ 'title' => array('type' => 'string', 'null' => false),
+ 'body' => array('type' => 'text', 'null' => true, 'default' => null),
+ 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
+ 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
+ 'indexes' => array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => true),
+ 'MyFtIndex' => array('column' => array('title', 'body'), 'type' => 'fulltext')
+ )
+ );
+ $result = $this->Schema->generateTable('fields', $posts);
+ $this->assertRegExp('/public \$fields/', $result);
+ $this->assertPattern('/\'type\' \=\> \'fulltext\'/', $result);
}
/**
diff --git a/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php b/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php
index a2276972f..0c98febaa 100644
--- a/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php
+++ b/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php
@@ -231,7 +231,7 @@ class CakeSessionTest extends CakeTestCase {
TestCakeSession::write('SessionTestCase', 'value');
$this->assertTrue(TestCakeSession::check('SessionTestCase'));
- $this->assertFalse(TestCakeSession::check('NotExistingSessionTestCase'), false);
+ $this->assertFalse(TestCakeSession::check('NotExistingSessionTestCase'));
}
/**
diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
index 7ae749268..aefcbe52d 100644
--- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
+++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
@@ -268,6 +268,13 @@ class MysqlTest extends CakeTestCase {
$this->Dbo->rawQuery('DROP TABLE ' . $name);
$this->assertEquals($expected, $result);
+ $name = $this->Dbo->fullTableName('bigint');
+ $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id bigint(20) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id));');
+ $expected = array('PRIMARY' => array('column' => 'id', 'unique' => 1));
+ $result = $this->Dbo->index('bigint', false);
+ $this->Dbo->rawQuery('DROP TABLE ' . $name);
+ $this->assertEquals($expected, $result);
+
$name = $this->Dbo->fullTableName('with_a_key');
$this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id), KEY `pointless_bool` ( `bool` ));');
$expected = array(
@@ -313,6 +320,16 @@ class MysqlTest extends CakeTestCase {
$result = $this->Dbo->index('with_multiple_compound_keys', false);
$this->Dbo->rawQuery('DROP TABLE ' . $name);
$this->assertEquals($expected, $result);
+
+ $name = $this->Dbo->fullTableName('with_fulltext');
+ $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, name varchar(255), description text, primary key(id), FULLTEXT KEY `MyFtIndex` ( `name`, `description` )) ENGINE=MyISAM;');
+ $expected = array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ 'MyFtIndex' => array('column' => array('name', 'description'), 'type' => 'fulltext')
+ );
+ $result = $this->Dbo->index('with_fulltext', false);
+ $this->Dbo->rawQuery('DROP TABLE ' . $name);
+ $this->assertEquals($expected, $result);
}
/**
@@ -477,6 +494,10 @@ class MysqlTest extends CakeTestCase {
$expected = 'integer';
$this->assertEquals($expected, $result);
+ $result = $this->Dbo->column('bigint(20)');
+ $expected = 'biginteger';
+ $this->assertEquals($expected, $result);
+
$result = $this->Dbo->column('tinyint(1)');
$expected = 'boolean';
$this->assertEquals($expected, $result);
@@ -548,9 +569,9 @@ class MysqlTest extends CakeTestCase {
$result = $this->Dbo->alterSchema($schemaB->compare($schemaA));
$this->assertContains("ALTER TABLE $table", $result);
- $this->assertContains('ADD KEY name_idx (`name`),', $result);
- $this->assertContains('ADD KEY group_idx (`group1`),', $result);
- $this->assertContains('ADD KEY compound_idx (`group1`, `group2`),', $result);
+ $this->assertContains('ADD KEY `name_idx` (`name`),', $result);
+ $this->assertContains('ADD KEY `group_idx` (`group1`),', $result);
+ $this->assertContains('ADD KEY `compound_idx` (`group1`, `group2`),', $result);
$this->assertContains('ADD PRIMARY KEY (`id`);', $result);
//Test that the string is syntactically correct
@@ -576,13 +597,13 @@ class MysqlTest extends CakeTestCase {
$result = $this->Dbo->alterSchema($schemaC->compare($schemaB));
$this->assertContains("ALTER TABLE $table", $result);
$this->assertContains('DROP PRIMARY KEY,', $result);
- $this->assertContains('DROP KEY name_idx,', $result);
- $this->assertContains('DROP KEY group_idx,', $result);
- $this->assertContains('DROP KEY compound_idx,', $result);
- $this->assertContains('ADD KEY id_name_idx (`id`, `name`),', $result);
- $this->assertContains('ADD UNIQUE KEY name_idx (`name`),', $result);
- $this->assertContains('ADD KEY group_idx (`group2`),', $result);
- $this->assertContains('ADD KEY compound_idx (`group2`, `group1`);', $result);
+ $this->assertContains('DROP KEY `name_idx`,', $result);
+ $this->assertContains('DROP KEY `group_idx`,', $result);
+ $this->assertContains('DROP KEY `compound_idx`,', $result);
+ $this->assertContains('ADD KEY `id_name_idx` (`id`, `name`),', $result);
+ $this->assertContains('ADD UNIQUE KEY `name_idx` (`name`),', $result);
+ $this->assertContains('ADD KEY `group_idx` (`group2`),', $result);
+ $this->assertContains('ADD KEY `compound_idx` (`group2`, `group1`);', $result);
$query = $this->Dbo->getConnection()->prepare($result);
$this->assertEquals($query->queryString, $result);
@@ -594,10 +615,10 @@ class MysqlTest extends CakeTestCase {
$result = $this->Dbo->alterSchema($schemaA->compare($schemaC));
$this->assertContains("ALTER TABLE $table", $result);
- $this->assertContains('DROP KEY name_idx,', $result);
- $this->assertContains('DROP KEY group_idx,', $result);
- $this->assertContains('DROP KEY compound_idx,', $result);
- $this->assertContains('DROP KEY id_name_idx;', $result);
+ $this->assertContains('DROP KEY `name_idx`,', $result);
+ $this->assertContains('DROP KEY `group_idx`,', $result);
+ $this->assertContains('DROP KEY `compound_idx`,', $result);
+ $this->assertContains('DROP KEY `id_name_idx`;', $result);
$query = $this->Dbo->getConnection()->prepare($result);
$this->assertEquals($query->queryString, $result);
@@ -752,7 +773,7 @@ class MysqlTest extends CakeTestCase {
}
/**
- * testBuildTableParameters method
+ * testGetCharsetName method
*
* @return void
*/
@@ -764,6 +785,34 @@ class MysqlTest extends CakeTestCase {
$this->assertEquals('cp1250', $result);
}
+/**
+ * testGetCharsetNameCaching method
+ *
+ * @return void
+ */
+ public function testGetCharsetNameCaching() {
+ $db = $this->getMock('Mysql', array('connect', '_execute', 'getVersion'));
+ $queryResult = $this->getMock('PDOStatement');
+
+ $db->expects($this->exactly(2))->method('getVersion')->will($this->returnValue('5.1'));
+
+ $db->expects($this->exactly(1))
+ ->method('_execute')
+ ->with('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?', array('utf8_unicode_ci'))
+ ->will($this->returnValue($queryResult));
+
+ $queryResult->expects($this->once())
+ ->method('fetch')
+ ->with(PDO::FETCH_ASSOC)
+ ->will($this->returnValue(array('CHARACTER_SET_NAME' => 'utf8')));
+
+ $result = $db->getCharsetName('utf8_unicode_ci');
+ $this->assertEquals('utf8', $result);
+
+ $result = $db->getCharsetName('utf8_unicode_ci');
+ $this->assertEquals('utf8', $result);
+ }
+
/**
* test that changing the virtualFieldSeparator allows for __ fields.
*
@@ -1951,8 +2000,8 @@ class MysqlTest extends CakeTestCase {
$expected = " WHERE SUM(`Post`.`comments_count`) > 500";
$this->assertEquals($expected, $result);
- $result = $this->Dbo->conditions("(Post.created < '" . date('Y-m-d H:i:s') . "') GROUP BY YEAR(Post.created), MONTH(Post.created)");
- $expected = " WHERE (`Post`.`created` < '" . date('Y-m-d H:i:s') . "') GROUP BY YEAR(`Post`.`created`), MONTH(`Post`.`created`)";
+ $result = $this->Dbo->conditions("(Post.created < '" . date('Y-m-d H:i') . "') GROUP BY YEAR(Post.created), MONTH(Post.created)");
+ $expected = " WHERE (`Post`.`created` < '" . date('Y-m-d H:i') . "') GROUP BY YEAR(`Post`.`created`), MONTH(`Post`.`created`)";
$this->assertEquals($expected, $result);
$result = $this->Dbo->conditions("score BETWEEN 90.1 AND 95.7");
@@ -2902,6 +2951,13 @@ class MysqlTest extends CakeTestCase {
$result = $this->Dbo->buildIndex($data);
$expected = array('UNIQUE KEY `MyIndex` (`id`, `name`)');
$this->assertEquals($expected, $result);
+
+ $data = array(
+ 'MyFtIndex' => array('column' => array('name', 'description'), 'type' => 'fulltext')
+ );
+ $result = $this->Dbo->buildIndex($data);
+ $expected = array('FULLTEXT KEY `MyFtIndex` (`name`, `description`)');
+ $this->assertEquals($expected, $result);
}
/**
@@ -3305,7 +3361,7 @@ class MysqlTest extends CakeTestCase {
);
$conditions = array('comment_count >' => 2);
- $query = 'SELECT ' . join(',', $this->Dbo->fields($Article, null, array('id', 'comment_count'))) .
+ $query = 'SELECT ' . implode(',', $this->Dbo->fields($Article, null, array('id', 'comment_count'))) .
' FROM ' . $this->Dbo->fullTableName($Article) . ' Article ' . $this->Dbo->conditions($conditions, true, true, $Article);
$result = $this->Dbo->fetchAll($query);
$expected = array(array(
diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php
index 2046e6b19..7015750d3 100644
--- a/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php
+++ b/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php
@@ -307,6 +307,10 @@ class PostgresTest extends CakeTestCase {
$this->assertEquals('string', $this->Dbo2->column('character varying'));
$this->assertEquals('time', $this->Dbo2->column('time without time zone'));
$this->assertEquals('datetime', $this->Dbo2->column('timestamp without time zone'));
+
+ $result = $this->Dbo2->column('bigint');
+ $expected = 'biginteger';
+ $this->assertEquals($expected, $result);
}
/**
@@ -530,6 +534,7 @@ class PostgresTest extends CakeTestCase {
id serial NOT NULL,
"varchar" character varying(40) NOT NULL,
"full_length" character varying NOT NULL,
+ "huge_int" bigint NOT NULL,
"timestamp" timestamp without time zone,
"date" date,
CONSTRAINT test_data_types_pkey PRIMARY KEY (id)
@@ -541,12 +546,15 @@ class PostgresTest extends CakeTestCase {
'connection' => 'test',
'models' => array('DatatypeTest')
));
- $schema->tables = array('datatype_tests' => $result['tables']['missing']['datatype_tests']);
+ $schema->tables = array(
+ 'datatype_tests' => $result['tables']['missing']['datatype_tests']
+ );
$result = $db1->createSchema($schema, 'datatype_tests');
$this->assertNotRegExp('/timestamp DEFAULT/', $result);
$this->assertRegExp('/\"full_length\"\s*text\s.*,/', $result);
- $this->assertRegExp('/timestamp\s*,/', $result);
+ $this->assertContains('timestamp ,', $result);
+ $this->assertContains('"huge_int" bigint NOT NULL,', $result);
$db1->query('DROP TABLE ' . $db1->fullTableName('datatype_tests'));
@@ -942,4 +950,26 @@ class PostgresTest extends CakeTestCase {
$this->assertNotEmpty($model->read(null, 1));
}
+ public function testResetSequence() {
+ $model = new Article();
+
+ $table = $this->Dbo->fullTableName($model, false);
+ $fields = array(
+ 'id', 'user_id', 'title', 'body', 'published',
+ );
+ $values = array(
+ array(1, 1, 'test', 'first post', false),
+ array(2, 1, 'test 2', 'second post post', false),
+ );
+ $this->Dbo->insertMulti($table, $fields, $values);
+ $sequence = $this->Dbo->getSequence($table);
+ $result = $this->Dbo->rawQuery("SELECT nextval('$sequence')");
+ $original = $result->fetch(PDO::FETCH_ASSOC);
+
+ $this->assertTrue($this->Dbo->resetSequence($table, 'id'));
+ $result = $this->Dbo->rawQuery("SELECT currval('$sequence')");
+ $new = $result->fetch(PDO::FETCH_ASSOC);
+ $this->assertTrue($new['currval'] > $original['nextval'], 'Sequence did not update');
+ }
+
}
diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php
index f590cc7a0..007f2a883 100644
--- a/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php
+++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php
@@ -77,7 +77,7 @@ class SqliteTest extends CakeTestCase {
*
* @var object
*/
- public $fixtures = array('core.user', 'core.uuid');
+ public $fixtures = array('core.user', 'core.uuid', 'core.datatype');
/**
* Actual DB connection used in testing
@@ -253,6 +253,16 @@ class SqliteTest extends CakeTestCase {
$result = $this->Dbo->buildColumn($data);
$expected = '"testName" integer(10) DEFAULT 10 NOT NULL';
$this->assertEquals($expected, $result);
+
+ $data = array(
+ 'name' => 'huge',
+ 'type' => 'biginteger',
+ 'length' => 20,
+ 'null' => false,
+ );
+ $result = $this->Dbo->buildColumn($data);
+ $expected = '"huge" bigint(20) NOT NULL';
+ $this->assertEquals($expected, $result);
}
/**
@@ -262,7 +272,11 @@ class SqliteTest extends CakeTestCase {
*/
public function testDescribe() {
$this->loadFixtures('User');
- $Model = new Model(array('name' => 'User', 'ds' => 'test', 'table' => 'users'));
+ $Model = new Model(array(
+ 'name' => 'User',
+ 'ds' => 'test',
+ 'table' => 'users'
+ ));
$this->Dbo->cacheSources = true;
Configure::write('Cache.disable', false);
@@ -310,6 +324,46 @@ class SqliteTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * Test that datatypes are reflected
+ *
+ * @return void
+ */
+ public function testDatatypes() {
+ $this->loadFixtures('Datatype');
+ $Model = new Model(array(
+ 'name' => 'Datatype',
+ 'ds' => 'test',
+ 'table' => 'datatypes'
+ ));
+ $result = $this->Dbo->describe($Model);
+ $expected = array(
+ 'id' => array(
+ 'type' => 'integer',
+ 'null' => false,
+ 'default' => 0,
+ 'key' => 'primary'
+ ),
+ 'float_field' => array(
+ 'type' => 'float',
+ 'length' => '5,2',
+ 'null' => false,
+ 'default' => null
+ ),
+ 'huge_int' => array(
+ 'type' => 'bigint',
+ 'length' => '20',
+ 'null' => true,
+ 'default' => null
+ ),
+ 'bool' => array(
+ 'type' => 'boolean',
+ 'null' => false,
+ 'default' => false
+ ),
+ );
+ }
+
/**
* test that describe does not corrupt UUID primary keys
*
diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php
index ee7695a5f..965c0735a 100644
--- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php
+++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php
@@ -553,6 +553,14 @@ class SqlserverTest extends CakeTestCase {
$result = $this->db->buildColumn($column);
$expected = "[checked] bit DEFAULT '1'";
$this->assertEquals($expected, $result);
+
+ $column = array(
+ 'name' => 'huge',
+ 'type' => 'biginteger',
+ );
+ $result = $this->db->buildColumn($column);
+ $expected = "[huge] bigint";
+ $this->assertEquals($expected, $result);
}
/**
diff --git a/lib/Cake/Test/Case/Model/ModelIntegrationTest.php b/lib/Cake/Test/Case/Model/ModelIntegrationTest.php
index a7063c0fd..4eec3151f 100644
--- a/lib/Cake/Test/Case/Model/ModelIntegrationTest.php
+++ b/lib/Cake/Test/Case/Model/ModelIntegrationTest.php
@@ -1667,6 +1667,14 @@ class ModelIntegrationTest extends BaseModelTest {
$result = $TestModel->alias;
$expected = 'AnotherTest';
$this->assertEquals($expected, $result);
+
+ $TestModel = ClassRegistry::init('Test');
+ $expected = null;
+ $this->assertEquals($expected, $TestModel->plugin);
+
+ $TestModel = ClassRegistry::init('TestPlugin.TestPluginComment');
+ $expected = 'TestPlugin';
+ $this->assertEquals($expected, $TestModel->plugin);
}
/**
diff --git a/lib/Cake/Test/Case/Model/ModelReadTest.php b/lib/Cake/Test/Case/Model/ModelReadTest.php
index fe3780345..c242e3d11 100644
--- a/lib/Cake/Test/Case/Model/ModelReadTest.php
+++ b/lib/Cake/Test/Case/Model/ModelReadTest.php
@@ -5401,7 +5401,9 @@ class ModelReadTest extends BaseModelTest {
));
$Post->Tag->primaryKey = 'tag';
- $result = $Post->find('all');
+ $result = $Post->find('all', array(
+ 'order' => array('Post.id' => 'ASC')
+ ));
$expected = array(
array(
'Post' => array(
diff --git a/lib/Cake/Test/Case/Model/ModelValidationTest.php b/lib/Cake/Test/Case/Model/ModelValidationTest.php
index 6c6fdd914..de747f735 100644
--- a/lib/Cake/Test/Case/Model/ModelValidationTest.php
+++ b/lib/Cake/Test/Case/Model/ModelValidationTest.php
@@ -713,25 +713,6 @@ class ModelValidationTest extends BaseModelTest {
$TestModel->invalidFields(array('fieldList' => array('title')));
}
-/**
- * Test that missing validation methods does not trigger errors in production mode.
- *
- * @return void
- */
- public function testMissingValidationErrorNoTriggering() {
- Configure::write('debug', 0);
- $TestModel = new ValidationTest1();
- $TestModel->create(array('title' => 'foo'));
- $TestModel->validate = array(
- 'title' => array(
- 'rule' => array('thisOneBringsThePain'),
- 'required' => true
- )
- );
- $TestModel->invalidFields(array('fieldList' => array('title')));
- $this->assertEquals(array(), $TestModel->validationErrors);
- }
-
/**
* Test placeholder replacement when validation message is an array
*
diff --git a/lib/Cake/Test/Case/Model/ModelWriteTest.php b/lib/Cake/Test/Case/Model/ModelWriteTest.php
index 1a015ef42..2879c3a10 100644
--- a/lib/Cake/Test/Case/Model/ModelWriteTest.php
+++ b/lib/Cake/Test/Case/Model/ModelWriteTest.php
@@ -58,7 +58,7 @@ class ModelWriteTest extends BaseModelTest {
$lastInsertId = $TestModel->JoinAsJoinB->getLastInsertID();
$data['id'] = $lastInsertId;
$this->assertEquals(array('JoinAsJoinB' => $data), $result);
- $this->assertTrue($lastInsertId != null);
+ $this->assertTrue($lastInsertId > 0);
$result = $TestModel->JoinAsJoinB->findById(1);
$expected = array(
@@ -6470,10 +6470,10 @@ class ModelWriteTest extends BaseModelTest {
// test belongsTo
$fieldList = array(
- 'Post' => array('title', 'author_id'),
+ 'Post' => array('title'),
'Author' => array('user')
);
- $TestModel->saveAll(array(
+ $data = array(
'Post' => array(
'title' => 'Post without body',
'body' => 'This will not be saved',
@@ -6482,7 +6482,8 @@ class ModelWriteTest extends BaseModelTest {
'user' => 'bob',
'test' => 'This will not be saved',
- )), array('fieldList' => $fieldList));
+ ));
+ $TestModel->saveAll($data, array('fieldList' => $fieldList));
$result = $TestModel->find('all');
$expected = array(
@@ -6569,22 +6570,42 @@ class ModelWriteTest extends BaseModelTest {
$this->db->truncate($TestModel);
$this->db->truncate(new Comment());
- $fieldList = array(
- 'Article' => array('id'),
- 'Comment' => array('article_id', 'user_id')
- );
- $result = $TestModel->saveAll(array(
- 'Article' => array('id' => 2, 'title' => 'I will not save'),
+ $data = array(
+ 'Article' => array('title' => 'I will not save'),
'Comment' => array(
array('comment' => 'First new comment', 'published' => 'Y', 'user_id' => 1),
array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
)
- ), array('fieldList' => $fieldList));
+ );
+
+ $fieldList = array(
+ 'Article' => array('id'),
+ 'Comment' => array('article_id', 'user_id')
+ );
+ $TestModel->saveAll($data, array('fieldList' => $fieldList));
$result = $TestModel->find('all');
$this->assertEquals('', $result[0]['Article']['title']);
$this->assertEquals('', $result[0]['Comment'][0]['comment']);
$this->assertEquals('', $result[0]['Comment'][1]['comment']);
+
+ $fieldList = array(
+ 'Article' => array('id'),
+ 'Comment' => array('user_id')
+ );
+ $TestModel->saveAll($data, array('fieldList' => $fieldList));
+ $result = $TestModel->find('all');
+
+ $this->assertEquals('', $result[1]['Article']['title']);
+ $this->assertEquals(2, count($result[1]['Comment']));
+
+ $TestModel->whitelist = array('id');
+ $TestModel->Comment->whitelist = array('user_id');
+ $TestModel->saveAll($data);
+ $result = $TestModel->find('all');
+
+ $this->assertEquals('', $result[2]['Article']['title']);
+ $this->assertEquals(2, count($result[2]['Comment']));
}
/**
@@ -6623,6 +6644,59 @@ class ModelWriteTest extends BaseModelTest {
$this->assertEmpty($TestModel->validationErrors);
}
+/**
+ * testSaveAllFieldListHasOneAddFkToWhitelist method
+ *
+ * @return void
+ */
+ public function testSaveAllFieldListHasOneAddFkToWhitelist() {
+ $this->loadFixtures('ArticleFeatured', 'Featured');
+ $Article = new ArticleFeatured();
+ $Article->belongsTo = $Article->hasMany = array();
+ $Article->Featured->validate = array('end_date' => 'notEmpty');
+
+ $record = array(
+ 'ArticleFeatured' => array(
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => '',
+ 'published' => 'Y'
+ ),
+ 'Featured' => array(
+ 'category_id' => 1,
+ 'end_date' => ''
+ )
+ );
+ $result = $Article->saveAll($record, array('validate' => 'only'));
+ $this->assertFalse($result);
+ $expected = array(
+ 'body' => array(
+ 'This field cannot be left blank'
+ ),
+ 'Featured' => array(
+ 'end_date' => array(
+ 'This field cannot be left blank'
+ )
+ )
+ );
+ $this->assertEquals($expected, $Article->validationErrors);
+
+ $fieldList = array(
+ 'ArticleFeatured' => array('user_id', 'title'),
+ 'Featured' => array('category_id')
+ );
+
+ $result = $Article->saveAll($record, array(
+ 'fieldList' => $fieldList, 'validate' => 'first'
+ ));
+ $this->assertTrue($result);
+ $this->assertEmpty($Article->validationErrors);
+
+ $Article->recursive = 0;
+ $result = $Article->find('first', array('order' => array('ArticleFeatured.created' => 'DESC')));
+ $this->assertSame($result['ArticleFeatured']['id'], $result['Featured']['article_featured_id']);
+ }
+
/**
* testSaveAllDeepFieldListValidateBelongsTo
*
diff --git a/lib/Cake/Test/Case/Model/models.php b/lib/Cake/Test/Case/Model/models.php
index b86a4b583..c6c5699a2 100644
--- a/lib/Cake/Test/Case/Model/models.php
+++ b/lib/Cake/Test/Case/Model/models.php
@@ -2003,28 +2003,28 @@ class CallbackPostTestModel extends CakeTestModel {
/**
* variable to control return of beforeValidate
*
- * @var string
+ * @var boolean
*/
public $beforeValidateReturn = true;
/**
* variable to control return of beforeSave
*
- * @var string
+ * @var boolean
*/
public $beforeSaveReturn = true;
/**
* variable to control return of beforeDelete
*
- * @var string
+ * @var boolean
*/
public $beforeDeleteReturn = true;
/**
* beforeSave callback
*
- * @return void
+ * @return boolean
*/
public function beforeSave($options = array()) {
return $this->beforeSaveReturn;
@@ -2033,7 +2033,7 @@ class CallbackPostTestModel extends CakeTestModel {
/**
* beforeValidate callback
*
- * @return void
+ * @return boolean
*/
public function beforeValidate($options = array()) {
return $this->beforeValidateReturn;
@@ -2042,7 +2042,7 @@ class CallbackPostTestModel extends CakeTestModel {
/**
* beforeDelete callback
*
- * @return void
+ * @return boolean
*/
public function beforeDelete($cascade = true) {
return $this->beforeDeleteReturn;
diff --git a/lib/Cake/Test/Case/Network/CakeRequestTest.php b/lib/Cake/Test/Case/Network/CakeRequestTest.php
index 487f60e80..189a109c7 100644
--- a/lib/Cake/Test/Case/Network/CakeRequestTest.php
+++ b/lib/Cake/Test/Case/Network/CakeRequestTest.php
@@ -981,7 +981,7 @@ class CakeRequestTest extends CakeTestCase {
* @return void
*/
public function detectCallback($request) {
- return $request->return == true;
+ return (bool)$request->return;
}
/**
@@ -1721,6 +1721,45 @@ class CakeRequestTest extends CakeTestCase {
}
}
+/**
+ * test the query() method
+ *
+ * @return void
+ */
+ public function testQuery() {
+ $_GET = array();
+ $_GET['foo'] = 'bar';
+
+ $request = new CakeRequest();
+
+ $result = $request->query('foo');
+ $this->assertEquals('bar', $result);
+
+ $result = $request->query('imaginary');
+ $this->assertNull($result);
+ }
+
+/**
+ * test the query() method with arrays passed via $_GET
+ *
+ * @return void
+ */
+ public function testQueryWithArray() {
+ $_GET = array();
+ $_GET['test'] = array('foo', 'bar');
+
+ $request = new CakeRequest();
+
+ $result = $request->query('test');
+ $this->assertEquals(array('foo', 'bar'), $result);
+
+ $result = $request->query('test.1');
+ $this->assertEquals('bar', $result);
+
+ $result = $request->query('test.2');
+ $this->assertNull($result);
+ }
+
/**
* test the data() method reading
*
@@ -1789,19 +1828,41 @@ class CakeRequestTest extends CakeTestCase {
* @return void
*/
public function testAcceptLanguage() {
+ // Weird language
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'inexistent,en-ca';
$result = CakeRequest::acceptLanguage();
$this->assertEquals(array('inexistent', 'en-ca'), $result, 'Languages do not match');
- $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'es_mx;en_ca';
+ // No qualifier
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'es_mx,en_ca';
$result = CakeRequest::acceptLanguage();
$this->assertEquals(array('es-mx', 'en-ca'), $result, 'Languages do not match');
+ // With qualifier
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4';
+ $result = CakeRequest::acceptLanguage();
+ $this->assertEquals(array('en-us', 'en', 'pt-br', 'pt'), $result, 'Languages do not match');
+
+ // With spaces
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'da, en-gb;q=0.8, en;q=0.7';
+ $result = CakeRequest::acceptLanguage();
+ $this->assertEquals(array('da', 'en-gb', 'en'), $result, 'Languages do not match');
+
+ // Checking if requested
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'es_mx,en_ca';
+ $result = CakeRequest::acceptLanguage();
+
$result = CakeRequest::acceptLanguage('en-ca');
$this->assertTrue($result);
+ $result = CakeRequest::acceptLanguage('en-CA');
+ $this->assertTrue($result);
+
$result = CakeRequest::acceptLanguage('en-us');
$this->assertFalse($result);
+
+ $result = CakeRequest::acceptLanguage('en-US');
+ $this->assertFalse($result);
}
/**
@@ -1907,6 +1968,40 @@ XML;
$this->assertFalse($request->isRequested());
}
+/**
+ * TestOnlyAllow
+ *
+ * @return void
+ */
+ public function testOnlyAllow() {
+ $_SERVER['REQUEST_METHOD'] = 'PUT';
+ $request = new CakeRequest('/posts/edit/1');
+
+ $this->assertTrue($request->onlyAllow(array('put')));
+
+ $_SERVER['REQUEST_METHOD'] = 'DELETE';
+ $this->assertTrue($request->onlyAllow('post', 'delete'));
+ }
+
+/**
+ * TestOnlyAllow throwing exception
+ *
+ */
+ public function testOnlyAllowException() {
+ $_SERVER['REQUEST_METHOD'] = 'PUT';
+ $request = new CakeRequest('/posts/edit/1');
+
+ try {
+ $request->onlyAllow('POST', 'DELETE');
+ $this->fail('An expected exception has not been raised.');
+ } catch (MethodNotAllowedException $e) {
+ $this->assertEquals(array('Allow' => 'POST, DELETE'), $e->responseHeader());
+ }
+
+ $this->setExpectedException('MethodNotAllowedException');
+ $request->onlyAllow('POST');
+ }
+
/**
* loadEnvironment method
*
diff --git a/lib/Cake/Test/Case/Network/CakeResponseTest.php b/lib/Cake/Test/Case/Network/CakeResponseTest.php
index 9f601b1b4..5446c0f96 100644
--- a/lib/Cake/Test/Case/Network/CakeResponseTest.php
+++ b/lib/Cake/Test/Case/Network/CakeResponseTest.php
@@ -1006,4 +1006,363 @@ class CakeResponseTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * testFileNotFound
+ *
+ * @expectedException NotFoundException
+ * @return void
+ */
+ public function testFileNotFound() {
+ $response = new CakeResponse();
+ $response->file('/some/missing/folder/file.jpg');
+ }
+
+/**
+ * testFile method
+ *
+ * @return void
+ */
+ public function testFile() {
+ $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('Content-Length', 38);
+
+ $response->expects($this->once())->method('_clearBuffer');
+ $response->expects($this->once())->method('_flushBuffer');
+
+ $response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css');
+
+ ob_start();
+ $result = $response->send();
+ $output = ob_get_clean();
+ $this->assertEquals("/* this is the test asset css file */\n", $output);
+ $this->assertTrue($result !== false);
+ }
+
+/**
+ * testFileWithUnknownFileTypeGeneric method
+ *
+ * @return void
+ */
+ public function testFileWithUnknownFileTypeGeneric() {
+ $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
+ $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
+
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->exactly(1))
+ ->method('type')
+ ->with('ini')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->once())
+ ->method('download')
+ ->with('no_section.ini');
+
+ $response->expects($this->at(2))
+ ->method('header')
+ ->with('Accept-Ranges', 'bytes');
+
+ $response->expects($this->at(3))
+ ->method('header')
+ ->with('Content-Length', 35);
+
+ $response->expects($this->once())->method('_clearBuffer');
+ $response->expects($this->once())->method('_flushBuffer');
+
+ $response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini');
+
+ ob_start();
+ $result = $response->send();
+ $output = ob_get_clean();
+ $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
+ $this->assertTrue($result !== false);
+ if ($currentUserAgent !== null) {
+ $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
+ }
+ }
+
+/**
+ * testFileWithUnknownFileTypeOpera method
+ *
+ * @return void
+ */
+ public function testFileWithUnknownFileTypeOpera() {
+ $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
+ $_SERVER['HTTP_USER_AGENT'] = 'Opera/9.80 (Windows NT 6.0; U; en) Presto/2.8.99 Version/11.10';
+
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->at(0))
+ ->method('type')
+ ->with('ini')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->at(1))
+ ->method('type')
+ ->with('application/octetstream')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->once())
+ ->method('download')
+ ->with('no_section.ini');
+
+ $response->expects($this->at(3))
+ ->method('header')
+ ->with('Accept-Ranges', 'bytes');
+
+ $response->expects($this->at(4))
+ ->method('header')
+ ->with('Content-Length', 35);
+
+ $response->expects($this->once())->method('_clearBuffer');
+ $response->expects($this->once())->method('_flushBuffer');
+ $response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini');
+
+ ob_start();
+ $result = $response->send();
+ $output = ob_get_clean();
+ $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
+ $this->assertTrue($result !== false);
+ if ($currentUserAgent !== null) {
+ $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
+ }
+ }
+
+/**
+ * testFileWithUnknownFileTypeIE method
+ *
+ * @return void
+ */
+ public function testFileWithUnknownFileTypeIE() {
+ $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
+ $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)';
+
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->at(0))
+ ->method('type')
+ ->with('ini')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->at(1))
+ ->method('type')
+ ->with('application/force-download')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->once())
+ ->method('download')
+ ->with('config.ini');
+
+ $response->expects($this->at(3))
+ ->method('header')
+ ->with('Accept-Ranges', 'bytes');
+
+ $response->expects($this->at(4))
+ ->method('header')
+ ->with('Content-Length', 35);
+
+ $response->expects($this->once())->method('_clearBuffer');
+ $response->expects($this->once())->method('_flushBuffer');
+ $response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini', array(
+ 'name' => 'config.ini'
+ ));
+
+ ob_start();
+ $result = $response->send();
+ $output = ob_get_clean();
+ $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
+ $this->assertTrue($result !== false);
+ if ($currentUserAgent !== null) {
+ $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
+ }
+ }
+/**
+ * testFileWithUnknownFileNoDownload method
+ *
+ * @return void
+ */
+ public function testFileWithUnknownFileNoDownload() {
+ $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
+ $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
+
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->exactly(1))
+ ->method('type')
+ ->with('ini')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->never())
+ ->method('download');
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini', array(
+ 'download' => false
+ ));
+
+ if ($currentUserAgent !== null) {
+ $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
+ }
+ }
+
+/**
+ * testConnectionAbortedOnBuffering method
+ *
+ * @return void
+ */
+ public function testConnectionAbortedOnBuffering() {
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->any())
+ ->method('type')
+ ->with('css')
+ ->will($this->returnArgument(0));
+
+ $response->expects($this->at(0))
+ ->method('_isActive')
+ ->will($this->returnValue(false));
+
+ $response->expects($this->once())->method('_clearBuffer');
+ $response->expects($this->never())->method('_flushBuffer');
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css');
+
+ $result = $response->send();
+ $this->assertNull($result);
+ }
+
+/**
+ * Test downloading files with UPPERCASE extensions.
+ *
+ * @return void
+ */
+ public function testFileUpperExtension() {
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->any())
+ ->method('type')
+ ->with('jpg')
+ ->will($this->returnArgument(0));
+
+ $response->expects($this->at(0))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS . 'test_2.JPG');
+ }
+
+/**
+ * Test downloading files with extension not explicitly set.
+ *
+ * @return void
+ */
+ public function testFileExtensionNotSet() {
+ $response = $this->getMock('CakeResponse', array(
+ 'header',
+ 'type',
+ 'download',
+ '_sendHeader',
+ '_setContentType',
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer'
+ ));
+
+ $response->expects($this->any())
+ ->method('type')
+ ->with('jpg')
+ ->will($this->returnArgument(0));
+
+ $response->expects($this->at(0))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+
+ $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS . 'test_2.JPG');
+ }
+
}
diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php
index abe6fcadf..49c46882b 100644
--- a/lib/Cake/Test/Case/Network/CakeSocketTest.php
+++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php
@@ -204,14 +204,147 @@ class CakeSocketTest extends CakeTestCase {
*/
public function testReset() {
$config = array(
- 'persistent' => true,
- 'host' => '127.0.0.1',
- 'protocol' => 'udp',
- 'port' => 80,
- 'timeout' => 20
+ 'persistent' => true,
+ 'host' => '127.0.0.1',
+ 'protocol' => 'udp',
+ 'port' => 80,
+ 'timeout' => 20
);
$anotherSocket = new CakeSocket($config);
$anotherSocket->reset();
$this->assertEquals(array(), $anotherSocket->config);
}
+
+/**
+ * testEncrypt
+ *
+ * @expectedException SocketException
+ * @return void
+ */
+ public function testEnableCryptoSocketExceptionNoSsl() {
+ $this->skipIf(!extension_loaded('openssl'), 'OpenSSL is not enabled cannot test SSL.');
+ $configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1);
+
+ // testing exception on no ssl socket server for ssl and tls methods
+ $this->Socket = new CakeSocket($configNoSslOrTls);
+ $this->Socket->connect();
+ $this->Socket->enableCrypto('sslv3', 'client');
+ }
+
+/**
+ * testEnableCryptoSocketExceptionNoTls
+ *
+ * @expectedException SocketException
+ * @return void
+ */
+ public function testEnableCryptoSocketExceptionNoTls() {
+ $configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1);
+
+ // testing exception on no ssl socket server for ssl and tls methods
+ $this->Socket = new CakeSocket($configNoSslOrTls);
+ $this->Socket->connect();
+ $this->Socket->enableCrypto('tls', 'client');
+ }
+
+/**
+ * _connectSocketToSslTls
+ *
+ * @return void
+ */
+ protected function _connectSocketToSslTls() {
+ $this->skipIf(!extension_loaded('openssl'), 'OpenSSL is not enabled cannot test SSL.');
+ $configSslTls = array('host' => 'smtp.gmail.com', 'port' => 465, 'timeout' => 5);
+ $this->Socket = new CakeSocket($configSslTls);
+ $this->Socket->connect();
+ }
+
+/**
+ * testEnableCryptoBadMode
+ *
+ * @expectedException InvalidArgumentException
+ * @return void
+ */
+ public function testEnableCryptoBadMode() {
+ // testing wrong encryption mode
+ $this->_connectSocketToSslTls();
+ $this->Socket->enableCrypto('doesntExistMode', 'server');
+ $this->Socket->disconnect();
+ }
+
+/**
+ * testEnableCrypto
+ *
+ * @return void
+ */
+ public function testEnableCrypto() {
+ // testing on ssl server
+ $this->_connectSocketToSslTls();
+ $this->assertTrue($this->Socket->enableCrypto('sslv3', 'client'));
+ $this->Socket->disconnect();
+
+ // testing on tls server
+ $this->_connectSocketToSslTls();
+ $this->assertTrue($this->Socket->enableCrypto('tls', 'client'));
+ $this->Socket->disconnect();
+ }
+
+/**
+ * testEnableCryptoExceptionEnableTwice
+ *
+ * @expectedException SocketException
+ * @return void
+ */
+ public function testEnableCryptoExceptionEnableTwice() {
+ // testing on tls server
+ $this->_connectSocketToSslTls();
+ $this->Socket->enableCrypto('tls', 'client');
+ $this->Socket->enableCrypto('tls', 'client');
+ }
+
+/**
+ * testEnableCryptoExceptionDisableTwice
+ *
+ * @expectedException SocketException
+ * @return void
+ */
+ public function testEnableCryptoExceptionDisableTwice() {
+ // testing on tls server
+ $this->_connectSocketToSslTls();
+ $this->Socket->enableCrypto('tls', 'client', false);
+ }
+
+/**
+ * testEnableCryptoEnableStatus
+ *
+ * @return void
+ */
+ public function testEnableCryptoEnableStatus() {
+ // testing on tls server
+ $this->_connectSocketToSslTls();
+ $this->assertFalse($this->Socket->encrypted);
+ $this->Socket->enableCrypto('tls', 'client', true);
+ $this->assertTrue($this->Socket->encrypted);
+ }
+
+/**
+ * test getting the context for a socket.
+ *
+ * @return void
+ */
+ public function testGetContext() {
+ $this->skipIf(!extension_loaded('openssl'), 'OpenSSL is not enabled cannot test SSL.');
+ $config = array(
+ 'host' => 'smtp.gmail.com',
+ 'port' => 465,
+ 'timeout' => 5,
+ 'context' => array(
+ 'ssl' => array('capture_peer' => true)
+ )
+ );
+ $this->Socket = new CakeSocket($config);
+ $this->Socket->connect();
+ $result = $this->Socket->context();
+ $this->assertEquals($config['context'], $result);
+ }
+
}
diff --git a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php
index 27e593f66..575b6b082 100644
--- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php
+++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php
@@ -644,13 +644,20 @@ class CakeEmailTest extends CakeTestCase {
*/
public function testAttachments() {
$this->CakeEmail->attachments(CAKE . 'basics.php');
- $expected = array('basics.php' => array('file' => CAKE . 'basics.php', 'mimetype' => 'application/octet-stream'));
+ $expected = array(
+ 'basics.php' => array(
+ 'file' => CAKE . 'basics.php',
+ 'mimetype' => 'application/octet-stream'
+ )
+ );
$this->assertSame($this->CakeEmail->attachments(), $expected);
$this->CakeEmail->attachments(array());
$this->assertSame($this->CakeEmail->attachments(), array());
- $this->CakeEmail->attachments(array(array('file' => CAKE . 'basics.php', 'mimetype' => 'text/plain')));
+ $this->CakeEmail->attachments(array(
+ array('file' => CAKE . 'basics.php', 'mimetype' => 'text/plain')
+ ));
$this->CakeEmail->addAttachments(CAKE . 'bootstrap.php');
$this->CakeEmail->addAttachments(array(CAKE . 'bootstrap.php'));
$this->CakeEmail->addAttachments(array('other.txt' => CAKE . 'bootstrap.php', 'license' => CAKE . 'LICENSE.txt'));
@@ -941,6 +948,43 @@ class CakeEmailTest extends CakeTestCase {
$this->assertContains('--' . $boundary . '--', $result['message']);
}
+/**
+ * Test disabling content-disposition.
+ *
+ * @return void
+ */
+ public function testSendWithNoContentDispositionAttachments() {
+ $this->CakeEmail->transport('debug');
+ $this->CakeEmail->from('cake@cakephp.org');
+ $this->CakeEmail->to('cake@cakephp.org');
+ $this->CakeEmail->subject('My title');
+ $this->CakeEmail->emailFormat('text');
+ $this->CakeEmail->attachments(array(
+ 'cake.png' => array(
+ 'file' => CAKE . 'VERSION.txt',
+ 'contentDisposition' => false
+ )
+ ));
+ $result = $this->CakeEmail->send('Hello');
+
+ $boundary = $this->CakeEmail->getBoundary();
+ $this->assertContains('Content-Type: multipart/mixed; boundary="' . $boundary . '"', $result['headers']);
+ $expected = "--$boundary\r\n" .
+ "Content-Type: text/plain; charset=UTF-8\r\n" .
+ "Content-Transfer-Encoding: 8bit\r\n" .
+ "\r\n" .
+ "Hello" .
+ "\r\n" .
+ "\r\n" .
+ "\r\n" .
+ "--{$boundary}\r\n" .
+ "Content-Type: application/octet-stream\r\n" .
+ "Content-Transfer-Encoding: base64\r\n" .
+ "\r\n";
+
+ $this->assertContains($expected, $result['message']);
+ $this->assertContains('--' . $boundary . '--', $result['message']);
+ }
/**
* testSendWithLog method
*
@@ -1124,7 +1168,7 @@ class CakeEmailTest extends CakeTestCase {
$this->CakeEmail->emailFormat('html');
$server = env('SERVER_NAME') ? env('SERVER_NAME') : 'localhost';
- if (env('SERVER_PORT') != null && env('SERVER_PORT') != 80) {
+ if (env('SERVER_PORT') && env('SERVER_PORT') != 80) {
$server .= ':' . env('SERVER_PORT');
}
diff --git a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php
index 0310e5320..53b213a38 100644
--- a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php
+++ b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php
@@ -81,7 +81,7 @@ class SmtpTransportTest extends CakeTestCase {
*/
public function setUp() {
if (!class_exists('MockSocket')) {
- $this->getMock('CakeSocket', array('read', 'write', 'connect'), array(), 'MockSocket');
+ $this->getMock('CakeSocket', array('read', 'write', 'connect', 'enableCrypto'), array(), 'MockSocket');
}
$this->socket = new MockSocket();
@@ -105,6 +105,70 @@ class SmtpTransportTest extends CakeTestCase {
$this->SmtpTransport->connect();
}
+/**
+ * testConnectEhloTls method
+ *
+ * @return void
+ */
+ public function testConnectEhloTls() {
+ $this->SmtpTransport->config(array('tls' => true));
+ $this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
+ $this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
+ $this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
+ $this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
+ $this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n");
+ $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("220 Server ready\r\n"));
+ $this->socket->expects($this->at(8))->method('other')->with('tls')->will($this->returnValue(true));
+ $this->socket->expects($this->at(9))->method('write')->with("EHLO localhost\r\n");
+ $this->socket->expects($this->at(10))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(11))->method('read')->will($this->returnValue("250 Accepted\r\n"));
+ $this->SmtpTransport->connect();
+ }
+
+/**
+ * testConnectEhloTlsOnNonTlsServer method
+ *
+ * @expectedException SocketException
+ * @return void
+ */
+ public function testConnectEhloTlsOnNonTlsServer() {
+ $this->SmtpTransport->config(array('tls' => true));
+ $this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
+ $this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
+ $this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
+ $this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
+ $this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n");
+ $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("500 5.3.3 Unrecognized command\r\n"));
+ $this->SmtpTransport->connect();
+ }
+
+/**
+ * testConnectEhloNoTlsOnRequiredTlsServer method
+ *
+ * @expectedException SocketException
+ * @return void
+ */
+ public function testConnectEhloNoTlsOnRequiredTlsServer() {
+ $this->SmtpTransport->config(array('tls' => false, 'username' => 'user', 'password' => 'pass'));
+ $this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
+ $this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
+ $this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
+ $this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
+ $this->socket->expects($this->at(5))->method('read')->with("AUTH LOGIN\r\n");
+ $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
+ $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("504 5.7.4 Unrecognized authentication type\r\n"));
+ $this->SmtpTransport->connect();
+ $this->SmtpTransport->auth();
+ }
+
/**
* testConnectHelo method
*
diff --git a/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php b/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php
index 3fc70d742..c0f2ba33b 100644
--- a/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php
+++ b/lib/Cake/Test/Case/Network/Http/HttpSocketTest.php
@@ -253,6 +253,9 @@ class HttpSocketTest extends CakeTestCase {
'protocol' => 'tcp',
'port' => 23,
'timeout' => 30,
+ 'ssl_verify_peer' => true,
+ 'ssl_verify_depth' => 5,
+ 'ssl_verify_host' => true,
'request' => array(
'uri' => array(
'scheme' => 'https',
@@ -260,7 +263,7 @@ class HttpSocketTest extends CakeTestCase {
'port' => 23
),
'redirect' => false,
- 'cookies' => array()
+ 'cookies' => array(),
)
);
$this->assertEquals($expected, $this->Socket->config);
@@ -278,6 +281,9 @@ class HttpSocketTest extends CakeTestCase {
'protocol' => 'tcp',
'port' => 80,
'timeout' => 30,
+ 'ssl_verify_peer' => true,
+ 'ssl_verify_depth' => 5,
+ 'ssl_verify_host' => true,
'request' => array(
'uri' => array(
'scheme' => 'http',
@@ -285,7 +291,7 @@ class HttpSocketTest extends CakeTestCase {
'port' => 80
),
'redirect' => false,
- 'cookies' => array()
+ 'cookies' => array(),
)
);
$this->assertEquals($expected, $this->Socket->config);
@@ -311,6 +317,15 @@ class HttpSocketTest extends CakeTestCase {
$response = $this->Socket->request(true);
$this->assertFalse($response);
+ $context = array(
+ 'ssl' => array(
+ 'verify_peer' => true,
+ 'verify_depth' => 5,
+ 'CN_match' => 'www.cakephp.org',
+ 'cafile' => CAKE . 'Config' . DS . 'cacert.pem'
+ )
+ );
+
$tests = array(
array(
'request' => 'http://www.cakephp.org/?foo=bar',
@@ -321,6 +336,7 @@ class HttpSocketTest extends CakeTestCase {
'protocol' => 'tcp',
'port' => 80,
'timeout' => 30,
+ 'context' => $context,
'request' => array(
'uri' => array(
'scheme' => 'http',
@@ -1668,4 +1684,38 @@ class HttpSocketTest extends CakeTestCase {
}
$this->assertEquals(true, $return);
}
+
+/**
+ * test configuring the context from the flat keys.
+ *
+ * @return void
+ */
+ public function testConfigContext() {
+ $this->Socket->reset();
+ $this->Socket->request('http://example.com');
+ $this->assertTrue($this->Socket->config['context']['ssl']['verify_peer']);
+ $this->assertEquals(5, $this->Socket->config['context']['ssl']['verify_depth']);
+ $this->assertEquals('example.com', $this->Socket->config['context']['ssl']['CN_match']);
+ $this->assertArrayNotHasKey('ssl_verify_peer', $this->Socket->config);
+ $this->assertArrayNotHasKey('ssl_verify_host', $this->Socket->config);
+ $this->assertArrayNotHasKey('ssl_verify_depth', $this->Socket->config);
+ }
+
+/**
+ * Test that requests fail when peer verification fails.
+ *
+ * @return void
+ */
+ public function testVerifyPeer() {
+ $this->skipIf(!extension_loaded('openssl'), 'OpenSSL is not enabled cannot test SSL.');
+ $socket = new HttpSocket();
+ try {
+ $result = $socket->get('https://typography.com');
+ $this->markTestSkipped('Found valid certificate, was expecting invalid certificate.');
+ } catch (SocketException $e) {
+ $message = $e->getMessage();
+ $this->assertContains('Peer certificate CN', $message);
+ $this->assertContains('Failed to enable crypto', $message);
+ }
+ }
}
diff --git a/lib/Cake/Test/Case/Routing/RouterTest.php b/lib/Cake/Test/Case/Routing/RouterTest.php
index 65e1ed7a9..b1be402d5 100644
--- a/lib/Cake/Test/Case/Routing/RouterTest.php
+++ b/lib/Cake/Test/Case/Routing/RouterTest.php
@@ -484,7 +484,7 @@ class RouterTest extends CakeTestCase {
$result = Router::url(array('controller' => 'tests', 'pages' => array(
1, 2, 3
)));
- $expected = '/tests/index/pages[0]:1/pages[1]:2/pages[2]:3';
+ $expected = '/tests/index/pages%5B0%5D:1/pages%5B1%5D:2/pages%5B2%5D:3';
$this->assertEquals($expected, $result);
$result = Router::url(array('controller' => 'tests',
@@ -496,7 +496,7 @@ class RouterTest extends CakeTestCase {
'three'
)
));
- $expected = '/tests/index/pages[param1][0]:one/pages[param1][1]:two/pages[0]:three';
+ $expected = '/tests/index/pages%5Bparam1%5D%5B0%5D:one/pages%5Bparam1%5D%5B1%5D:two/pages%5B0%5D:three';
$this->assertEquals($expected, $result);
$result = Router::url(array('controller' => 'tests',
@@ -508,7 +508,7 @@ class RouterTest extends CakeTestCase {
'three'
)
));
- $expected = '/tests/index/pages[param1][one]:1/pages[param1][two]:2/pages[0]:three';
+ $expected = '/tests/index/pages%5Bparam1%5D%5Bone%5D:1/pages%5Bparam1%5D%5Btwo%5D:2/pages%5B0%5D:three';
$this->assertEquals($expected, $result);
$result = Router::url(array('controller' => 'tests',
@@ -520,14 +520,14 @@ class RouterTest extends CakeTestCase {
'cool'
)
));
- $expected = '/tests/index/super[nested][array]:awesome/super[nested][something]:else/super[0]:cool';
+ $expected = '/tests/index/super%5Bnested%5D%5Barray%5D:awesome/super%5Bnested%5D%5Bsomething%5D:else/super%5B0%5D:cool';
$this->assertEquals($expected, $result);
$result = Router::url(array('controller' => 'tests', 'namedParam' => array(
'keyed' => 'is an array',
'test'
)));
- $expected = '/tests/index/namedParam[keyed]:is%20an%20array/namedParam[0]:test';
+ $expected = '/tests/index/namedParam%5Bkeyed%5D:is%20an%20array/namedParam%5B0%5D:test';
$this->assertEquals($expected, $result);
}
@@ -2306,6 +2306,26 @@ class RouterTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * test using custom route class in PluginDot notation
+ */
+ public function testUsingCustomRouteClassPluginDotSyntax() {
+ App::build(array(
+ 'Plugin' => array(
+ CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
+ )
+ ));
+ CakePlugin::load('TestPlugin');
+ App::uses('TestRoute', 'TestPlugin.Routing/Route');
+ $routes = Router::connect(
+ '/:slug',
+ array('controller' => 'posts', 'action' => 'view'),
+ array('routeClass' => 'TestPlugin.TestRoute', 'slug' => '[a-z_-]+')
+ );
+ $this->assertInstanceOf('TestRoute', $routes[0]);
+ CakePlugin::unload('TestPlugin');
+ }
+
/**
* test that route classes must extend CakeRoute
*
@@ -2319,9 +2339,13 @@ class RouterTest extends CakeTestCase {
/**
* test reversing parameter arrays back into strings.
*
+ * Mark the router as initialized so it doesn't auto-load routes
+ *
* @return void
*/
public function testRouterReverse() {
+ Router::$initialized = true;
+
$params = array(
'controller' => 'posts',
'action' => 'view',
@@ -2508,6 +2532,15 @@ class RouterTest extends CakeTestCase {
$url = '://example.com';
$this->assertEquals($url, Router::url($url));
+
+ $url = 'javascript:void(0)';
+ $this->assertEquals($url, Router::url($url));
+
+ $url = 'tel:012345-678';
+ $this->assertEquals($url, Router::url($url));
+
+ $url = 'sms:012345-678';
+ $this->assertEquals($url, Router::url($url));
}
/**
diff --git a/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php b/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php
index 9a25b4939..78617881e 100644
--- a/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php
+++ b/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php
@@ -61,7 +61,7 @@ class CakeTestSuiteTest extends CakeTestCase {
* @return void
*/
public function testAddTestDirectoryRecursiveWithHidden() {
- $this->skipIf(!is_writeable(TMP), 'Cant addTestDirectoryRecursiveWithHidden unless the tmp folder is writable.');
+ $this->skipIf(!is_writable(TMP), 'Cant addTestDirectoryRecursiveWithHidden unless the tmp folder is writable.');
$Folder = new Folder(TMP . 'MyTestFolder', true, 0777);
mkdir($Folder->path . DS . '.svn', 0777, true);
@@ -85,7 +85,7 @@ class CakeTestSuiteTest extends CakeTestCase {
* @return void
*/
public function testAddTestDirectoryRecursiveWithNonPhp() {
- $this->skipIf(!is_writeable(TMP), 'Cant addTestDirectoryRecursiveWithNonPhp unless the tmp folder is writable.');
+ $this->skipIf(!is_writable(TMP), 'Cant addTestDirectoryRecursiveWithNonPhp unless the tmp folder is writable.');
$Folder = new Folder(TMP . 'MyTestFolder', true, 0777);
touch($Folder->path . DS . 'BackupTest.php~');
diff --git a/lib/Cake/Test/Case/Utility/CakeNumberTest.php b/lib/Cake/Test/Case/Utility/CakeNumberTest.php
index bcae41d85..9a28eb8bf 100644
--- a/lib/Cake/Test/Case/Utility/CakeNumberTest.php
+++ b/lib/Cake/Test/Case/Utility/CakeNumberTest.php
@@ -70,6 +70,56 @@ class CakeNumberTest extends CakeTestCase {
$result = $this->Number->format($value, '-');
$expected = '100-100-100';
$this->assertEquals($expected, $result);
+
+ $value = 0.00001;
+ $result = $this->Number->format($value, array('places' => 1));
+ $expected = '$0.0';
+ $this->assertEquals($expected, $result);
+
+ $value = -0.00001;
+ $result = $this->Number->format($value, array('places' => 1));
+ $expected = '$0.0';
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testFormatDelta method
+ *
+ * @return void
+ */
+ public function testFormatDelta() {
+ $value = '100100100';
+
+ $result = $this->Number->formatDelta($value);
+ $expected = '+100,100,100.00';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Number->formatDelta($value, array('before' => '', 'after' => ''));
+ $expected = '+100,100,100.00';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Number->formatDelta($value, array('before' => '[', 'after' => ']'));
+ $expected = '[+100,100,100.00]';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Number->formatDelta(-$value, array('before' => '[', 'after' => ']'));
+ $expected = '[-100,100,100.00]';
+ $this->assertEquals($expected, $result);
+
+ $value = 0;
+ $result = $this->Number->formatDelta($value, array('places' => 1, 'before' => '[', 'after' => ']'));
+ $expected = '[0.0]';
+ $this->assertEquals($expected, $result);
+
+ $value = 0.0001;
+ $result = $this->Number->formatDelta($value, array('places' => 1, 'before' => '[', 'after' => ']'));
+ $expected = '[0.0]';
+ $this->assertEquals($expected, $result);
+
+ $value = 9876.1234;
+ $result = $this->Number->formatDelta($value, array('places' => 1, 'decimals' => ',', 'thousands' => '.'));
+ $expected = '+9.876,1';
+ $this->assertEquals($expected, $result);
}
/**
@@ -231,6 +281,39 @@ class CakeNumberTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * Test default currency
+ *
+ * @return void
+ */
+ public function testDefaultCurrency() {
+ $result = $this->Number->defaultCurrency();
+ $this->assertEquals('USD', $result);
+ $this->Number->addFormat('NOK', array('before' => 'Kr. '));
+
+ $this->Number->defaultCurrency('NOK');
+ $result = $this->Number->defaultCurrency();
+ $this->assertEquals('NOK', $result);
+
+ $result = $this->Number->currency(1000);
+ $expected = 'Kr. 1,000.00';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Number->currency(2000);
+ $expected = 'Kr. 2,000.00';
+ $this->assertEquals($expected, $result);
+ $this->Number->defaultCurrency('EUR');
+ $result = $this->Number->currency(1000);
+ $expected = '€1.000,00';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Number->currency(2000);
+ $expected = '€2.000,00';
+ $this->assertEquals($expected, $result);
+
+ $this->Number->defaultCurrency('USD');
+ }
+
/**
* testCurrencyPositive method
*
@@ -523,4 +606,45 @@ class CakeNumberTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
+/**
+ * testFromReadableSize
+ *
+ * @dataProvider filesizes
+ * @return void
+ */
+ public function testFromReadableSize($params, $expected) {
+ $result = $this->Number->fromReadableSize($params['size'], $params['default']);
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testFromReadableSize
+ *
+ * @expectedException CakeException
+ * @return void
+ */
+ public function testFromReadableSizeException() {
+ $result = $this->Number->fromReadableSize('bogus', false);
+ }
+
+/**
+ * filesizes dataprovider
+ *
+ * @return array
+ */
+ public function filesizes() {
+ return array(
+ array(array('size' => '512B', 'default' => false), 512),
+ array(array('size' => '1KB', 'default' => false), 1024),
+ array(array('size' => '1.5KB', 'default' => false), 1536),
+ array(array('size' => '1MB', 'default' => false), 1048576),
+ array(array('size' => '1mb', 'default' => false), 1048576),
+ array(array('size' => '1.5MB', 'default' => false), 1572864),
+ array(array('size' => '1GB', 'default' => false), 1073741824),
+ array(array('size' => '1.5GB', 'default' => false), 1610612736),
+ array(array('size' => '512', 'default' => 'Unknown type'), 512),
+ array(array('size' => '2VB', 'default' => 'Unknown type'), 'Unknown type')
+ );
+ }
+
}
diff --git a/lib/Cake/Test/Case/Utility/DebuggerTest.php b/lib/Cake/Test/Case/Utility/DebuggerTest.php
index 8040073c3..bb1416f78 100644
--- a/lib/Cake/Test/Case/Utility/DebuggerTest.php
+++ b/lib/Cake/Test/Case/Utility/DebuggerTest.php
@@ -325,10 +325,45 @@ object(View) {
request => object(CakeRequest) {}
response => object(CakeResponse) {}
elementCache => 'default'
+ elementCacheSettings => array()
int => (int) 2
float => (float) 1.333
+
+TEXT;
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+ $expected .= << array(
+ (int) 0 => 'viewVars',
+ (int) 1 => 'autoLayout',
+ (int) 2 => 'ext',
+ (int) 3 => 'helpers',
+ (int) 4 => 'view',
+ (int) 5 => 'layout',
+ (int) 6 => 'name',
+ (int) 7 => 'theme',
+ (int) 8 => 'layoutPath',
+ (int) 9 => 'viewPath',
+ (int) 10 => 'request',
+ (int) 11 => 'plugin',
+ (int) 12 => 'passedArgs',
+ (int) 13 => 'cacheAction'
+ )
+ [protected] _scripts => array()
+ [protected] _paths => array()
+ [protected] _helpersLoaded => false
+ [protected] _parents => array()
+ [protected] _current => null
+ [protected] _currentType => ''
+ [protected] _stack => array()
+ [protected] _eventManager => object(CakeEventManager) {}
+ [protected] _eventManagerConfigured => false
+
+TEXT;
+ }
+ $expected .= <<assertTextEquals($expected, $result);
$data = array(
@@ -356,6 +391,13 @@ array(
[maximum depth reached]
)
)
+TEXT;
+ $this->assertTextEquals($expected, $result);
+
+ $data = false;
+ $result = Debugger::exportVar($data);
+ $expected = <<assertTextEquals($expected, $result);
}
diff --git a/lib/Cake/Test/Case/Utility/FolderTest.php b/lib/Cake/Test/Case/Utility/FolderTest.php
index 76ee08af4..69faff367 100644
--- a/lib/Cake/Test/Case/Utility/FolderTest.php
+++ b/lib/Cake/Test/Case/Utility/FolderTest.php
@@ -29,11 +29,16 @@ class FolderTest extends CakeTestCase {
protected static $_tmp = array();
/**
- * Save the directory names in TMP
+ * Save the directory names in TMP and make sure default directories exist
*
* @return void
*/
public static function setUpBeforeClass() {
+ $dirs = array('cache', 'logs', 'sessions', 'tests');
+ foreach ($dirs as $dir) {
+ new Folder(TMP . $dir, true);
+ }
+
foreach (scandir(TMP) as $file) {
if (is_dir(TMP . $file) && !in_array($file, array('.', '..'))) {
self::$_tmp[] = $file;
@@ -369,7 +374,7 @@ class FolderTest extends CakeTestCase {
* @return void
*/
public function testFolderReadWithHiddenFiles() {
- $this->skipIf(!is_writeable(TMP), 'Cant test Folder::read with hidden files unless the tmp folder is writable.');
+ $this->skipIf(!is_writable(TMP), 'Cant test Folder::read with hidden files unless the tmp folder is writable.');
$Folder = new Folder(TMP . 'folder_tree_hidden', true, 0777);
mkdir($Folder->path . DS . '.svn');
@@ -452,7 +457,7 @@ class FolderTest extends CakeTestCase {
* @return void
*/
public function testFolderTreeWithHiddenFiles() {
- $this->skipIf(!is_writeable(TMP), 'Can\'t test Folder::tree with hidden files unless the tmp folder is writable.');
+ $this->skipIf(!is_writable(TMP), 'Can\'t test Folder::tree with hidden files unless the tmp folder is writable.');
$Folder = new Folder(TMP . 'folder_tree_hidden', true, 0777);
mkdir($Folder->path . DS . '.svn', 0777, true);
@@ -635,7 +640,7 @@ class FolderTest extends CakeTestCase {
$this->assertSame(array_diff($expected, $result), array());
$result = $Folder->find('.*', true);
- $expected = array('config.php', 'routes.php');
+ $expected = array('cacert.pem', 'config.php', 'routes.php');
$this->assertSame($expected, $result);
$result = $Folder->find('.*\.php');
@@ -761,6 +766,55 @@ class FolderTest extends CakeTestCase {
$Folder->delete($Folder->pwd() . 'config_non_existent');
}
+/**
+ * test that errors and messages can be resetted
+ *
+ * @return void
+ */
+ public function testReset() {
+ $path = TMP . 'folder_delete_test';
+ mkdir($path);
+ $folder = $path . DS . 'sub';
+ mkdir($folder);
+ $file = $folder . DS . 'file';
+ touch($file);
+
+ chmod($folder, 0555);
+ chmod($file, 0444);
+
+ $Folder = new Folder($folder);
+ $return = $Folder->delete();
+ $this->assertFalse($return);
+
+ $messages = $Folder->messages();
+ $errors = $Folder->errors();
+ $expected = array(
+ $file . ' NOT removed',
+ $folder . ' NOT removed',
+ );
+ sort($expected);
+ sort($errors);
+ $this->assertEmpty($messages);
+ $this->assertEquals($expected, $errors);
+
+ chmod($file, 0644);
+ chmod($folder, 0755);
+
+ $return = $Folder->delete();
+ $this->assertTrue($return);
+
+ $messages = $Folder->messages();
+ $errors = $Folder->errors();
+ $expected = array(
+ $file . ' removed',
+ $folder . ' removed',
+ );
+ sort($expected);
+ sort($messages);
+ $this->assertEmpty($errors);
+ $this->assertEquals($expected, $messages);
+ }
+
/**
* testDelete method
*
@@ -803,6 +857,64 @@ class FolderTest extends CakeTestCase {
/**
* testCopy method
*
+ * Verify that subdirectories existing in both destination and source directory
+ * are merged recursively.
+ *
+ * @return void
+ */
+ public function testCopy() {
+ extract($this->_setupFilesystem());
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->copy($folderThree);
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+
+ $Folder = new Folder($folderTwo);
+ $result = $Folder->copy($folderThree);
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'file2.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderB' . DS . 'fileB.php'));
+
+ $Folder = new Folder($path);
+ $Folder->delete();
+ }
+
+/**
+ * testCopyWithMerge method
+ *
+ * Verify that subdirectories existing in both destination and source directory
+ * are merged recursively.
+ *
+ * @return void
+ */
+ public function testCopyWithMerge() {
+ extract($this->_setupFilesystem());
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->copy($folderThree);
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+
+ $Folder = new Folder($folderTwo);
+ $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::MERGE));
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'file2.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderB' . DS . 'fileB.php'));
+
+ $Folder = new Folder($path);
+ $Folder->delete();
+ }
+
+/**
+ * testCopyWithSkip method
+ *
* Verify that directories and files are copied recursively
* even if the destination directory already exists.
* Subdirectories existing in both destination and source directory
@@ -810,125 +922,251 @@ class FolderTest extends CakeTestCase {
*
* @return void
*/
- public function testCopy() {
- $path = TMP . 'folder_test';
- $folderOne = $path . DS . 'folder1';
- $folderTwo = $folderOne . DS . 'folder2';
- $folderThree = $path . DS . 'folder3';
- $fileOne = $folderOne . DS . 'file1.php';
- $fileTwo = $folderTwo . DS . 'file2.php';
+ public function testCopyWithSkip() {
+ extract($this->_setupFilesystem());
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->copy(array('to' => $folderTwo, 'scheme' => Folder::SKIP));
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php'));
+
+ $Folder = new Folder($folderTwo);
+ $Folder->delete();
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->copy(array('to' => $folderTwo, 'scheme' => Folder::SKIP));
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php'));
+
+ $Folder = new Folder($folderTwo);
+ $Folder->delete();
- new Folder($path, true);
- new Folder($folderOne, true);
new Folder($folderTwo, true);
- new Folder($folderThree, true);
- touch($fileOne);
- touch($fileTwo);
+ new Folder($folderTwo . DS . 'folderB', true);
+ file_put_contents($folderTwo . DS . 'file2.php', 'touched');
+ file_put_contents($folderTwo . DS . 'folderB' . DS . 'fileB.php', 'untouched');
- $Folder = new Folder($folderOne);
- $result = $Folder->copy($folderThree);
+ $Folder = new Folder($folderTwo);
+ $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::SKIP));
$this->assertTrue($result);
- $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
- $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php'));
-
- $Folder = new Folder($folderThree);
- $Folder->delete();
-
- $Folder = new Folder($folderOne);
- $result = $Folder->copy($folderThree);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
- $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php'));
-
- $Folder = new Folder($folderThree);
- $Folder->delete();
-
- new Folder($folderThree, true);
- new Folder($folderThree . DS . 'folder2', true);
- file_put_contents($folderThree . DS . 'folder2' . DS . 'file2.php', 'untouched');
-
- $Folder = new Folder($folderOne);
- $result = $Folder->copy($folderThree);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
- $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folder2' . DS . 'file2.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'file2.php'));
+ $this->assertEquals('touched', file_get_contents($folderThree . DS . 'file2.php'));
+ $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folderB' . DS . 'fileB.php'));
$Folder = new Folder($path);
$Folder->delete();
}
+/**
+ * testCopyWithOverwrite
+ *
+ * Verify that subdirectories existing in both destination and source directory
+ * are overwritten/replaced recursively.
+ *
+ * @return void
+ */
+ public function testCopyWithOverwrite() {
+ extract($this->_setupFilesystem());
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::OVERWRITE));
+
+ $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+
+ $Folder = new Folder($folderTwo);
+ $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::OVERWRITE));
+ $this->assertTrue($result);
+
+ $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+
+ $Folder = new Folder($folderOne);
+ unlink($fileOneA);
+ $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::OVERWRITE));
+ $this->assertTrue($result);
+
+ $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'file2.php'));
+ $this->assertTrue(!file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php'));
+ $this->assertTrue(file_exists($folderThree . DS . 'folderB' . DS . 'fileB.php'));
+
+ $Folder = new Folder($path);
+ $Folder->delete();
+ }
+
+/**
+ * Setup filesystem for copy tests
+ * $path: folder_test/
+ * - folder1/file1.php
+ * - folder1/folderA/fileA.php
+ * - folder2/file2.php
+ * - folder2/folderB/fileB.php
+ * - folder3/
+ *
+ * @return array Filenames to extract in the test methods
+ */
+ protected function _setupFilesystem() {
+ $path = TMP . 'folder_test';
+
+ $folderOne = $path . DS . 'folder1';
+ $folderOneA = $folderOne . DS . 'folderA';
+ $folderTwo = $path . DS . 'folder2';
+ $folderTwoB = $folderTwo . DS . 'folderB';
+ $folderThree = $path . DS . 'folder3';
+
+ $fileOne = $folderOne . DS . 'file1.php';
+ $fileTwo = $folderTwo . DS . 'file2.php';
+ $fileOneA = $folderOneA . DS . 'fileA.php';
+ $fileTwoB = $folderTwoB . DS . 'fileB.php';
+
+ new Folder($path, true);
+ new Folder($folderOne, true);
+ new Folder($folderOneA, true);
+ new Folder($folderTwo, true);
+ new Folder($folderTwoB, true);
+ new Folder($folderThree, true);
+ touch($fileOne);
+ touch($fileTwo);
+ touch($fileOneA);
+ touch($fileTwoB);
+
+ return compact(
+ 'path',
+ 'folderOne', 'folderOneA', 'folderTwo', 'folderTwoB', 'folderThree',
+ 'fileOne', 'fileOneA', 'fileTwo', 'fileTwoB');
+ }
+
/**
* testMove method
*
* Verify that directories and files are moved recursively
* even if the destination directory already exists.
* Subdirectories existing in both destination and source directory
- * are skipped and not merged or overwritten.
+ * are merged recursively.
*
* @return void
*/
public function testMove() {
- $path = TMP . 'folder_test';
- $folderOne = $path . DS . 'folder1';
- $folderTwo = $folderOne . DS . 'folder2';
- $folderThree = $path . DS . 'folder3';
- $fileOne = $folderOne . DS . 'file1.php';
- $fileTwo = $folderTwo . DS . 'file2.php';
-
- new Folder($path, true);
- new Folder($folderOne, true);
- new Folder($folderTwo, true);
- new Folder($folderThree, true);
- touch($fileOne);
- touch($fileTwo);
+ extract($this->_setupFilesystem());
$Folder = new Folder($folderOne);
- $result = $Folder->move($folderThree);
+ $result = $Folder->move($folderTwo);
$this->assertTrue($result);
- $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
- $this->assertTrue(is_dir($folderThree . DS . 'folder2'));
- $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertTrue(is_dir($folderTwo . DS . 'folderB'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'folderB' . DS . 'fileB.php'));
$this->assertFalse(file_exists($fileOne));
- $this->assertFalse(file_exists($folderTwo));
- $this->assertFalse(file_exists($fileTwo));
+ $this->assertTrue(file_exists($folderTwo . DS . 'folderA'));
+ $this->assertFalse(file_exists($folderOneA));
+ $this->assertFalse(file_exists($fileOneA));
- $Folder = new Folder($folderThree);
+ $Folder = new Folder($folderTwo);
$Folder->delete();
new Folder($folderOne, true);
- new Folder($folderTwo, true);
+ new Folder($folderOneA, true);
touch($fileOne);
- touch($fileTwo);
+ touch($fileOneA);
$Folder = new Folder($folderOne);
- $result = $Folder->move($folderThree);
+ $result = $Folder->move($folderTwo);
$this->assertTrue($result);
- $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
- $this->assertTrue(is_dir($folderThree . DS . 'folder2'));
- $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertTrue(is_dir($folderTwo . DS . 'folderA'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php'));
$this->assertFalse(file_exists($fileOne));
- $this->assertFalse(file_exists($folderTwo));
- $this->assertFalse(file_exists($fileTwo));
+ $this->assertFalse(file_exists($folderOneA));
+ $this->assertFalse(file_exists($fileOneA));
- $Folder = new Folder($folderThree);
+ $Folder = new Folder($folderTwo);
$Folder->delete();
new Folder($folderOne, true);
+ new Folder($folderOneA, true);
new Folder($folderTwo, true);
- new Folder($folderThree, true);
- new Folder($folderThree . DS . 'folder2', true);
+ new Folder($folderTwoB, true);
touch($fileOne);
- touch($fileTwo);
- file_put_contents($folderThree . DS . 'folder2' . DS . 'file2.php', 'untouched');
+ touch($fileOneA);
+ new Folder($folderOne . DS . 'folderB', true);
+ touch($folderOne . DS . 'folderB' . DS . 'fileB.php');
+ file_put_contents($folderTwoB . DS . 'fileB.php', 'untouched');
$Folder = new Folder($folderOne);
- $result = $Folder->move($folderThree);
+ $result = $Folder->move($folderTwo);
$this->assertTrue($result);
- $this->assertTrue(file_exists($folderThree . DS . 'file1.php'));
- $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folder2' . DS . 'file2.php'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertEquals('', file_get_contents($folderTwoB . DS . 'fileB.php'));
$this->assertFalse(file_exists($fileOne));
- $this->assertFalse(file_exists($folderTwo));
- $this->assertFalse(file_exists($fileTwo));
+ $this->assertFalse(file_exists($folderOneA));
+ $this->assertFalse(file_exists($fileOneA));
+
+ $Folder = new Folder($path);
+ $Folder->delete();
+ }
+
+/**
+ * testMoveWithSkip method
+ *
+ * Verify that directories and files are moved recursively
+ * even if the destination directory already exists.
+ * Subdirectories existing in both destination and source directory
+ * are skipped and not merged or overwritten.
+ *
+ * @return void
+ */
+ public function testMoveWithSkip() {
+ extract($this->_setupFilesystem());
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->move(array('to' => $folderTwo, 'scheme' => Folder::SKIP));
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertTrue(is_dir($folderTwo . DS . 'folderB'));
+ $this->assertTrue(file_exists($folderTwoB . DS . 'fileB.php'));
+ $this->assertFalse(file_exists($fileOne));
+ $this->assertFalse(file_exists($folderOneA));
+ $this->assertFalse(file_exists($fileOneA));
+
+ $Folder = new Folder($folderTwo);
+ $Folder->delete();
+
+ new Folder($folderOne, true);
+ new Folder($folderOneA, true);
+ new Folder($folderTwo, true);
+ touch($fileOne);
+ touch($fileOneA);
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->move(array('to' => $folderTwo, 'scheme' => Folder::SKIP));
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertTrue(is_dir($folderTwo . DS . 'folderA'));
+ $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php'));
+ $this->assertFalse(file_exists($fileOne));
+ $this->assertFalse(file_exists($folderOneA));
+ $this->assertFalse(file_exists($fileOneA));
+
+ $Folder = new Folder($folderTwo);
+ $Folder->delete();
+
+ new Folder($folderOne, true);
+ new Folder($folderOneA, true);
+ new Folder($folderTwo, true);
+ new Folder($folderTwoB, true);
+ touch($fileOne);
+ touch($fileOneA);
+ file_put_contents($folderTwoB . DS . 'fileB.php', 'untouched');
+
+ $Folder = new Folder($folderOne);
+ $result = $Folder->move(array('to' => $folderTwo, 'scheme' => Folder::SKIP));
+ $this->assertTrue($result);
+ $this->assertTrue(file_exists($folderTwo . DS . 'file1.php'));
+ $this->assertEquals('untouched', file_get_contents($folderTwoB . DS . 'fileB.php'));
+ $this->assertFalse(file_exists($fileOne));
+ $this->assertFalse(file_exists($folderOneA));
+ $this->assertFalse(file_exists($fileOneA));
$Folder = new Folder($path);
$Folder->delete();
diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php
index cb323d9dd..5c349adf5 100644
--- a/lib/Cake/Test/Case/Utility/SecurityTest.php
+++ b/lib/Cake/Test/Case/Utility/SecurityTest.php
@@ -1,9 +1,5 @@
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
@@ -12,7 +8,6 @@
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
- * @package Cake.Test.Case.Utility
* @since CakePHP(tm) v 1.2.0.5432
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
@@ -67,6 +62,45 @@ class SecurityTest extends CakeTestCase {
$this->assertTrue(Security::validateAuthKey($authKey));
}
+/**
+ * testHashInvalidSalt method
+ *
+ * @expectedException PHPUnit_Framework_Error
+ * @return void
+ */
+ public function testHashInvalidSalt() {
+ $result = Security::hash('someKey', 'blowfish', true);
+ }
+
+/**
+ * testHashAnotherInvalidSalt
+ *
+ * @expectedException PHPUnit_Framework_Error
+ * @return void
+ */
+ public function testHashAnotherInvalidSalt() {
+ $result = Security::hash('someKey', 'blowfish', '$1$lksdjoijfaoijs');
+ }
+
+/**
+ * testHashYetAnotherInvalidSalt
+ *
+ * @expectedException PHPUnit_Framework_Error
+ * @return void
+ */
+ public function testHashYetAnotherInvalidSalt() {
+ $result = Security::hash('someKey', 'blowfish', '$2a$10$123');
+ }
+
+/**
+ * testHashInvalidCost method
+ *
+ * @expectedException PHPUnit_Framework_Error
+ * @return void
+ */
+ public function testHashInvalidCost() {
+ Security::setCost(1000);
+ }
/**
* testHash method
*
@@ -115,6 +149,50 @@ class SecurityTest extends CakeTestCase {
Security::setHash($_hashType);
}
+/**
+ * Test that hash() works with blowfish.
+ *
+ * @return void
+ */
+ public function testHashBlowfish() {
+ Security::setCost(10);
+ $test = Security::hash('password', 'blowfish');
+ $this->skipIf(strpos($test, '$2a$') === false, 'Blowfish hashes are incorrect.');
+
+ $_hashType = Security::$hashType;
+
+ $key = 'someKey';
+ $hashType = 'blowfish';
+ Security::setHash($hashType);
+
+ $this->assertSame(Security::$hashType, $hashType);
+ $this->assertSame(strlen(Security::hash($key, null, false)), 60);
+
+ $password = $submittedPassword = $key;
+ $storedPassword = Security::hash($password);
+
+ $hashedPassword = Security::hash($submittedPassword, null, $storedPassword);
+ $this->assertSame($storedPassword, $hashedPassword);
+
+ $submittedPassword = 'someOtherKey';
+ $hashedPassword = Security::hash($submittedPassword, null, $storedPassword);
+ $this->assertNotSame($storedPassword, $hashedPassword);
+
+ $expected = sha1('customsaltsomevalue');
+ $result = Security::hash('somevalue', 'sha1', 'customsalt');
+ $this->assertSame($expected, $result);
+
+ $oldSalt = Configure::read('Security.salt');
+ Configure::write('Security.salt', 'customsalt');
+
+ $expected = sha1('customsaltsomevalue');
+ $result = Security::hash('somevalue', 'sha1', true);
+ $this->assertSame($expected, $result);
+
+ Configure::write('Security.salt', $oldSalt);
+ Security::setHash($_hashType);
+ }
+
/**
* testCipher method
*
@@ -164,6 +242,7 @@ class SecurityTest extends CakeTestCase {
* @return void
*/
public function testRijndael() {
+ $this->skipIf(!function_exists('mcrypt_encrypt'));
$txt = 'The quick brown fox jumped over the lazy dog.';
$key = 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi';
diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php
index efa024b5b..3072078fb 100644
--- a/lib/Cake/Test/Case/Utility/StringTest.php
+++ b/lib/Cake/Test/Case/Utility/StringTest.php
@@ -372,6 +372,7 @@ TEXT;
$text9 = 'ะะะะ ะกะขะฃะคะฅะฆะงะจะฉะชะซะฌะญะฎะฏะฐะฑะฒะณะดะตะถะทะธะนะบะปะผะฝะพะฟัััััั
ััััััั';
$text10 = 'http://example.com/something/foo:bar';
+ $elipsis = "\xe2\x80\xa6";
$this->assertSame($this->Text->truncate($text1, 15), 'The quick br...');
$this->assertSame($this->Text->truncate($text1, 15, array('exact' => false)), 'The quick...');
$this->assertSame($this->Text->truncate($text1, 100), 'The quick brown fox jumps over the lazy dog');
@@ -379,18 +380,18 @@ TEXT;
$this->assertSame($this->Text->truncate($text2, 10, array('exact' => false)), '...');
$this->assertSame($this->Text->truncate($text3, 20), '© 2005-20...');
$this->assertSame($this->Text->truncate($text4, 15), ' This image ...');
- $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!
But t...');
- $this->assertSame($this->Text->truncate($text4, 90, array('html' => true)), ' This image tag is not XHTML conform!
But the following image tag should be conform
Grea...');
- $this->assertSame($this->Text->truncate($text5, 6, array('ending' => '', 'html' => true)), '012345');
- $this->assertSame($this->Text->truncate($text5, 20, array('ending' => '', 'html' => true)), $text5);
- $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "Extra dates have been announced for this year's...
");
+ $this->assertSame($this->Text->truncate($text5, 6, array('ellipsis' => '')), '01<');
+ $this->assertSame($this->Text->truncate($text1, 15, array('html' => true)), 'The quick brow' . $elipsis);
+ $this->assertSame($this->Text->truncate($text1, 15, array('exact' => false, 'html' => true)), 'The quick' . $elipsis);
+ $this->assertSame($this->Text->truncate($text2, 10, array('html' => true)), 'Heizölrüc' . $elipsis);
+ $this->assertSame($this->Text->truncate($text2, 10, array('exact' => false, 'html' => true)), $elipsis);
+ $this->assertSame($this->Text->truncate($text3, 20, array('html' => true)), '© 2005-2007, Cake S' . $elipsis . '');
+ $this->assertSame($this->Text->truncate($text4, 15, array('html' => true)), ' This image ta' . $elipsis);
+ $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!
But the' . $elipsis . '');
+ $this->assertSame($this->Text->truncate($text4, 90, array('html' => true)), ' This image tag is not XHTML conform!
But the following image tag should be conform
Great,' . $elipsis);
+ $this->assertSame($this->Text->truncate($text5, 6, array('ellipsis' => '', 'html' => true)), '012345');
+ $this->assertSame($this->Text->truncate($text5, 20, array('ellipsis' => '', 'html' => true)), $text5);
+ $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "Extra dates have been announced for this year's" . $elipsis . "
");
$this->assertSame($this->Text->truncate($text7, 255), $text7);
$this->assertSame($this->Text->truncate($text7, 15), 'El moรฑo estรก...');
$this->assertSame($this->Text->truncate($text8, 15), 'Vive la R' . chr(195) . chr(169) . 'pu...');
@@ -399,7 +400,7 @@ TEXT;
$text = 'Iamatestwithnospacesandhtml
';
$result = $this->Text->truncate($text, 10, array(
- 'ending' => '...',
+ 'ellipsis' => '...',
'exact' => false,
'html' => true
));
@@ -422,7 +423,7 @@ podeรญs adquirirla.
http://www.amazon.com/Steve-
Jobs-Walter-Isaacson/dp/1451648537
';
$result = $this->Text->truncate($text, 500, array(
- 'ending' => '... ',
+ 'ellipsis' => '... ',
'exact' => false,
'html' => true
));
@@ -441,6 +442,88 @@ Isaacson", aquรญ os dejamos la direcciรณn de amazon donde
podeรญs adquirirla.
...
';
$this->assertEquals($expected, $result);
+
+ // test deprecated `ending` (`ellipsis` taking precedence if both are defined)
+ $result = $this->Text->truncate($text1, 31, array(
+ 'ending' => '.',
+ 'exact' => false,
+ ));
+ $expected = 'The quick brown fox jumps.';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Text->truncate($text1, 31, array(
+ 'ellipsis' => '..',
+ 'ending' => '.',
+ 'exact' => false,
+ ));
+ $expected = 'The quick brown fox jumps..';
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testTruncate method with non utf8 sites
+ *
+ * @return void
+ */
+ public function testTruncateLegacy() {
+ Configure::write('App.encoding', 'ISO-8859-1');
+ $text = '© 2005-2007, Cake Software Foundation, Inc.
written by Alexander Wegener';
+ $result = $this->Text->truncate($text, 31, array(
+ 'html' => true,
+ 'exact' => false,
+ ));
+ $expected = '© 2005-2007, Cake Software...';
+ $this->assertEquals($expected, $result);
+
+ $result = $this->Text->truncate($text, 31, array(
+ 'html' => true,
+ 'exact' => true,
+ ));
+ $expected = '© 2005-2007, Cake Software F...';
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testTail method
+ *
+ * @return void
+ */
+ public function testTail() {
+ $text1 = 'The quick brown fox jumps over the lazy dog';
+ $text2 = 'Heizölrückstoßabdämpfung';
+ $text3 = 'El moรฑo estรก en el lugar correcto. Eso fue lo que dijo la niรฑa, ยฟhabrรก dicho la verdad?';
+ $text4 = 'Vive la R' . chr(195) . chr(169) . 'publique de France';
+ $text5 = 'ะะะะ ะกะขะฃะคะฅะฆะงะจะฉะชะซะฌะญะฎะฏะฐะฑะฒะณะดะตะถะทะธะนะบะปะผะฝะพะฟัััััั
ััััััั';
+
+ $result = $this->Text->tail($text1, 13);
+ $this->assertEquals('...e lazy dog', $result);
+
+ $result = $this->Text->tail($text1, 13, array('exact' => false));
+ $this->assertEquals('...lazy dog', $result);
+
+ $result = $this->Text->tail($text1, 100);
+ $this->assertEquals('The quick brown fox jumps over the lazy dog', $result);
+
+ $result = $this->Text->tail($text2, 10);
+ $this->assertEquals('...;mpfung', $result);
+
+ $result = $this->Text->tail($text2, 10, array('exact' => false));
+ $this->assertEquals('...', $result);
+
+ $result = $this->Text->tail($text3, 255);
+ $this->assertEquals($text3, $result);
+
+ $result = $this->Text->tail($text3, 21);
+ $this->assertEquals('...รก dicho la verdad?', $result);
+
+ $result = $this->Text->tail($text4, 25);
+ $this->assertEquals('...a R' . chr(195) . chr(169) . 'publique de France', $result);
+
+ $result = $this->Text->tail($text5, 10);
+ $this->assertEquals('...ััััััั', $result);
+
+ $result = $this->Text->tail($text5, 6, array('ellipsis' => ''));
+ $this->assertEquals('ัััััั', $result);
}
/**
diff --git a/lib/Cake/Test/Case/Utility/ValidationTest.php b/lib/Cake/Test/Case/Utility/ValidationTest.php
index 22afee2c9..56f935a1b 100644
--- a/lib/Cake/Test/Case/Utility/ValidationTest.php
+++ b/lib/Cake/Test/Case/Utility/ValidationTest.php
@@ -2273,7 +2273,7 @@ class ValidationTest extends CakeTestCase {
}
/**
- * testMimeType method
+ * testUploadError method
*
* @return void
*/
@@ -2284,4 +2284,23 @@ class ValidationTest extends CakeTestCase {
$this->assertFalse(Validation::uploadError(2));
$this->assertFalse(Validation::uploadError(array('error' => 2)));
}
+
+/**
+ * testFileSize method
+ *
+ * @return void
+ */
+ public function testFileSize() {
+ $image = CORE_PATH . 'Cake' . DS . 'Test' . DS . 'test_app' . DS . 'webroot' . DS . 'img' . DS . 'cake.power.gif';
+ $this->assertTrue(Validation::fileSize($image, '<', 1024));
+ $this->assertTrue(Validation::fileSize(array('tmp_name' => $image), 'isless', 1024));
+ $this->assertTrue(Validation::fileSize($image, '<', '1KB'));
+ $this->assertTrue(Validation::fileSize($image, '>=', 200));
+ $this->assertTrue(Validation::fileSize($image, '==', 201));
+ $this->assertTrue(Validation::fileSize($image, '==', '201B'));
+
+ $this->assertFalse(Validation::fileSize($image, 'isgreater', 1024));
+ $this->assertFalse(Validation::fileSize(array('tmp_name' => $image), '>', '1KB'));
+ }
+
}
diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php
index 4549e48a0..ef9f057c6 100644
--- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php
+++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php
@@ -800,14 +800,32 @@ class FormHelperTest extends CakeTestCase {
$this->Form->request['_Token'] = array('key' => $key);
$result = $this->Form->secure($fields);
- $expected = Security::hash(serialize($fields) . Configure::read('Security.salt'));
- $expected .= ':' . 'Model.valid';
+ $hash = Security::hash(serialize($fields) . Configure::read('Security.salt'));
+ $hash .= ':' . 'Model.valid';
+ $hash = urlencode($hash);
$expected = array(
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
- 'value' => urlencode($expected), 'id' => 'preg:/TokenFields\d+/'
+ 'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
+ )),
+ array('input' => array(
+ 'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
+ 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/'
+ )),
+ '/div'
+ );
+ $this->assertTags($result, $expected);
+
+ $path = CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS;
+ $this->Form->Html->loadConfig('htmlhelper_tags', $path);
+ $result = $this->Form->secure($fields);
+ $expected = array(
+ 'div' => array('class' => 'hidden'),
+ array('input' => array(
+ 'type' => 'hidden', 'name' => 'data[_Token][fields]',
+ 'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
@@ -2402,6 +2420,78 @@ class FormHelperTest extends CakeTestCase {
}
}
+/**
+ * Test generating checkboxes with disabled elements.
+ *
+ * @return void
+ */
+ public function testInputCheckboxWithDisabledElements() {
+ $options = array(1 => 'One', 2 => 'Two', '3' => 'Three');
+ $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => 'disabled', 'options' => $options));
+
+ $expected = array(
+ array('div' => array('class' => 'input select')),
+ array('label' => array('for' => "ContactMultiple")),
+ 'Multiple',
+ '/label',
+ array('input' => array('type' => 'hidden', 'name' => "data[Contact][multiple]", 'value' => '', 'id' => "ContactMultiple")),
+ array('div' => array('class' => 'checkbox')),
+ array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 1, 'disabled' => 'disabled', 'id' => "ContactMultiple1")),
+ array('label' => array('for' => "ContactMultiple1")),
+ 'One',
+ '/label',
+ '/div',
+ array('div' => array('class' => 'checkbox')),
+ array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 2, 'disabled' => 'disabled', 'id' => "ContactMultiple2")),
+ array('label' => array('for' => "ContactMultiple2")),
+ 'Two',
+ '/label',
+ '/div',
+ array('div' => array('class' => 'checkbox')),
+ array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 3, 'disabled' => 'disabled', 'id' => "ContactMultiple3")),
+ array('label' => array('for' => "ContactMultiple3")),
+ 'Three',
+ '/label',
+ '/div',
+ '/div'
+ );
+ $this->assertTags($result, $expected);
+
+ $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => true, 'options' => $options));
+ $this->assertTags($result, $expected);
+
+ $disabled = array('2', 3);
+
+ $expected = array(
+ array('div' => array('class' => 'input select')),
+ array('label' => array('for' => "ContactMultiple")),
+ 'Multiple',
+ '/label',
+ array('input' => array('type' => 'hidden', 'name' => "data[Contact][multiple]", 'value' => '', 'id' => "ContactMultiple")),
+ array('div' => array('class' => 'checkbox')),
+ array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 1, 'id' => "ContactMultiple1")),
+ array('label' => array('for' => "ContactMultiple1")),
+ 'One',
+ '/label',
+ '/div',
+ array('div' => array('class' => 'checkbox')),
+ array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 2, 'disabled' => 'disabled', 'id' => "ContactMultiple2")),
+ array('label' => array('for' => "ContactMultiple2")),
+ 'Two',
+ '/label',
+ '/div',
+ array('div' => array('class' => 'checkbox')),
+ array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 3, 'disabled' => 'disabled', 'id' => "ContactMultiple3")),
+ array('label' => array('for' => "ContactMultiple3")),
+ 'Three',
+ '/label',
+ '/div',
+ '/div'
+ );
+ $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => $disabled, 'options' => $options));
+ $this->assertTags($result, $expected);
+ }
+
/**
* test input name with leading integer, ensure attributes are generated correctly.
*
@@ -6126,6 +6216,19 @@ class FormHelperTest extends CakeTestCase {
'/a'
));
+ $result = $this->Form->postLink('Delete', '/posts/delete/1', array('method' => 'delete'));
+ $this->assertTags($result, array(
+ 'form' => array(
+ 'method' => 'post', 'action' => '/posts/delete/1',
+ 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;'
+ ),
+ 'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'DELETE'),
+ '/form',
+ 'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'),
+ 'Delete',
+ '/a'
+ ));
+
$result = $this->Form->postLink('Delete', '/posts/delete/1', array(), 'Confirm?');
$this->assertTags($result, array(
'form' => array(
diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php
index 678a1df23..fcb299071 100644
--- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php
+++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php
@@ -337,6 +337,30 @@ class HtmlHelperTest extends CakeTestCase {
$result = $this->Html->link('http://www.example.org?param1=value1¶m2=value2');
$expected = array('a' => array('href' => 'http://www.example.org?param1=value1¶m2=value2'), 'http://www.example.org?param1=value1¶m2=value2', '/a');
$this->assertTags($result, $expected);
+
+ $result = $this->Html->link('alert', 'javascript:alert(\'cakephp\');');
+ $expected = array('a' => array('href' => 'javascript:alert('cakephp');'), 'alert', '/a');
+ $this->assertTags($result, $expected);
+
+ $result = $this->Html->link('write me', 'mailto:example@cakephp.org');
+ $expected = array('a' => array('href' => 'mailto:example@cakephp.org'), 'write me', '/a');
+ $this->assertTags($result, $expected);
+
+ $result = $this->Html->link('call me on 0123465-798', 'tel:0123465-798');
+ $expected = array('a' => array('href' => 'tel:0123465-798'), 'call me on 0123465-798', '/a');
+ $this->assertTags($result, $expected);
+
+ $result = $this->Html->link('text me on 0123465-798', 'sms:0123465-798');
+ $expected = array('a' => array('href' => 'sms:0123465-798'), 'text me on 0123465-798', '/a');
+ $this->assertTags($result, $expected);
+
+ $result = $this->Html->link('say hello to 0123465-798', 'sms:0123465-798?body=hello there');
+ $expected = array('a' => array('href' => 'sms:0123465-798?body=hello there'), 'say hello to 0123465-798', '/a');
+ $this->assertTags($result, $expected);
+
+ $result = $this->Html->link('say hello to 0123465-798', 'sms:0123465-798?body=hello "cakephp"');
+ $expected = array('a' => array('href' => 'sms:0123465-798?body=hello "cakephp"'), 'say hello to 0123465-798', '/a');
+ $this->assertTags($result, $expected);
}
/**
@@ -1839,7 +1863,8 @@ class HtmlHelperTest extends CakeTestCase {
$expected = array(
'tags' => array(
'form' => 'start form',
- 'formend' => 'finish form'
+ 'formend' => 'finish form',
+ 'hiddenblock' => '%s
'
)
);
$this->assertEquals($expected, $result);
diff --git a/lib/Cake/Test/Case/View/Helper/PaginatorHelperTest.php b/lib/Cake/Test/Case/View/Helper/PaginatorHelperTest.php
index fb8289f0c..a04467e2f 100644
--- a/lib/Cake/Test/Case/View/Helper/PaginatorHelperTest.php
+++ b/lib/Cake/Test/Case/View/Helper/PaginatorHelperTest.php
@@ -1436,6 +1436,28 @@ class PaginatorHelperTest extends CakeTestCase {
);
$this->assertTags($result, $expected);
+ $result = $this->Paginator->numbers(array('first' => 1, 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'a'));
+ $expected = array(
+ array('li' => array()), array('a' => array('href' => '/index/page:1')), '1', '/a', '/li',
+ ' | ',
+ array('li' => array('class' => 'active')), array('a' => array()), '2', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:3')), '3', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:4')), '4', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:5')), '5', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:6')), '6', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:7')), '7', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:8')), '8', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:9')), '9', '/a', '/li',
+ );
+ $this->assertTags($result, $expected);
+
$result = $this->Paginator->numbers(array('first' => 1, 'class' => 'page-link', 'currentClass' => 'active'));
$expected = array(
array('span' => array('class' => 'page-link')), array('a' => array('href' => '/index/page:1')), '1', '/a', '/span',
@@ -1668,6 +1690,16 @@ class PaginatorHelperTest extends CakeTestCase {
);
$this->assertTags($result, $expected);
+ $result = $this->Paginator->numbers(array('modulus' => 3, 'currentTag' => 'span', 'tag' => 'li'));
+ $expected = array(
+ array('li' => array('class' => 'current')), array('span' => array()), '1', '/span', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:2')), '2', '/a', '/li',
+ ' | ',
+ array('li' => array()), array('a' => array('href' => '/index/page:3')), '3', '/a', '/li',
+ );
+ $this->assertTags($result, $expected);
+
$this->Paginator->request->params['paging'] = array(
'Client' => array(
'page' => 2,
diff --git a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php
index 34e99576d..6595757c0 100644
--- a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php
+++ b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php
@@ -642,13 +642,12 @@ class RssHelperTest extends CakeTestCase {
)
);
$result = $this->Rss->item(null, $item);
- if (!function_exists('finfo_open') &&
- (function_exists('mime_content_type') && false === mime_content_type($tmpFile))
- ) {
- $type = false;
+ if (!function_exists('mime_content_type')) {
+ $type = null;
} else {
- $type = 'text/plain';
+ $type = mime_content_type($tmpFile);
}
+
$expected = array(
'- assertTags($result, $expected);
$File->delete();
diff --git a/lib/Cake/Test/Case/View/JsonViewTest.php b/lib/Cake/Test/Case/View/JsonViewTest.php
index 39a3e7a1d..ed2b04e4e 100644
--- a/lib/Cake/Test/Case/View/JsonViewTest.php
+++ b/lib/Cake/Test/Case/View/JsonViewTest.php
@@ -76,6 +76,7 @@ class JsonViewTest extends CakeTestCase {
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
));
$Request = new CakeRequest();
+ $Request->params['named'] = array('page' => 2);
$Response = new CakeResponse();
$Controller = new Controller($Request, $Response);
$Controller->name = $Controller->viewPath = 'Posts';
@@ -91,9 +92,10 @@ class JsonViewTest extends CakeTestCase {
);
$Controller->set('user', $data);
$View = new JsonView($Controller);
+ $View->helpers = array('Paginator');
$output = $View->render('index');
- $expected = json_encode(array('user' => 'fake', 'list' => array('item1', 'item2')));
+ $expected = json_encode(array('user' => 'fake', 'list' => array('item1', 'item2'), 'paging' => array('page' => 2)));
$this->assertSame($expected, $output);
$this->assertSame('application/json', $Response->type());
}
diff --git a/lib/Cake/Test/Case/View/MediaViewTest.php b/lib/Cake/Test/Case/View/MediaViewTest.php
index 8660a119b..8e787ea27 100644
--- a/lib/Cake/Test/Case/View/MediaViewTest.php
+++ b/lib/Cake/Test/Case/View/MediaViewTest.php
@@ -35,8 +35,15 @@ class MediaViewTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
- $this->MediaView = $this->getMock('MediaView', array('_isActive', '_clearBuffer', '_flushBuffer'));
- $this->MediaView->response = $this->getMock('CakeResponse');
+ $this->MediaView = new MediaView();
+ $this->MediaView->response = $this->getMock('CakeResponse', array(
+ '_isActive',
+ '_clearBuffer',
+ '_flushBuffer',
+ 'type',
+ 'header',
+ 'download'
+ ));
}
/**
@@ -71,10 +78,10 @@ class MediaViewTest extends CakeTestCase {
public function testRender() {
$this->MediaView->viewVars = array(
'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS,
- 'id' => 'test_asset.css',
- 'extension' => 'css',
+ 'id' => 'test_asset.css'
);
- $this->MediaView->expects($this->exactly(2))
+
+ $this->MediaView->response->expects($this->exactly(1))
->method('_isActive')
->will($this->returnValue(true));
@@ -83,28 +90,28 @@ class MediaViewTest extends CakeTestCase {
->with('css')
->will($this->returnArgument(0));
- $this->MediaView->response->expects($this->at(1))
+ $this->MediaView->response->expects($this->at(0))
->method('header')
->with(array(
- 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
- 'Expires' => '0',
- 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0',
- 'Pragma' => 'no-cache'
+ 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
+ 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
+ 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT'
));
$this->MediaView->response->expects($this->at(2))
->method('header')
- ->with(array(
- 'Content-Length' => 31
- ));
- $this->MediaView->response->expects($this->once())->method('send');
- $this->MediaView->expects($this->once())->method('_clearBuffer');
- $this->MediaView->expects($this->once())->method('_flushBuffer');
+ ->with('Content-Length', 38);
+
+ $this->MediaView->response->expects($this->once())->method('_clearBuffer');
+ $this->MediaView->response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+ $this->MediaView->response->expects($this->once())->method('_flushBuffer');
ob_start();
$result = $this->MediaView->render();
$output = ob_get_clean();
- $this->assertEquals('this is the test asset css file', $output);
+ $this->assertEquals("/* this is the test asset css file */\n", $output);
$this->assertTrue($result !== false);
}
@@ -118,28 +125,22 @@ class MediaViewTest extends CakeTestCase {
$_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
$this->MediaView->viewVars = array(
'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS,
- 'id' => 'no_section.ini',
- 'extension' => 'ini',
+ 'id' => 'no_section.ini'
);
- $this->MediaView->expects($this->exactly(2))
- ->method('_isActive')
- ->will($this->returnValue(true));
$this->MediaView->response->expects($this->exactly(1))
->method('type')
->with('ini')
->will($this->returnValue(false));
- $this->MediaView->response->expects($this->at(1))
+ $this->MediaView->response->expects($this->at(0))
->method('header')
->with($this->logicalAnd(
- $this->arrayHasKey('Date'),
+ $this->arrayHasKey('Last-Modified'),
$this->arrayHasKey('Expires'),
$this->arrayHasKey('Cache-Control'),
- $this->arrayHasKey('Pragma'),
- $this->contains('0'),
- $this->contains('private, must-revalidate, post-check=0, pre-check=0'),
- $this->contains('no-cache')
+ $this->contains('Mon, 26 Jul 1997 05:00:00 GMT'),
+ $this->contains('no-store, no-cache, must-revalidate, post-check=0, pre-check=0')
));
$this->MediaView->response->expects($this->once())
@@ -148,17 +149,17 @@ class MediaViewTest extends CakeTestCase {
$this->MediaView->response->expects($this->at(3))
->method('header')
- ->with(array(
- 'Accept-Ranges' => 'bytes'
- ));
+ ->with('Accept-Ranges', 'bytes');
$this->MediaView->response->expects($this->at(4))
->method('header')
->with('Content-Length', 35);
- $this->MediaView->response->expects($this->once())->method('send');
- $this->MediaView->expects($this->once())->method('_clearBuffer');
- $this->MediaView->expects($this->once())->method('_flushBuffer');
+ $this->MediaView->response->expects($this->once())->method('_clearBuffer');
+ $this->MediaView->response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+ $this->MediaView->response->expects($this->once())->method('_flushBuffer');
ob_start();
$result = $this->MediaView->render();
@@ -181,48 +182,43 @@ class MediaViewTest extends CakeTestCase {
$this->MediaView->viewVars = array(
'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS,
'id' => 'no_section.ini',
- 'extension' => 'ini',
);
- $this->MediaView->expects($this->exactly(2))
- ->method('_isActive')
- ->will($this->returnValue(true));
$this->MediaView->response->expects($this->at(0))
+ ->method('header')
+ ->with(array(
+ 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
+ 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
+ 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT'
+ ));
+
+ $this->MediaView->response->expects($this->at(1))
->method('type')
->with('ini')
->will($this->returnValue(false));
- $this->MediaView->response->expects($this->at(1))
- ->method('header')
- ->with(array(
- 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
- 'Expires' => '0',
- 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0',
- 'Pragma' => 'no-cache'
- ));
-
$this->MediaView->response->expects($this->at(2))
->method('type')
->with('application/octetstream')
->will($this->returnValue(false));
- $this->MediaView->response->expects($this->once())
+ $this->MediaView->response->expects($this->at(3))
->method('download')
->with('no_section.ini');
$this->MediaView->response->expects($this->at(4))
->method('header')
- ->with(array(
- 'Accept-Ranges' => 'bytes'
- ));
+ ->with('Accept-Ranges', 'bytes');
$this->MediaView->response->expects($this->at(5))
->method('header')
->with('Content-Length', 35);
- $this->MediaView->response->expects($this->once())->method('send');
- $this->MediaView->expects($this->once())->method('_clearBuffer');
- $this->MediaView->expects($this->once())->method('_flushBuffer');
+ $this->MediaView->response->expects($this->once())->method('_clearBuffer');
+ $this->MediaView->response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+ $this->MediaView->response->expects($this->once())->method('_flushBuffer');
ob_start();
$result = $this->MediaView->render();
@@ -245,49 +241,44 @@ class MediaViewTest extends CakeTestCase {
$this->MediaView->viewVars = array(
'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS,
'id' => 'no_section.ini',
- 'extension' => 'ini',
'name' => 'config'
);
- $this->MediaView->expects($this->exactly(2))
- ->method('_isActive')
- ->will($this->returnValue(true));
$this->MediaView->response->expects($this->at(0))
+ ->method('header')
+ ->with(array(
+ 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
+ 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
+ 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT'
+ ));
+
+ $this->MediaView->response->expects($this->at(1))
->method('type')
->with('ini')
->will($this->returnValue(false));
- $this->MediaView->response->expects($this->at(1))
- ->method('header')
- ->with(array(
- 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
- 'Expires' => '0',
- 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0',
- 'Pragma' => 'no-cache'
- ));
-
$this->MediaView->response->expects($this->at(2))
->method('type')
->with('application/force-download')
->will($this->returnValue(false));
- $this->MediaView->response->expects($this->once())
+ $this->MediaView->response->expects($this->at(3))
->method('download')
->with('config.ini');
$this->MediaView->response->expects($this->at(4))
->method('header')
- ->with(array(
- 'Accept-Ranges' => 'bytes'
- ));
+ ->with('Accept-Ranges', 'bytes');
$this->MediaView->response->expects($this->at(5))
->method('header')
->with('Content-Length', 35);
- $this->MediaView->response->expects($this->once())->method('send');
- $this->MediaView->expects($this->once())->method('_clearBuffer');
- $this->MediaView->expects($this->once())->method('_flushBuffer');
+ $this->MediaView->response->expects($this->once())->method('_clearBuffer');
+ $this->MediaView->response->expects($this->exactly(1))
+ ->method('_isActive')
+ ->will($this->returnValue(true));
+ $this->MediaView->response->expects($this->once())->method('_flushBuffer');
ob_start();
$result = $this->MediaView->render();
@@ -299,29 +290,6 @@ class MediaViewTest extends CakeTestCase {
}
}
-/**
- * testConnectionAborted method
- *
- * @return void
- */
- public function testConnectionAborted() {
- $this->MediaView->viewVars = array(
- 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS,
- 'id' => 'test_asset.css',
- 'extension' => 'css',
- );
-
- $this->MediaView->expects($this->once())
- ->method('_isActive')
- ->will($this->returnValue(false));
-
- $this->MediaView->response->expects($this->never())
- ->method('type');
-
- $result = $this->MediaView->render();
- $this->assertFalse($result);
- }
-
/**
* testConnectionAbortedOnBuffering method
*
@@ -330,29 +298,22 @@ class MediaViewTest extends CakeTestCase {
public function testConnectionAbortedOnBuffering() {
$this->MediaView->viewVars = array(
'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS,
- 'id' => 'test_asset.css',
- 'extension' => 'css',
+ 'id' => 'test_asset.css'
);
- $this->MediaView->expects($this->at(0))
- ->method('_isActive')
- ->will($this->returnValue(true));
-
$this->MediaView->response->expects($this->any())
->method('type')
->with('css')
->will($this->returnArgument(0));
- $this->MediaView->expects($this->at(1))
+ $this->MediaView->response->expects($this->at(1))
->method('_isActive')
->will($this->returnValue(false));
- $this->MediaView->response->expects($this->once())->method('send');
- $this->MediaView->expects($this->once())->method('_clearBuffer');
- $this->MediaView->expects($this->never())->method('_flushBuffer');
+ $this->MediaView->response->expects($this->once())->method('_clearBuffer');
+ $this->MediaView->response->expects($this->never())->method('_flushBuffer');
- $result = $this->MediaView->render();
- $this->assertFalse($result);
+ $this->MediaView->render();
}
/**
@@ -363,8 +324,7 @@ class MediaViewTest extends CakeTestCase {
public function testRenderUpperExtension() {
$this->MediaView->viewVars = array(
'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS,
- 'id' => 'test_2.JPG',
- 'extension' => 'JPG',
+ 'id' => 'test_2.JPG'
);
$this->MediaView->response->expects($this->any())
@@ -372,30 +332,7 @@ class MediaViewTest extends CakeTestCase {
->with('jpg')
->will($this->returnArgument(0));
- $this->MediaView->expects($this->at(0))
- ->method('_isActive')
- ->will($this->returnValue(true));
-
- $this->MediaView->render();
- }
-
-/**
- * Test downloading files with extension not explicitly set.
- *
- * @return void
- */
- public function testRenderExtensionNotSet() {
- $this->MediaView->viewVars = array(
- 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS,
- 'id' => 'test_2.JPG',
- );
-
- $this->MediaView->response->expects($this->any())
- ->method('type')
- ->with('jpg')
- ->will($this->returnArgument(0));
-
- $this->MediaView->expects($this->at(0))
+ $this->MediaView->response->expects($this->at(0))
->method('_isActive')
->will($this->returnValue(true));
diff --git a/lib/Cake/Test/Case/View/ViewTest.php b/lib/Cake/Test/Case/View/ViewTest.php
index 75875349d..cc8713dcd 100644
--- a/lib/Cake/Test/Case/View/ViewTest.php
+++ b/lib/Cake/Test/Case/View/ViewTest.php
@@ -662,7 +662,7 @@ class ViewTest extends CakeTestCase {
*
*/
public function testElementCallbacks() {
- $this->getMock('HtmlHelper', array(), array($this->View), 'ElementCallbackMockHtmlHelper');
+ $this->getMock('Helper', array(), array($this->View), 'ElementCallbackMockHtmlHelper');
$this->View->helpers = array('ElementCallbackMockHtml');
$this->View->loadHelpers();
@@ -726,13 +726,13 @@ class ViewTest extends CakeTestCase {
$expected = 'this is the test element';
$this->assertEquals($expected, $result);
- $result = Cache::read('element__test_element_cache', 'test_view');
+ $result = Cache::read('element__test_element_cache_callbacks', 'test_view');
$this->assertEquals($expected, $result);
$result = $View->element('test_element', array('param' => 'one', 'foo' => 'two'), array('cache' => true));
$this->assertEquals($expected, $result);
- $result = Cache::read('element__test_element_cache_param_foo', 'test_view');
+ $result = Cache::read('element__test_element_cache_callbacks_param_foo', 'test_view');
$this->assertEquals($expected, $result);
$result = $View->element('test_element', array(
@@ -751,7 +751,7 @@ class ViewTest extends CakeTestCase {
), array(
'cache' => array('config' => 'test_view'),
));
- $result = Cache::read('element__test_element_cache_param_foo', 'test_view');
+ $result = Cache::read('element__test_element_cache_callbacks_param_foo', 'test_view');
$this->assertEquals($expected, $result);
Cache::clear(true, 'test_view');
@@ -1258,6 +1258,19 @@ class ViewTest extends CakeTestCase {
$this->assertEquals('Block content', $result);
}
+/**
+ * Test prepending to a block with append.
+ *
+ * @return void
+ */
+ public function testBlockPrepend() {
+ $this->View->assign('test', 'Block');
+ $this->View->prepend('test', 'Before ');
+
+ $result = $this->View->fetch('test');
+ $this->assertEquals('Before Block', $result);
+ }
+
/**
* You should be able to append to undefined blocks.
*
@@ -1269,6 +1282,17 @@ class ViewTest extends CakeTestCase {
$this->assertEquals('Unknown', $result);
}
+/**
+ * You should be able to prepend to undefined blocks.
+ *
+ * @return void
+ */
+ public function testBlockPrependUndefined() {
+ $this->View->prepend('test', 'Unknown');
+ $result = $this->View->fetch('test');
+ $this->assertEquals('Unknown', $result);
+ }
+
/**
* setting an array should cause an exception.
*
@@ -1462,4 +1486,20 @@ TEXT;
$end = memory_get_usage();
$this->assertLessThanOrEqual($start + 5000, $end);
}
+
+/**
+ * tests that a vew block uses default value when not assigned and uses assigned value when it is
+ *
+ * @return void
+ */
+ public function testBlockDefaultValue() {
+ $default = 'Default';
+ $result = $this->View->fetch('title', $default);
+ $this->assertEquals($default, $result);
+
+ $expected = 'My Title';
+ $this->View->assign('title', $expected);
+ $result = $this->View->fetch('title', $default);
+ $this->assertEquals($expected, $result);
+ }
}
diff --git a/lib/Cake/Test/Case/View/XmlViewTest.php b/lib/Cake/Test/Case/View/XmlViewTest.php
index 44582e79a..f7697bdf0 100644
--- a/lib/Cake/Test/Case/View/XmlViewTest.php
+++ b/lib/Cake/Test/Case/View/XmlViewTest.php
@@ -64,6 +64,13 @@ class XmlViewTest extends CakeTestCase {
$expected = Xml::build(array('response' => array('users' => $data)))->asXML();
$this->assertSame($expected, $output);
+
+ $Controller->set('_rootNode', 'custom_name');
+ $View = new XmlView($Controller);
+ $output = $View->render(false);
+
+ $expected = Xml::build(array('custom_name' => array('users' => $data)))->asXML();
+ $this->assertSame($expected, $output);
}
/**
@@ -79,13 +86,20 @@ class XmlViewTest extends CakeTestCase {
$Controller->set($data);
$Controller->set('_serialize', array('no', 'user'));
$View = new XmlView($Controller);
+ $this->assertSame('application/xml', $Response->type());
$output = $View->render(false);
-
$expected = array(
'response' => array('no' => $data['no'], 'user' => $data['user'])
);
$this->assertSame(Xml::build($expected)->asXML(), $output);
- $this->assertSame('application/xml', $Response->type());
+
+ $Controller->set('_rootNode', 'custom_name');
+ $View = new XmlView($Controller);
+ $output = $View->render(false);
+ $expected = array(
+ 'custom_name' => array('no' => $data['no'], 'user' => $data['user'])
+ );
+ $this->assertSame(Xml::build($expected)->asXML(), $output);
}
/**
diff --git a/lib/Cake/Test/Fixture/CakeSessionFixture.php b/lib/Cake/Test/Fixture/CakeSessionFixture.php
new file mode 100644
index 000000000..5b7f43025
--- /dev/null
+++ b/lib/Cake/Test/Fixture/CakeSessionFixture.php
@@ -0,0 +1,47 @@
+
+ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice
+ *
+ * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
+ * @package Cake.Test.Fixture
+ * @since CakePHP(tm) v 2.3.0
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+/**
+ * Fixture class for the default session configuration
+ *
+ * @package Cake.Test.Fixture
+ */
+class CakeSessionFixture extends CakeTestFixture {
+
+/**
+ * name property
+ *
+ * @var string
+ */
+ public $name = 'CakeSession';
+
+/**
+ * fields property
+ *
+ * @var array
+ */
+ public $fields = array(
+ 'id' => array('type' => 'string', 'length' => 128, 'key' => 'primary'),
+ 'data' => array('type' => 'text','null' => true),
+ 'expires' => array('type' => 'integer', 'length' => 11, 'null' => true)
+ );
+
+/**
+ * records property
+ *
+ * @var array
+ */
+ public $records = array();
+}
diff --git a/lib/Cake/Test/Fixture/DatatypeFixture.php b/lib/Cake/Test/Fixture/DatatypeFixture.php
index 0a9f2e067..d583ce5d0 100644
--- a/lib/Cake/Test/Fixture/DatatypeFixture.php
+++ b/lib/Cake/Test/Fixture/DatatypeFixture.php
@@ -39,6 +39,7 @@ class DatatypeFixture extends CakeTestFixture {
public $fields = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
'float_field' => array('type' => 'float', 'length' => '5,2', 'null' => false, 'default' => null),
+ 'huge_int' => array('type' => 'biginteger'),
'bool' => array('type' => 'boolean', 'null' => false, 'default' => false),
);
@@ -48,6 +49,6 @@ class DatatypeFixture extends CakeTestFixture {
* @var array
*/
public $records = array(
- array('id' => 1, 'float_field' => 42.23, 'bool' => 0),
+ array('id' => 1, 'float_field' => 42.23, 'huge_int' => '1234567891234567891', 'bool' => 0),
);
}
diff --git a/lib/Cake/Test/test_app/Config/htmlhelper_tags.php b/lib/Cake/Test/test_app/Config/htmlhelper_tags.php
index abff9cdf5..850f26d12 100644
--- a/lib/Cake/Test/test_app/Config/htmlhelper_tags.php
+++ b/lib/Cake/Test/test_app/Config/htmlhelper_tags.php
@@ -3,6 +3,7 @@
$config = array(
'tags' => array(
'form' => 'start form',
- 'formend' => 'finish form'
+ 'formend' => 'finish form',
+ 'hiddenblock' => '
%s
'
)
);
\ No newline at end of file
diff --git a/lib/Cake/Test/test_app/Error/TestAppsExceptionRenderer.php b/lib/Cake/Test/test_app/Error/TestAppsExceptionRenderer.php
index e104a01c2..efd92b26f 100644
--- a/lib/Cake/Test/test_app/Error/TestAppsExceptionRenderer.php
+++ b/lib/Cake/Test/test_app/Error/TestAppsExceptionRenderer.php
@@ -7,7 +7,7 @@ class TestAppsExceptionRenderer extends ExceptionRenderer {
if (!$request = Router::getRequest(true)) {
$request = new CakeRequest();
}
- $response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
+ $response = new CakeResponse();
try {
$controller = new TestAppsErrorController($request, $response);
$controller->layout = 'banana';
diff --git a/lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php b/lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php
new file mode 100644
index 000000000..efd890a5f
--- /dev/null
+++ b/lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php
@@ -0,0 +1,7 @@
+
0 ):
+if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace');
endif;
?>
diff --git a/lib/Cake/Test/test_app/View/Errors/error500.ctp b/lib/Cake/Test/test_app/View/Errors/error500.ctp
index 4e1f36ece..54d3774df 100644
--- a/lib/Cake/Test/test_app/View/Errors/error500.ctp
+++ b/lib/Cake/Test/test_app/View/Errors/error500.ctp
@@ -22,7 +22,7 @@
0 ):
+if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace');
endif;
?>
diff --git a/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp b/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp
index dae25af94..1cb60aedc 100644
--- a/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp
+++ b/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp
@@ -1,4 +1,4 @@
-
+
diff --git a/lib/Cake/Test/test_app/View/Layouts/default.ctp b/lib/Cake/Test/test_app/View/Layouts/default.ctp
index 21b25e111..626128141 100644
--- a/lib/Cake/Test/test_app/View/Layouts/default.ctp
+++ b/lib/Cake/Test/test_app/View/Layouts/default.ctp
@@ -19,7 +19,7 @@ $this->loadHelper('Html');
$cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework');
?>
-
+
Html->charset(); ?>
diff --git a/lib/Cake/Test/test_app/View/Layouts/flash.ctp b/lib/Cake/Test/test_app/View/Layouts/flash.ctp
index 2a0c34fc2..81b70979e 100644
--- a/lib/Cake/Test/test_app/View/Layouts/flash.ctp
+++ b/lib/Cake/Test/test_app/View/Layouts/flash.ctp
@@ -16,13 +16,13 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
?>
-
+
Html->charset(); ?>
-
+