diff --git a/app/Config/bootstrap.php b/app/Config/bootstrap.php index fce18ccba..3b772c691 100644 --- a/app/Config/bootstrap.php +++ b/app/Config/bootstrap.php @@ -23,7 +23,66 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -// Setup a 'default' cache configuration for use in the application. +/** + * Cache Engine Configuration + * Default settings provided below + * + * File storage engine. + * + * Cache::config('default', array( + * 'engine' => 'File', //[required] + * 'duration'=> 3600, //[optional] + * 'probability'=> 100, //[optional] + * 'path' => CACHE, //[optional] use system tmp directory - remember to use absolute path + * 'prefix' => 'cake_', //[optional] prefix every cache file with this string + * 'lock' => false, //[optional] use file locking + * 'serialize' => true, // [optional] + * 'mask' => 0666, // [optional] permission mask to use when creating cache files + * )); + * + * APC (http://pecl.php.net/package/APC) + * + * Cache::config('default', array( + * 'engine' => 'Apc', //[required] + * 'duration'=> 3600, //[optional] + * 'probability'=> 100, //[optional] + * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string + * )); + * + * Xcache (http://xcache.lighttpd.net/) + * + * Cache::config('default', array( + * 'engine' => 'Xcache', //[required] + * 'duration'=> 3600, //[optional] + * 'probability'=> 100, //[optional] + * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string + * 'user' => 'user', //user from xcache.admin.user settings + * 'password' => 'password', //plaintext password (xcache.admin.pass) + * )); + * + * Memcache (http://memcached.org/) + * + * Cache::config('default', array( + * 'engine' => 'Memcache', //[required] + * 'duration'=> 3600, //[optional] + * 'probability'=> 100, //[optional] + * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string + * 'servers' => array( + * '127.0.0.1:11211' // localhost, default port 11211 + * ), //[optional] + * 'persistent' => true, // [optional] set this to false for non-persistent connections + * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory) + * )); + * + * Wincache (http://php.net/wincache) + * + * Cache::config('default', array( + * 'engine' => 'Wincache', //[required] + * 'duration'=> 3600, //[optional] + * 'probability'=> 100, //[optional] + * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string + * )); + */ Cache::config('default', array('engine' => 'File')); /** diff --git a/app/Config/core.php b/app/Config/core.php index 2989f13cd..771ed5b98 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -231,71 +231,13 @@ */ //date_default_timezone_set('UTC'); -/** - * - * Cache Engine Configuration - * Default settings provided below - * - * File storage engine. - * - * Cache::config('default', array( - * 'engine' => 'File', //[required] - * 'duration'=> 3600, //[optional] - * 'probability'=> 100, //[optional] - * 'path' => CACHE, //[optional] use system tmp directory - remember to use absolute path - * 'prefix' => 'cake_', //[optional] prefix every cache file with this string - * 'lock' => false, //[optional] use file locking - * 'serialize' => true, [optional] - * )); - * - * APC (http://pecl.php.net/package/APC) - * - * Cache::config('default', array( - * 'engine' => 'Apc', //[required] - * 'duration'=> 3600, //[optional] - * 'probability'=> 100, //[optional] - * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string - * )); - * - * Xcache (http://xcache.lighttpd.net/) - * - * Cache::config('default', array( - * 'engine' => 'Xcache', //[required] - * 'duration'=> 3600, //[optional] - * 'probability'=> 100, //[optional] - * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string - * 'user' => 'user', //user from xcache.admin.user settings - * 'password' => 'password', //plaintext password (xcache.admin.pass) - * )); - * - * Memcache (http://memcached.org/) - * - * Cache::config('default', array( - * 'engine' => 'Memcache', //[required] - * 'duration'=> 3600, //[optional] - * 'probability'=> 100, //[optional] - * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string - * 'servers' => array( - * '127.0.0.1:11211' // localhost, default port 11211 - * ), //[optional] - * 'persistent' => true, // [optional] set this to false for non-persistent connections - * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory) - * )); - * - * Wincache (http://php.net/wincache) - * - * Cache::config('default', array( - * 'engine' => 'Wincache', //[required] - * 'duration'=> 3600, //[optional] - * 'probability'=> 100, //[optional] - * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string - * )); - */ - /** * Pick the caching engine to use. If APC is enabled use it. * If running via cli - apc is disabled by default. ensure it's available and enabled in this case * + * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php. + * Please check the comments in boostrap.php for more info on the cache engines available + * and their setttings. */ $engine = 'File'; if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) { diff --git a/app/View/Pages/home.ctp b/app/View/Pages/home.ctp index 79644ae56..cb409a043 100644 --- a/app/View/Pages/home.ctp +++ b/app/View/Pages/home.ctp @@ -121,9 +121,9 @@ if (isset($filePresent)): App::uses('Validation', 'Utility'); if (!Validation::alphaNumeric('cakephp')) { echo '

'; - __d('cake_dev', 'PCRE has not been compiled with Unicode support.'); - echo '
'; - __d('cake_dev', 'Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring'); + echo __d('cake_dev', 'PCRE has not been compiled with Unicode support.'); + echo '
'; + echo __d('cake_dev', 'Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring'); echo '

'; } ?> diff --git a/lib/Cake/Console/Command/Task/ControllerTask.php b/lib/Cake/Console/Command/Task/ControllerTask.php index 621b95cc8..c1178dcec 100644 --- a/lib/Cake/Console/Command/Task/ControllerTask.php +++ b/lib/Cake/Console/Command/Task/ControllerTask.php @@ -126,7 +126,7 @@ class ControllerTask extends BakeTask { protected function _interactive() { $this->interactive = true; $this->hr(); - $this->out(__d('cake_console', "Bake Controller\nPath: %s", $this->path)); + $this->out(__d('cake_console', "Bake Controller\nPath: %s", $this->getPath())); $this->hr(); if (empty($this->connection)) { diff --git a/lib/Cake/Console/Command/Task/ExtractTask.php b/lib/Cake/Console/Command/Task/ExtractTask.php index ed28c196b..fad45e89a 100644 --- a/lib/Cake/Console/Command/Task/ExtractTask.php +++ b/lib/Cake/Console/Command/Task/ExtractTask.php @@ -70,12 +70,19 @@ class ExtractTask extends AppShell { protected $_tokens = array(); /** - * Extracted strings + * Extracted strings indexed by domain. * * @var array */ protected $_strings = array(); +/** + * Singular strings and their line numbers. + * + * @var array + */ + protected $_lines = array(); + /** * Destination path * @@ -325,8 +332,10 @@ class ExtractTask extends AppShell { if ($mapCount == count($strings)) { extract(array_combine($map, $strings)); $domain = isset($domain) ? $domain : 'default'; + $string = isset($plural) ? $singular . "\0" . $plural : $singular; - $this->_strings[$domain][$string][$this->_file][] = $line; + $this->_strings[$domain][] = $string; + $this->_lines[$domain][$singular][$this->_file][] = $line; } else { $this->_markerError($this->_file, $line, $functionName, $count); } @@ -406,7 +415,8 @@ class ExtractTask extends AppShell { $message = $rule; } if ($message) { - $this->_strings[$domain][$message][$file][] = 'validation for field ' . $field; + $this->_strings[$domain][] = $message; + $this->_lines[$domain][$message][$file][] = 'validation for field ' . $field; } } } @@ -419,7 +429,16 @@ class ExtractTask extends AppShell { */ protected function _buildFiles() { foreach ($this->_strings as $domain => $strings) { - foreach ($strings as $string => $files) { + $added = array(); + rsort($strings); + + foreach ($strings as $i => $string) { + $plural = false; + $singular = $string; + if (strpos($string, "\0") !== false) { + list($singular, $plural) = explode("\0", $string); + } + $files = $this->_lines[$domain][$singular]; $occurrences = array(); foreach ($files as $file => $lines) { $occurrences[] = $file . ':' . implode(';', $lines); @@ -427,17 +446,21 @@ class ExtractTask extends AppShell { $occurrences = implode("\n#: ", $occurrences); $header = '#: ' . str_replace($this->_paths, '', $occurrences) . "\n"; - if (strpos($string, "\0") === false) { + if ($plural === false && !empty($added[$singular])) { + continue; + } + + if ($plural === false) { $sentence = "msgid \"{$string}\"\n"; $sentence .= "msgstr \"\"\n\n"; } else { - list($singular, $plural) = explode("\0", $string); $sentence = "msgid \"{$singular}\"\n"; $sentence .= "msgid_plural \"{$plural}\"\n"; $sentence .= "msgstr[0] \"\"\n"; $sentence .= "msgstr[1] \"\"\n\n"; } + $added[$singular] = true; $this->_store($domain, $header, $sentence); if ($domain != 'default' && $this->_merge) { $this->_store('default', $header, $sentence); diff --git a/lib/Cake/Console/Command/Task/FixtureTask.php b/lib/Cake/Console/Command/Task/FixtureTask.php index 36c51e3d7..bf58cd4a7 100644 --- a/lib/Cake/Console/Command/Task/FixtureTask.php +++ b/lib/Cake/Console/Command/Task/FixtureTask.php @@ -137,7 +137,7 @@ class FixtureTask extends BakeTask { protected function _interactive() { $this->DbConfig->interactive = $this->Model->interactive = $this->interactive = true; $this->hr(); - $this->out(__d('cake_console', "Bake Fixture\nPath: %s", $this->path)); + $this->out(__d('cake_console', "Bake Fixture\nPath: %s", $this->getPath())); $this->hr(); if (!isset($this->connection)) { diff --git a/lib/Cake/Console/Command/Task/ModelTask.php b/lib/Cake/Console/Command/Task/ModelTask.php index bcdbdda98..9f30eadac 100644 --- a/lib/Cake/Console/Command/Task/ModelTask.php +++ b/lib/Cake/Console/Command/Task/ModelTask.php @@ -190,7 +190,7 @@ class ModelTask extends BakeTask { */ protected function _interactive() { $this->hr(); - $this->out(__d('cake_console', "Bake Model\nPath: %s", $this->path)); + $this->out(__d('cake_console', "Bake Model\nPath: %s", $this->getPath())); $this->hr(); $this->interactive = true; diff --git a/lib/Cake/Console/Command/Task/TestTask.php b/lib/Cake/Console/Command/Task/TestTask.php index ee4e1ab5e..21a2e3ff1 100644 --- a/lib/Cake/Console/Command/Task/TestTask.php +++ b/lib/Cake/Console/Command/Task/TestTask.php @@ -94,7 +94,7 @@ class TestTask extends BakeTask { $this->interactive = true; $this->hr(); $this->out(__d('cake_console', 'Bake Tests')); - $this->out(__d('cake_console', 'Path: %s', $this->path)); + $this->out(__d('cake_console', 'Path: %s', $this->getPath())); $this->hr(); if ($type) { diff --git a/lib/Cake/Console/Command/Task/ViewTask.php b/lib/Cake/Console/Command/Task/ViewTask.php index b125d0791..4fe53b7ec 100644 --- a/lib/Cake/Console/Command/Task/ViewTask.php +++ b/lib/Cake/Console/Command/Task/ViewTask.php @@ -195,7 +195,7 @@ class ViewTask extends BakeTask { */ protected function _interactive() { $this->hr(); - $this->out(sprintf("Bake View\nPath: %s", $this->path)); + $this->out(sprintf("Bake View\nPath: %s", $this->getPath())); $this->hr(); $this->DbConfig->interactive = $this->Controller->interactive = $this->interactive = true; diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthorize.php b/lib/Cake/Controller/Component/Auth/BaseAuthorize.php index f4c33fe3d..00763ab84 100644 --- a/lib/Cake/Controller/Component/Auth/BaseAuthorize.php +++ b/lib/Cake/Controller/Component/Auth/BaseAuthorize.php @@ -108,11 +108,13 @@ abstract class BaseAuthorize { */ public function action($request, $path = '/:plugin/:controller/:action') { $plugin = empty($request['plugin']) ? null : Inflector::camelize($request['plugin']) . '/'; - return str_replace( + $path = str_replace( array(':controller', ':action', ':plugin/'), array(Inflector::camelize($request['controller']), $request['action'], $plugin), $this->settings['actionPath'] . $path ); + $path = str_replace('//', '/', $path); + return trim($path, '/'); } /** diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index cea188349..3abb24ddc 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -483,7 +483,8 @@ class CookieComponent extends Component { * @return array Map of key and values */ protected function _explode($string) { - if ($string[0] === '{' || $string[0] === '[') { + $first = substr($string, 0, 1); + if ($first !== false && $first === '{' || $first === '[') { $ret = json_decode($string, true); return ($ret != null) ? $ret : $string; } diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php index 6ca9b073f..c6f8f261c 100644 --- a/lib/Cake/Controller/Component/RequestHandlerComponent.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -160,7 +160,10 @@ class RequestHandlerComponent extends Component { * switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml` * is requested, the view path becomes `app/View/Controller/xml/action.ctp`. Also if * `controller/action` is requested with `Accept-Type: application/xml` in the headers - * the view path will become `app/View/Controller/xml/action.ctp`. + * the view path will become `app/View/Controller/xml/action.ctp`. Layout and template + * types will only switch to mime-types recognized by CakeResponse. If you need to declare + * additional mime-types, you can do so using CakeResponse::type() in your controllers beforeFilter() + * method. * - If a helper with the same name as the extension exists, it is added to the controller. * - If the extension is of a type that RequestHandler understands, it will set that * Content-type in the response header. diff --git a/lib/Cake/Core/App.php b/lib/Cake/Core/App.php index b105b0633..6d37fbd3e 100644 --- a/lib/Cake/Core/App.php +++ b/lib/Cake/Core/App.php @@ -860,7 +860,7 @@ class App { ), 'Vendor' => array( '%s' . 'Vendor' . DS, - VENDORS + dirname(dirname(CAKE)) . DS . 'vendors' . DS, ), 'Plugin' => array( APP . 'Plugin' . DS, diff --git a/lib/Cake/Error/ErrorHandler.php b/lib/Cake/Error/ErrorHandler.php index 2c2a2ee09..5899a71b4 100644 --- a/lib/Cake/Error/ErrorHandler.php +++ b/lib/Cake/Error/ErrorHandler.php @@ -217,6 +217,7 @@ class ErrorHandler { $log = LOG_NOTICE; break; case E_DEPRECATED: + case E_USER_DEPRECATED: $error = 'Deprecated'; $log = LOG_NOTICE; break; diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index b903d8998..9b51bfad8 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -745,7 +745,7 @@ class Sqlserver extends DboSource { */ protected function _execute($sql, $params = array(), $prepareOptions = array()) { $this->_lastAffected = false; - if (strncasecmp($sql, 'SELECT', 6) == 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/Model.php b/lib/Cake/Model/Model.php index 8986405f0..79acfbad3 100644 --- a/lib/Cake/Model/Model.php +++ b/lib/Cake/Model/Model.php @@ -2662,6 +2662,10 @@ class Model extends Object implements CakeEventListener { protected function _findCount($state, $query, $results = array()) { if ($state === 'before') { $db = $this->getDataSource(); + $query['order'] = false; + if (!method_exists($db, 'calculate') || !method_exists($db, 'expression')) { + return $query; + } if (empty($query['fields'])) { $query['fields'] = $db->calculate($this, 'count'); } elseif (is_string($query['fields']) && !preg_match('/count/i', $query['fields'])) { @@ -2669,7 +2673,6 @@ class Model extends Object implements CakeEventListener { $db->expression($query['fields']), 'count' )); } - $query['order'] = false; return $query; } elseif ($state === 'after') { foreach (array(0, $this->alias) as $key) { diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 539ec797a..cedefee39 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -208,6 +208,7 @@ class CakeResponse { 'hh' => 'text/plain', 'html' => array('text/html', '*/*'), 'htm' => array('text/html', '*/*'), + 'ics' => 'text/calendar', 'm' => 'text/plain', 'rtf' => 'text/rtf', 'rtx' => 'text/richtext', diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 69c3982c2..c9aaf72ce 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -686,6 +686,9 @@ class CakeEmail { if ($email === $alias) { $return[] = $email; } else { + if (strpos($alias, ',') !== false) { + $alias = '"' . $alias . '"'; + } $return[] = sprintf('%s <%s>', $this->_encode($alias), $email); } } @@ -1109,9 +1112,6 @@ class CakeEmail { $restore = mb_internal_encoding(); mb_internal_encoding($this->_appCharset); } - if (strpos($text, ',') !== false) { - $text = '"' . $text . '"'; - } $return = mb_encode_mimeheader($text, $this->headerCharset, 'B'); if ($internalEncoding) { mb_internal_encoding($restore); diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index 2a211f7b4..f382ad26a 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -1077,15 +1077,17 @@ class Router { * Instructs the router to parse out file extensions from the URL. For example, * http://example.com/posts.rss would yield an file extension of "rss". * The file extension itself is made available in the controller as - * $this->params['url']['ext'], and is used by the RequestHandler component to + * `$this->params['ext']`, and is used by the RequestHandler component to * automatically switch to alternate layouts and templates, and load helpers - * corresponding to the given content, i.e. RssHelper. + * corresponding to the given content, i.e. RssHelper. Switching layouts and helpers + * requires that the chosen extension has a defined mime type in `CakeResponse` * * A list of valid extension can be passed to this method, i.e. Router::parseExtensions('rss', 'xml'); * If no parameters are given, anything after the first . (dot) after the last / in the URL will be * parsed, excluding querystring parameters (i.e. ?q=...). * * @return void + * @see RequestHandler::startup() */ public static function parseExtensions() { self::$_parseExtensions = true; diff --git a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php index 15e0254ee..d358c7540 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php @@ -93,27 +93,37 @@ class ExtractTaskTest extends CakeTestCase { // home.ctp $pattern = '/msgid "Your tmp directory is writable."\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Your tmp directory is NOT writable."\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "The %s is being used for caching. To change the config edit '; $pattern .= 'APP\/config\/core.php "\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Your cache is NOT working. Please check '; $pattern .= 'the settings in APP\/config\/core.php"\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Your database configuration file is present."\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Your database configuration file is NOT present."\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Rename config\/database.php.default to '; $pattern .= 'config\/database.php"\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Cake is able to connect to the database."\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Cake is NOT able to connect to the database."\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "Editing this Page"\nmsgstr ""\n/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "To change the content of this page, create: APP\/views\/pages\/home\.ctp/'; $this->assertRegExp($pattern, $result); @@ -121,10 +131,13 @@ class ExtractTaskTest extends CakeTestCase { $this->assertRegExp($pattern, $result); // extract.ctp - $pattern = '/\#: (\\\\|\/)extract\.ctp:6\n'; + $pattern = '/\#: (\\\\|\/)extract\.ctp:15;6\n'; $pattern .= 'msgid "You have %d new message."\nmsgid_plural "You have %d new messages."/'; $this->assertRegExp($pattern, $result); + $pattern = '/msgid "You have %d new message."\nmsgstr ""/'; + $this->assertNotRegExp($pattern, $result, 'No duplicate msgid'); + $pattern = '/\#: (\\\\|\/)extract\.ctp:7\n'; $pattern .= 'msgid "You deleted %d message."\nmsgid_plural "You deleted %d messages."/'; $this->assertRegExp($pattern, $result); @@ -134,7 +147,7 @@ class ExtractTaskTest extends CakeTestCase { $pattern .= 'msgid "Editing this Page"\nmsgstr ""/'; $this->assertRegExp($pattern, $result); - $pattern = '/\#: (\\\\|\/)extract\.ctp:17\nmsgid "'; + $pattern = '/\#: (\\\\|\/)extract\.ctp:18\nmsgid "'; $pattern .= 'Hot features!'; $pattern .= '\\\n - No Configuration: Set-up the database and let the magic begin'; $pattern .= '\\\n - Extremely Simple: Just look at the name...It\'s Cake'; diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php index 5861bfe03..dc3afda78 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php @@ -75,7 +75,7 @@ class ActionsAuthorizeTest extends CakeTestCase { $this->Acl->expects($this->once()) ->method('check') - ->with($user, '/controllers/Posts/index') + ->with($user, 'controllers/Posts/index') ->will($this->returnValue(false)); $this->assertFalse($this->auth->authorize($user['User'], $request)); @@ -104,7 +104,7 @@ class ActionsAuthorizeTest extends CakeTestCase { $this->Acl->expects($this->once()) ->method('check') - ->with($user, '/controllers/Posts/index') + ->with($user, 'controllers/Posts/index') ->will($this->returnValue(true)); $this->assertTrue($this->auth->authorize($user['User'], $request)); @@ -134,7 +134,7 @@ class ActionsAuthorizeTest extends CakeTestCase { $expected = array('TestPlugin.TestPluginAuthUser' => array('id' => 1, 'user' => 'mariano')); $this->Acl->expects($this->once()) ->method('check') - ->with($expected, '/controllers/Posts/index') + ->with($expected, 'controllers/Posts/index') ->will($this->returnValue(true)); $this->assertTrue($this->auth->authorize($user, $request)); @@ -154,8 +154,23 @@ class ActionsAuthorizeTest extends CakeTestCase { )); $result = $this->auth->action($request); + $this->assertEquals('controllers/Posts/index', $result); + } - $this->assertEquals('/controllers/Posts/index', $result); +/** + * Make sure that action() doesn't create double slashes anywhere. + * + * @return void + */ + public function testActionNoDoubleSlash() { + $this->auth->settings['actionPath'] = '/controllers/'; + $request = array( + 'plugin' => null, + 'controller' => 'posts', + 'action' => 'index' + ); + $result = $this->auth->action($request); + $this->assertEquals('controllers/Posts/index', $result); } /** @@ -172,6 +187,6 @@ class ActionsAuthorizeTest extends CakeTestCase { )); $result = $this->auth->action($request); - $this->assertEquals('/controllers/DebugKit/Posts/index', $result); + $this->assertEquals('controllers/DebugKit/Posts/index', $result); } } diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index 56fe5b645..701973dab 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -471,6 +471,21 @@ class CookieComponentTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * Test reading empty values. + */ + public function testReadEmpty() { + $_COOKIE['CakeTestCookie'] = array( + 'JSON' => '{"name":"value"}', + 'Empty' => '', + 'String' => '{"somewhat:"broken"}' + ); + $this->assertEqual(array('name' => 'value'), $this->Cookie->read('JSON')); + $this->assertEqual('value', $this->Cookie->read('JSON.name')); + $this->assertEqual('', $this->Cookie->read('Empty')); + $this->assertEqual('{"somewhat:"broken"}', $this->Cookie->read('String')); + } + /** * test that no error is issued for non array data. * @@ -483,6 +498,7 @@ class CookieComponentTest extends CakeTestCase { $this->assertNull($this->Cookie->read('value')); } + /** * test that deleting a top level keys kills the child elements too. * diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index 95394bf62..c01678c68 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -633,4 +633,31 @@ class SqlserverTest extends CakeTestCase { $this->assertEquals('nate', $results[1]['User']['user']); } +/** + * Test that the return of stored procedures is honoured + * + * @return void + */ + public function testStoredProcedureReturn() { + $sql = <<Dbo->execute($sql); + + $sql = <<Dbo->execute($sql); + $this->Dbo->execute('DROP PROC cake_test_procedure'); + + $result = $query->fetch(); + $this->assertEquals(2, $result['value']); + } + } diff --git a/lib/Cake/Test/Case/Model/ModelDeleteTest.php b/lib/Cake/Test/Case/Model/ModelDeleteTest.php index 9ce2e0717..e3a64e0b1 100644 --- a/lib/Cake/Test/Case/Model/ModelDeleteTest.php +++ b/lib/Cake/Test/Case/Model/ModelDeleteTest.php @@ -555,7 +555,9 @@ class ModelDeleteTest extends BaseModelTest { * @return void */ public function testDeleteDependent() { - $this->loadFixtures('Bidding', 'BiddingMessage'); + $this->loadFixtures('Bidding', 'BiddingMessage', 'Article', + 'ArticlesTag', 'Comment', 'User', 'Attachment' + ); $Bidding = new Bidding(); $result = $Bidding->find('all'); $expected = array( @@ -626,6 +628,20 @@ class ModelDeleteTest extends BaseModelTest { ), ); $this->assertEquals($expected, $result); + + $Article = new Article(); + $result = $Article->Comment->find('count', array( + 'conditions' => array('Comment.article_id' => 1) + )); + $this->assertEquals(4, $result); + + $result = $Article->delete(1, true); + $this->assertIdentical(true, true); + + $result = $Article->Comment->find('count', array( + 'conditions' => array('Comment.article_id' => 1) + )); + $this->assertEquals(0, $result); } /** diff --git a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php index a962bab1c..3c8c0d0fb 100644 --- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php +++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php @@ -395,6 +395,8 @@ class CakeEmailTest extends CakeTestCase { $this->CakeEmail->subject('You have a new message.'); $this->assertSame($this->CakeEmail->subject(), 'You have a new message.'); + $this->CakeEmail->subject('You have a new message, I think.'); + $this->assertSame($this->CakeEmail->subject(), 'You have a new message, I think.'); $this->CakeEmail->subject(1); $this->assertSame($this->CakeEmail->subject(), '1'); diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 40f1ff4f8..33732b2ac 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -1462,6 +1462,31 @@ class FormHelperTest extends CakeTestCase { $this->assertEquals(array(), $this->Form->fields); } +/** + * testTagIsInvalid method + * + * @return void + */ + public function testTagIsInvalid() { + $Contact = ClassRegistry::getObject('Contact'); + $Contact->validationErrors[0]['email'] = array('Please provide an email'); + + $this->Form->setEntity('Contact.0.email'); + $result = $this->Form->tagIsInvalid(); + $expected = array('Please provide an email'); + $this->assertEquals($expected, $result); + + $this->Form->setEntity('Contact.1.email'); + $result = $this->Form->tagIsInvalid(); + $expected = false; + $this->assertIdentical($expected, $result); + + $this->Form->setEntity('Contact.0.name'); + $result = $this->Form->tagIsInvalid(); + $expected = false; + $this->assertIdentical($expected, $result); + } + /** * testPasswordValidation method * diff --git a/lib/Cake/Test/Case/View/MediaViewTest.php b/lib/Cake/Test/Case/View/MediaViewTest.php index d1377ee20..38d68a239 100644 --- a/lib/Cake/Test/Case/View/MediaViewTest.php +++ b/lib/Cake/Test/Case/View/MediaViewTest.php @@ -244,6 +244,7 @@ class MediaViewTest extends CakeTestCase { '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') @@ -270,7 +271,7 @@ class MediaViewTest extends CakeTestCase { $this->MediaView->response->expects($this->once()) ->method('download') - ->with('no_section.ini'); + ->with('config.ini'); $this->MediaView->response->expects($this->at(4)) ->method('header') @@ -357,7 +358,7 @@ class MediaViewTest extends CakeTestCase { * * @return void */ - function testRenderUpperExtesnion() { + public function testRenderUpperExtension() { $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS .'img' . DS, 'id' => 'test_2.JPG', @@ -376,4 +377,27 @@ class MediaViewTest extends CakeTestCase { $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)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $this->MediaView->render(); + } + } diff --git a/lib/Cake/Test/test_app/View/Pages/extract.ctp b/lib/Cake/Test/test_app/View/Pages/extract.ctp index 5e6abf54e..cba9b012f 100644 --- a/lib/Cake/Test/test_app/View/Pages/extract.ctp +++ b/lib/Cake/Test/test_app/View/Pages/extract.ctp @@ -12,6 +12,7 @@ echo __dn('domain', 'You deleted %d message (domain).', 'You deleted %d messages // Duplicated Message echo __('Editing this Page'); +echo __('You have %d new message.'); // Multiline __('Hot features!' diff --git a/lib/Cake/Utility/Debugger.php b/lib/Cake/Utility/Debugger.php index 34e85df41..a32a8e748 100644 --- a/lib/Cake/Utility/Debugger.php +++ b/lib/Cake/Utility/Debugger.php @@ -241,6 +241,11 @@ class Debugger { $error = 'Notice'; $level = LOG_NOTICE; break; + case E_DEPRECATED: + case E_USER_DEPRECATED: + $error = 'Deprecated'; + $level = LOG_NOTICE; + break; default: return; break; @@ -805,5 +810,4 @@ class Debugger { trigger_error(__d('cake_dev', 'Please change the value of \'Security.cipherSeed\' in app/Config/core.php to a numeric (digits only) seed value specific to your application'), E_USER_NOTICE); } } - } diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 95d4d80e2..15089517d 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -272,8 +272,8 @@ class FormHelper extends AppHelper { * Returns false if given form field described by the current entity has no errors. * Otherwise it returns the validation message * - * @return mixed Either false when there or no errors, or the error - * string. The error string could be ''. + * @return mixed Either false when there or no errors, or an array of error + * strings. An error string could be ''. * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::tagIsInvalid */ public function tagIsInvalid() { @@ -289,8 +289,8 @@ class FormHelper extends AppHelper { if (empty($errors)) { return false; } - $error = Set::classicExtract($errors, join('.', $entity)); - return $error === null ? false : $error; + $errors = Set::classicExtract($errors, join('.', $entity)); + return $errors === null ? false : $errors; } /** @@ -739,7 +739,7 @@ class FormHelper extends AppHelper { * * ### Options * - * - `for` - Set the for attribute, if its not defined the for attribute + * - `for` - Set the for attribute, if its not defined the for attribute * will be generated from the $fieldName parameter using * FormHelper::domId(). * @@ -776,8 +776,8 @@ class FormHelper extends AppHelper { * }}} * * @param string $fieldName This should be "Modelname.fieldname" - * @param string $text Text that will appear in the label field. If - * $text is left undefined the text will be inflected from the + * @param string $text Text that will appear in the label field. If + * $text is left undefined the text will be inflected from the * fieldName. * @param mixed $options An array of HTML attributes, or a string, to be used as a class name. * @return string The formatted LABEL element diff --git a/lib/Cake/View/MediaView.php b/lib/Cake/View/MediaView.php index 81b7dbf45..822e2beb8 100644 --- a/lib/Cake/View/MediaView.php +++ b/lib/Cake/View/MediaView.php @@ -31,9 +31,11 @@ App::uses('CakeRequest', 'Network'); * - `id` The filename on the server's filesystem, including extension. * - `name` The filename that will be sent to the user, specified without the extension. * - `download` Set to true to set a `Content-Disposition` header. This is ideal for file downloads. - * - `extension` The extension of the file being served. This is used to set the mimetype + * - `extension` The extension of the file being served. This is used to set the mimetype. + * If not provided its extracted from filename provided as `id`. * - `path` The absolute path, including the trailing / on the server's filesystem to `id`. * - `mimeType` The mime type of the file if CakeResponse doesn't know about it. + * Must be an associative array with extension as key and mime type as value eg. array('ini' => 'text/plain') * * ### Usage * @@ -101,7 +103,11 @@ class MediaView extends View { $this->response->type($mimeType); } - if (isset($extension) && $this->_isActive()) { + if (!isset($extension)) { + $extension = pathinfo($id, PATHINFO_EXTENSION); + } + + if ($this->_isActive()) { $extension = strtolower($extension); $chunkSize = 8192; $buffer = ''; @@ -116,7 +122,7 @@ class MediaView extends View { } else { $modified = time(); } - if ($this->response->type($extension) === false) { + if (!$extension || $this->response->type($extension) === false) { $download = true; } @@ -145,6 +151,8 @@ class MediaView extends View { } if (is_null($name)) { $name = $id; + } elseif ($extension) { + $name .= '.' . $extension; } $this->response->download($name); $this->response->header(array('Accept-Ranges' => 'bytes')); diff --git a/lib/Cake/bootstrap.php b/lib/Cake/bootstrap.php index 17f647784..f34b4001e 100644 --- a/lib/Cake/bootstrap.php +++ b/lib/Cake/bootstrap.php @@ -23,6 +23,10 @@ define('TIME_START', microtime(true)); if (!defined('E_DEPRECATED')) { define('E_DEPRECATED', 8192); } + +if (!defined('E_USER_DEPRECATED')) { + define('E_USER_DEPRECATED', E_USER_NOTICE); +} error_reporting(E_ALL & ~E_DEPRECATED); if (!defined('CAKE_CORE_INCLUDE_PATH')) {