From 333f36585b27072d40f8b0d5e7b464b0c50e185a Mon Sep 17 00:00:00 2001 From: Dean Sofer Date: Tue, 26 Jul 2011 01:39:56 -0700 Subject: [PATCH 01/33] Added `'integer' => 'number'` for HTML5 Located in $map in the `FormHelper::input()` method. This means that if a field input is related to an integer column in the database, it will show up as a number input in the HTML5 form (where supported) yet gracefully degrade. --- lib/Cake/View/Helper/FormHelper.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index a4be6890a..3bdd5d31c 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -917,7 +917,8 @@ class FormHelper extends AppHelper { 'string' => 'text', 'datetime' => 'datetime', 'boolean' => 'checkbox', 'timestamp' => 'datetime', 'text' => 'textarea', 'time' => 'time', - 'date' => 'date', 'float' => 'text' + 'date' => 'date', 'float' => 'text', + 'integer' => 'number' ); if (isset($this->map[$type])) { From 804e88b092f38f95d4b23ad72a7f34c4f57b969e Mon Sep 17 00:00:00 2001 From: Dean Sofer Date: Tue, 26 Jul 2011 02:19:41 -0700 Subject: [PATCH 02/33] Added test for HTML5 `FormHelper::input()` integer to number in $map --- .../Test/Case/View/Helper/FormHelperTest.php | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 1a61b6719..a1f15255a 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -97,7 +97,8 @@ class Contact extends CakeTestModel { 'password' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'), 'published' => array('type' => 'date', 'null' => true, 'default' => null, 'length' => null), 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''), - 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null) + 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null), + 'age' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => null) ); /** @@ -886,6 +887,36 @@ class FormHelperTest extends CakeTestCase { '/div' ); } + +/** + * Tests correct generation of text fields for double and float fields + * + * @access public + * @return void + */ + public function testTextFieldTypeNumberGenerationForIntegers() { + $model = ClassRegistry::getObject('Contact'); + $model->setSchema(array('foo' => array( + 'type' => 'integer', + 'null' => false, + 'default' => null, + 'length' => null + ))); + + $this->Form->create('Contact'); + $result = $this->Form->input('foo'); + $expected = array( + 'div' => array('class' => 'input text'), + 'label' => array('for' => 'ContactFoo'), + 'Foo', + '/label', + array('input' => array( + 'type' => 'number', 'name' => 'data[Contact][foo]', + 'id' => 'ContactFoo' + )), + '/div' + ); + } /** * testFormSecurityMultipleFields method From 2ef17ec0a7b1cd8349402830075e0156ec631272 Mon Sep 17 00:00:00 2001 From: Dean Sofer Date: Wed, 27 Jul 2011 15:15:31 -0700 Subject: [PATCH 03/33] Additional tweak to FormHelper::input(), make float types use the number input --- lib/Cake/View/Helper/FormHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 3bdd5d31c..7c9bc4062 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -917,7 +917,7 @@ class FormHelper extends AppHelper { 'string' => 'text', 'datetime' => 'datetime', 'boolean' => 'checkbox', 'timestamp' => 'datetime', 'text' => 'textarea', 'time' => 'time', - 'date' => 'date', 'float' => 'text', + 'date' => 'date', 'float' => 'number', 'integer' => 'number' ); From 9577fb0ca247afa7f7aa335de7aa02e18230f98f Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 31 Jul 2011 01:07:46 +0530 Subject: [PATCH 04/33] Fixed TreeBehavior::childCount(). Closes #1833 --- lib/Cake/Model/Behavior/TreeBehavior.php | 2 +- lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php index 2ee639cf1..e467389c7 100644 --- a/lib/Cake/Model/Behavior/TreeBehavior.php +++ b/lib/Cake/Model/Behavior/TreeBehavior.php @@ -219,7 +219,7 @@ class TreeBehavior extends ModelBehavior { if ($id === null) { return $Model->find('count', array('conditions' => $scope)); - } elseif (isset($Model->data[$Model->alias][$left]) && isset($Model->data[$Model->alias][$right])) { + } elseif ($Model->id === $id && isset($Model->data[$Model->alias][$left]) && isset($Model->data[$Model->alias][$right])) { $data = $Model->data[$Model->alias]; } else { $data = $Model->find('first', array('conditions' => array($scope, $Model->escapeField() => $id), 'recursive' => $recursive)); diff --git a/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php b/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php index c21750ad1..3a3257448 100644 --- a/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php @@ -1118,6 +1118,11 @@ class TreeBehaviorNumberTest extends CakeTestCase { $total = $this->Tree->childCount(); $this->assertEqual($total, 6); + + $this->Tree->read(null, $data[$modelClass]['id']); + $id = $this->Tree->field('id', array($modelClass . '.name' => '1.2')); + $total = $this->Tree->childCount($id); + $this->assertEqual($total, 2); } /** From dbdc0a1e37e004761e5879a351250b52570e3407 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Tue, 2 Aug 2011 14:56:03 +0200 Subject: [PATCH 05/33] moving test icons one dir up, and remove subdir img in img --- .../skel/webroot/img/{img => }/test-error-icon.png | Bin .../skel/webroot/img/{img => }/test-fail-icon.png | Bin .../skel/webroot/img/{img => }/test-pass-icon.png | Bin .../skel/webroot/img/{img => }/test-skip-icon.png | Bin 4 files changed, 0 insertions(+), 0 deletions(-) rename lib/Cake/Console/Templates/skel/webroot/img/{img => }/test-error-icon.png (100%) rename lib/Cake/Console/Templates/skel/webroot/img/{img => }/test-fail-icon.png (100%) rename lib/Cake/Console/Templates/skel/webroot/img/{img => }/test-pass-icon.png (100%) rename lib/Cake/Console/Templates/skel/webroot/img/{img => }/test-skip-icon.png (100%) diff --git a/lib/Cake/Console/Templates/skel/webroot/img/img/test-error-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-error-icon.png similarity index 100% rename from lib/Cake/Console/Templates/skel/webroot/img/img/test-error-icon.png rename to lib/Cake/Console/Templates/skel/webroot/img/test-error-icon.png diff --git a/lib/Cake/Console/Templates/skel/webroot/img/img/test-fail-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-fail-icon.png similarity index 100% rename from lib/Cake/Console/Templates/skel/webroot/img/img/test-fail-icon.png rename to lib/Cake/Console/Templates/skel/webroot/img/test-fail-icon.png diff --git a/lib/Cake/Console/Templates/skel/webroot/img/img/test-pass-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-pass-icon.png similarity index 100% rename from lib/Cake/Console/Templates/skel/webroot/img/img/test-pass-icon.png rename to lib/Cake/Console/Templates/skel/webroot/img/test-pass-icon.png diff --git a/lib/Cake/Console/Templates/skel/webroot/img/img/test-skip-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-skip-icon.png similarity index 100% rename from lib/Cake/Console/Templates/skel/webroot/img/img/test-skip-icon.png rename to lib/Cake/Console/Templates/skel/webroot/img/test-skip-icon.png From 721c438817254e12096273afc0941297771a314d Mon Sep 17 00:00:00 2001 From: Mark Story Date: Thu, 28 Jul 2011 13:44:07 -0400 Subject: [PATCH 06/33] Re-adding support for PHP's include_path. Moving constants that are made of other constants into bootstrap.php --- app/Console/cake.php | 27 ++++++++++++++---- app/webroot/index.php | 27 +++++++++++++----- app/webroot/test.php | 24 +++++++++++----- .../Console/Templates/skel/webroot/index.php | 28 ++++++++++++++----- .../Console/Templates/skel/webroot/test.php | 24 +++++++++++----- lib/Cake/Console/cake.php | 2 +- lib/Cake/bootstrap.php | 27 ++++++++++-------- 7 files changed, 113 insertions(+), 46 deletions(-) diff --git a/app/Console/cake.php b/app/Console/cake.php index b9c404167..8b30ffd84 100644 --- a/app/Console/cake.php +++ b/app/Console/cake.php @@ -3,8 +3,6 @@ /** * Command-line code generation utility to automate programmer chores. * - * Shell dispatcher class - * * PHP 5 * * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) @@ -15,10 +13,29 @@ * * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @package app.console - * @since CakePHP(tm) v 1.2.0.5012 + * @package app.Console + * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once(dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'lib'. DIRECTORY_SEPARATOR . 'Cake' . DIRECTORY_SEPARATOR . 'Console' . DIRECTORY_SEPARATOR . 'ShellDispatcher.php'); +$ds = DIRECTORY_SEPARATOR; +$dispatcher = 'Cake' . $ds . 'Console' . $ds . 'ShellDispatcher.php'; +$found = false; +$paths = explode(PATH_SEPARATOR, ini_get('include_path')); + +foreach ($paths as $path) { + if (file_exists($path . $ds . $dispatcher)) { + $found = $path; + } +} + +if (!$found && function_exists('ini_set')) { + $root = dirname(dirname(dirname(__FILE__))); + ini_set('include_path', $root . $ds. 'lib' . PATH_SEPARATOR . ini_get('include_path')); +} + +if (!include($dispatcher)) { + trigger_error('Could not locate CakePHP core files.', E_USER_ERROR); +} +unset($paths, $path, $found, $dispatcher, $root, $ds); return ShellDispatcher::run($argv); diff --git a/app/webroot/index.php b/app/webroot/index.php index 943e310aa..31901c223 100644 --- a/app/webroot/index.php +++ b/app/webroot/index.php @@ -44,13 +44,17 @@ if (!defined('APP_DIR')) { define('APP_DIR', basename(dirname(dirname(__FILE__)))); } + /** * The absolute path to the "cake" directory, WITHOUT a trailing DS. * + * Un-comment this line to specify a fixed path to CakePHP. + * This should point at the directory containg `Cake`. + * + * For ease of development CakePHP uses PHP's include_path. If you + * cannot modify your include_path set this value. */ - if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); - } + //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); /** * Editing below this line should NOT be necessary. @@ -63,11 +67,20 @@ if (!defined('WWW_ROOT')) { define('WWW_ROOT', dirname(__FILE__) . DS); } - if (!defined('CORE_PATH')) { - define('APP_PATH', ROOT . DS . APP_DIR . DS); - define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); + + if (!defined('CAKE_CORE_INCLUDE_PATH')) { + if (function_exists('ini_set')) { + ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); + } + if (!include('Cake' . DS . 'bootstrap.php')) { + $failed = true; + } + } else { + if (!include(CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php')) { + $failed = true; + } } - if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { + if (!empty($failed)) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } diff --git a/app/webroot/test.php b/app/webroot/test.php index aa6759d06..f48bfb593 100644 --- a/app/webroot/test.php +++ b/app/webroot/test.php @@ -44,13 +44,14 @@ ini_set('display_errors', 1); if (!defined('APP_DIR')) { define('APP_DIR', basename(dirname(dirname(__FILE__)))); } + /** * The absolute path to the "Cake" directory, WITHOUT a trailing DS. * + * For ease of development CakePHP uses PHP's include_path. If you + * need to cannot modify your include_path, you can set this path. */ - if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); - } + //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); /** * Editing below this line should not be necessary. @@ -63,11 +64,20 @@ if (!defined('WEBROOT_DIR')) { if (!defined('WWW_ROOT')) { define('WWW_ROOT', dirname(__FILE__) . DS); } -if (!defined('CORE_PATH')) { - define('APP_PATH', ROOT . DS . APP_DIR . DS); - define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); + +if (!defined('CAKE_CORE_INCLUDE_PATH')) { + if (function_exists('ini_set')) { + ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); + } + if (!include('Cake' . DS . 'bootstrap.php')) { + $failed = true; + } +} else { + if (!include(CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php')) { + $failed = true; + } } -if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { +if (!empty($failed)) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } diff --git a/lib/Cake/Console/Templates/skel/webroot/index.php b/lib/Cake/Console/Templates/skel/webroot/index.php index 7b67ae20b..2dced12c7 100644 --- a/lib/Cake/Console/Templates/skel/webroot/index.php +++ b/lib/Cake/Console/Templates/skel/webroot/index.php @@ -44,13 +44,17 @@ if (!defined('APP_DIR')) { define('APP_DIR', basename(dirname(dirname(__FILE__)))); } + /** * The absolute path to the "cake" directory, WITHOUT a trailing DS. * + * Un-comment this line to specify a fixed path to CakePHP. + * This should point at the directory containg `Cake`. + * + * For ease of development CakePHP uses PHP's include_path. If you + * need to squeeze a bit more performance you can set this path. */ - if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); - } + //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); /** * Editing below this line should NOT be necessary. @@ -63,11 +67,20 @@ if (!defined('WWW_ROOT')) { define('WWW_ROOT', dirname(__FILE__) . DS); } - if (!defined('CORE_PATH')) { - define('APP_PATH', ROOT . DS . APP_DIR . DS); - define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); + + if (!defined('CAKE_CORE_INCLUDE_PATH')) { + if (function_exists('ini_set')) { + ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); + } + if (!include('Cake' . DS . 'bootstrap.php')) { + $failed = true; + } + } else { + if (!include(CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php')) { + $failed = true; + } } - if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { + if (!empty($failed)) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } @@ -76,5 +89,6 @@ } App::uses('Dispatcher', 'Routing'); + $Dispatcher = new Dispatcher(); $Dispatcher->dispatch(new CakeRequest(), new CakeResponse(array('charset' => Configure::read('App.encoding')))); diff --git a/lib/Cake/Console/Templates/skel/webroot/test.php b/lib/Cake/Console/Templates/skel/webroot/test.php index aa6759d06..f48bfb593 100644 --- a/lib/Cake/Console/Templates/skel/webroot/test.php +++ b/lib/Cake/Console/Templates/skel/webroot/test.php @@ -44,13 +44,14 @@ ini_set('display_errors', 1); if (!defined('APP_DIR')) { define('APP_DIR', basename(dirname(dirname(__FILE__)))); } + /** * The absolute path to the "Cake" directory, WITHOUT a trailing DS. * + * For ease of development CakePHP uses PHP's include_path. If you + * need to cannot modify your include_path, you can set this path. */ - if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); - } + //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); /** * Editing below this line should not be necessary. @@ -63,11 +64,20 @@ if (!defined('WEBROOT_DIR')) { if (!defined('WWW_ROOT')) { define('WWW_ROOT', dirname(__FILE__) . DS); } -if (!defined('CORE_PATH')) { - define('APP_PATH', ROOT . DS . APP_DIR . DS); - define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); + +if (!defined('CAKE_CORE_INCLUDE_PATH')) { + if (function_exists('ini_set')) { + ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); + } + if (!include('Cake' . DS . 'bootstrap.php')) { + $failed = true; + } +} else { + if (!include(CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php')) { + $failed = true; + } } -if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { +if (!empty($failed)) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } diff --git a/lib/Cake/Console/cake.php b/lib/Cake/Console/cake.php index 6e4381516..28282e675 100644 --- a/lib/Cake/Console/cake.php +++ b/lib/Cake/Console/cake.php @@ -19,6 +19,6 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR. 'ShellDispatcher.php'); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'ShellDispatcher.php'); return ShellDispatcher::run($argv); diff --git a/lib/Cake/bootstrap.php b/lib/Cake/bootstrap.php index 2696b06b1..21b2a1e6d 100644 --- a/lib/Cake/bootstrap.php +++ b/lib/Cake/bootstrap.php @@ -23,18 +23,21 @@ if (!defined('E_DEPRECATED')) { } error_reporting(E_ALL & ~E_DEPRECATED); -/** - * If the index.php file is used instead of an .htaccess file - * or if the user can not set the web root to use the public - * directory we will define ROOT there, otherwise we set it - * here. - */ - if (!defined('ROOT')) { - define('ROOT', '../'); - } - if (!defined('WEBROOT_DIR')) { - define('WEBROOT_DIR', 'webroot'); - } +if (!defined('CAKE_CORE_INCLUDE_PATH')) { + define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(__FILE__))); +} + +if (!defined('CORE_PATH')) { + define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); +} + +if (!defined('APP_PATH')) { + define('APP_PATH', ROOT . DS . APP_DIR . DS); +} + +if (!defined('WEBROOT_DIR')) { + define('WEBROOT_DIR', 'webroot'); +} /** * Path to the cake directory. From 20e9015f80ac88fbf20ae0382772dc2a38a6d7e3 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 30 Jul 2011 13:41:43 -0400 Subject: [PATCH 07/33] Making skel files generate hard coded paths, when CakePHP is not on the include_path, and exclude hard coded paths when it is. --- lib/Cake/Console/Command/Task/ProjectTask.php | 67 +++++++++++++------ .../Console/Templates/skel/Console/cake.php | 25 +++++-- .../Console/Templates/skel/webroot/index.php | 2 +- .../Console/Templates/skel/webroot/test.php | 2 +- 4 files changed, 69 insertions(+), 27 deletions(-) diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php index 3aa6c5184..cb72a2809 100644 --- a/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -97,20 +97,19 @@ class ProjectTask extends Shell { $success = false; } - $this->out(__d('cake_console', 'The value for CAKE_CORE_INCLUDE_PATH can be hardcoded set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH)); - $this->out(__d('cake_console', 'If you hard code it, the project will possibly run only in your computer.')); - $setConstants = $this->in(__d('cake_console', 'Do you want to set CAKE_CORE_INCLUDE_PATH in webroot/index.php?'), array('y', 'n'), 'n'); - if (strtolower($setConstants) === 'y') { - if ($this->corePath($path) === true) { - $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH)); - $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php', CAKE_CORE_INCLUDE_PATH)); - $this->out(__d('cake_console', ' * Remember to check these values after moving to production server')); - } else { - $this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' .DS .'index.php')); - $success = false; - } + $hardCode = false; + if (!$this->cakeOnIncludePath()) { + $this->out(__d('cake_console', 'CakePHP is not on your `include_path`, CAKE_CORE_INCLUDE_PATH will be hard coded.')); + $this->out(__d('cake_console', 'You can fix this by adding CakePHP to your `include_path`.')); + $hardCode = true; + } + if ($this->corePath($path, $hardCode) === true) { + $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH)); + $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php', CAKE_CORE_INCLUDE_PATH)); + $this->out(__d('cake_console', ' * Remember to check these values after moving to production server')); } else { - $this->out(__d('cake_console', 'Please make sure your cake core is accessible, if you have problems edit CAKE_CORE_INCLUDE_PATH in webroot/index.php')); + $this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' .DS .'index.php')); + $success = false; } $Folder = new Folder($path); @@ -128,6 +127,21 @@ class ProjectTask extends Shell { } } +/** + * Checks PHP's include_path for CakePHP. + * + * @return bool Indicates whether or not CakePHP exists on include_path + */ + public function cakeOnIncludePath() { + $paths = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($paths as $path) { + if (file_exists($path . DS . 'Cake' . DS . 'bootstrap.php')) { + return true; + } + } + return false; + } + /** * Looks for a skeleton template of a Cake application, * and if not found asks the user for a path. When there is a path @@ -225,8 +239,8 @@ class ProjectTask extends Shell { $File = new File($path . 'Console' . DS . 'cake.php'); $contents = $File->read(); if (preg_match('/(__CAKE_PATH__)/', $contents, $match)) { - $path = CAKE . 'Console' . DS; - $replacement = "'" . str_replace(DS, "' . DIRECTORY_SEPARATOR . '", $path) . "'"; + $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " \$ds . '" : "'"; + $replacement = $root . str_replace(DS, "' . \$ds . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'"; $result = str_replace($match[0], $replacement, $contents); if ($File->write($result)) { return true; @@ -285,13 +299,20 @@ class ProjectTask extends Shell { * @param string $path Project path * @return boolean Success */ - public function corePath($path) { + public function corePath($path, $hardCode = true) { + $prefix = $hardCode == true ? '' : '//'; + if (dirname($path) !== CAKE_CORE_INCLUDE_PATH) { $File = new File($path . 'webroot' . DS . 'index.php'); $contents = $File->read(); - if (preg_match('/([\s]*define\(\'CAKE_CORE_INCLUDE_PATH\',[\s\'A-z0-9\.]*\);)/', $contents, $match)) { - $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'"; - $result = str_replace($match[0], "\n\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents); + $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'"; + $corePath = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'"; + if (preg_match('#(\s*[/]+define\(\'CAKE_CORE_INCLUDE_PATH\', .*?\);)#', $contents, $match)) { + $result = str_replace( + $match[0], + "\n\t" . $prefix . "define('CAKE_CORE_INCLUDE_PATH', " . $corePath . ");", + $contents + ); if (!$File->write($result)) { return false; } @@ -301,8 +322,12 @@ class ProjectTask extends Shell { $File = new File($path . 'webroot' . DS . 'test.php'); $contents = $File->read(); - if (preg_match('/([\s]*define\(\'CAKE_CORE_INCLUDE_PATH\',[\s\'A-z0-9\.]*\);)/', $contents, $match)) { - $result = str_replace($match[0], "\n\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents); + if (preg_match('#(\s*[/]+define\(\'CAKE_CORE_INCLUDE_PATH\', .*?\);)#', $contents, $match)) { + $result = str_replace( + $match[0], + "\n\t" . $prefix . "define('CAKE_CORE_INCLUDE_PATH', " . $corePath . ");", + $contents + ); if (!$File->write($result)) { return false; } diff --git a/lib/Cake/Console/Templates/skel/Console/cake.php b/lib/Cake/Console/Templates/skel/Console/cake.php index 5c7d3f1f5..d77755334 100644 --- a/lib/Cake/Console/Templates/skel/Console/cake.php +++ b/lib/Cake/Console/Templates/skel/Console/cake.php @@ -3,8 +3,6 @@ /** * Command-line code generation utility to automate programmer chores. * - * Shell dispatcher class - * * PHP 5 * * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) @@ -16,9 +14,28 @@ * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project * @package app.Console - * @since CakePHP(tm) v 1.2.0.5012 + * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once(__CAKE_PATH__ . 'ShellDispatcher.php'); +$ds = DIRECTORY_SEPARATOR; +$dispatcher = 'Cake' . $ds . 'Console' . $ds . 'ShellDispatcher.php'; +$found = false; +$paths = explode(PATH_SEPARATOR, ini_get('include_path')); + +foreach ($paths as $path) { + if (file_exists($path . $ds . $dispatcher)) { + $found = $path; + } +} + +if (!$found && function_exists('ini_set')) { + $root = dirname(dirname(dirname(__FILE__))); + ini_set('include_path', __CAKE_PATH__ . PATH_SEPARATOR . ini_get('include_path')); +} + +if (!include($dispatcher)) { + trigger_error('Could not locate CakePHP core files.', E_USER_ERROR); +} +unset($paths, $path, $found, $dispatcher, $root, $ds); return ShellDispatcher::run($argv); diff --git a/lib/Cake/Console/Templates/skel/webroot/index.php b/lib/Cake/Console/Templates/skel/webroot/index.php index 2dced12c7..824565bcc 100644 --- a/lib/Cake/Console/Templates/skel/webroot/index.php +++ b/lib/Cake/Console/Templates/skel/webroot/index.php @@ -54,7 +54,7 @@ * For ease of development CakePHP uses PHP's include_path. If you * need to squeeze a bit more performance you can set this path. */ - //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); + //define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__); /** * Editing below this line should NOT be necessary. diff --git a/lib/Cake/Console/Templates/skel/webroot/test.php b/lib/Cake/Console/Templates/skel/webroot/test.php index f48bfb593..9f83f4315 100644 --- a/lib/Cake/Console/Templates/skel/webroot/test.php +++ b/lib/Cake/Console/Templates/skel/webroot/test.php @@ -51,7 +51,7 @@ ini_set('display_errors', 1); * For ease of development CakePHP uses PHP's include_path. If you * need to cannot modify your include_path, you can set this path. */ - //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); + //define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__); /** * Editing below this line should not be necessary. From 6e2870c706efe970fae9f239619beededfb39aec Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 31 Jul 2011 14:49:33 -0400 Subject: [PATCH 08/33] Removing APP_PATH it is always the same as APP. Fixing a typo in index.php. --- index.php | 6 ------ lib/Cake/Console/Command/CommandListShell.php | 2 +- lib/Cake/Console/Command/Task/ProjectTask.php | 2 +- lib/Cake/Console/Shell.php | 2 +- lib/Cake/Console/ShellDispatcher.php | 6 +++--- lib/Cake/bootstrap.php | 4 ---- 6 files changed, 6 insertions(+), 16 deletions(-) diff --git a/index.php b/index.php index 1dfeb30c8..10231902a 100644 --- a/index.php +++ b/index.php @@ -37,10 +37,4 @@ define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); } -/** - * Set the include path or define app and core path - */ - define('APP_PATH', ROOT . DS . APP_DIR . DS); - define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); - require APP_DIR . DS . WEBROOT_DIR . DS . 'index.php'; diff --git a/lib/Cake/Console/Command/CommandListShell.php b/lib/Cake/Console/Command/CommandListShell.php index ce3017081..9ffdf83e3 100644 --- a/lib/Cake/Console/Command/CommandListShell.php +++ b/lib/Cake/Console/Command/CommandListShell.php @@ -45,7 +45,7 @@ class CommandListShell extends Shell { if (empty($this->params['xml'])) { $this->out(__d('cake_console', "Current Paths:"), 2); $this->out(" -app: ". APP_DIR); - $this->out(" -working: " . rtrim(APP_PATH, DS)); + $this->out(" -working: " . rtrim(APP, DS)); $this->out(" -root: " . rtrim(ROOT, DS)); $this->out(" -core: " . rtrim(CORE_PATH, DS)); $this->out(""); diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php index cb72a2809..c88029cb8 100644 --- a/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -50,7 +50,7 @@ class ProjectTask extends Shell { while (!$project) { $prompt = __d('cake_console', "What is the path to the project you want to bake?"); - $project = $this->in($prompt, null, APP_PATH . 'myapp'); + $project = $this->in($prompt, null, APP . 'myapp'); } if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) { diff --git a/lib/Cake/Console/Shell.php b/lib/Cake/Console/Shell.php index 24b594ec3..2e1bd59e2 100644 --- a/lib/Cake/Console/Shell.php +++ b/lib/Cake/Console/Shell.php @@ -206,7 +206,7 @@ class Shell extends Object { $this->out(__d('cake_console', 'Welcome to CakePHP %s Console', 'v' . Configure::version())); $this->hr(); $this->out(__d('cake_console', 'App : %s', APP_DIR)); - $this->out(__d('cake_console', 'Path: %s', APP_PATH)); + $this->out(__d('cake_console', 'Path: %s', APP)); $this->hr(); } diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index 580440099..e188151c0 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -122,15 +122,15 @@ class ShellDispatcher { private function __bootstrap() { define('ROOT', $this->params['root']); define('APP_DIR', $this->params['app']); - define('APP_PATH', $this->params['working'] . DS); - define('WWW_ROOT', APP_PATH . $this->params['webroot'] . DS); + define('APP', $this->params['working'] . DS); + define('WWW_ROOT', APP . $this->params['webroot'] . DS); if (!is_dir(ROOT . DS . APP_DIR . DS . 'tmp')) { define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS); } $boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php'); require CORE_PATH . 'Cake' . DS . 'bootstrap.php'; - if (!file_exists(APP_PATH . 'Config' . DS . 'core.php')) { + if (!file_exists(APP . 'Config' . DS . 'core.php')) { include_once CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'Config' . DS . 'core.php'; App::build(); } diff --git a/lib/Cake/bootstrap.php b/lib/Cake/bootstrap.php index 21b2a1e6d..e034b5566 100644 --- a/lib/Cake/bootstrap.php +++ b/lib/Cake/bootstrap.php @@ -31,10 +31,6 @@ if (!defined('CORE_PATH')) { define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); } -if (!defined('APP_PATH')) { - define('APP_PATH', ROOT . DS . APP_DIR . DS); -} - if (!defined('WEBROOT_DIR')) { define('WEBROOT_DIR', 'webroot'); } From cdcabc79b675f3448b4ca73d4cdd4dd31bb73d9f Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 31 Jul 2011 15:15:03 -0400 Subject: [PATCH 09/33] Doing some refactoring in the project task. Adding tests for constants staying commented out when CakePHP is on the include_path. --- lib/Cake/Console/Command/Task/ProjectTask.php | 61 ++++++++++--------- .../Console/Command/Task/ProjectTaskTest.php | 29 +++++---- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php index c88029cb8..49d8fb099 100644 --- a/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -52,6 +52,7 @@ class ProjectTask extends Shell { $prompt = __d('cake_console', "What is the path to the project you want to bake?"); $project = $this->in($prompt, null, APP . 'myapp'); } + if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) { $project = $_SERVER['PWD'] . DS . $project; @@ -297,47 +298,49 @@ class ProjectTask extends Shell { * Generates and writes CAKE_CORE_INCLUDE_PATH * * @param string $path Project path + * @param bool $hardCode Wether or not define calls should be hardcoded. * @return boolean Success */ public function corePath($path, $hardCode = true) { - $prefix = $hardCode == true ? '' : '//'; - if (dirname($path) !== CAKE_CORE_INCLUDE_PATH) { - $File = new File($path . 'webroot' . DS . 'index.php'); - $contents = $File->read(); - $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'"; - $corePath = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'"; - if (preg_match('#(\s*[/]+define\(\'CAKE_CORE_INCLUDE_PATH\', .*?\);)#', $contents, $match)) { - $result = str_replace( - $match[0], - "\n\t" . $prefix . "define('CAKE_CORE_INCLUDE_PATH', " . $corePath . ");", - $contents - ); - if (!$File->write($result)) { - return false; - } - } else { + $filename = $path . 'webroot' . DS . 'index.php'; + if (!$this->_replaceCorePath($filename, $hardCode)) { return false; } - - $File = new File($path . 'webroot' . DS . 'test.php'); - $contents = $File->read(); - if (preg_match('#(\s*[/]+define\(\'CAKE_CORE_INCLUDE_PATH\', .*?\);)#', $contents, $match)) { - $result = str_replace( - $match[0], - "\n\t" . $prefix . "define('CAKE_CORE_INCLUDE_PATH', " . $corePath . ");", - $contents - ); - if (!$File->write($result)) { - return false; - } - } else { + $filename = $path . 'webroot' . DS . 'test.php'; + if (!$this->_replaceCorePath($filename, $hardCode)) { return false; } return true; } } +/** + * Replaces the __CAKE_PATH__ placeholder in the template files. + * + * @param string $filename The filename to operate on. + * @param boolean $hardCode Whether or not the define should be uncommented. + * @retun bool Success + */ + protected function _replaceCorePath($filename, $hardCode) { + $contents = file_get_contents($filename); + + $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'"; + $corePath = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'"; + + $result = str_replace('__CAKE_PATH__', $corePath, $contents, $count); + if ($hardCode) { + $result = str_replace('//define(\'CAKE_CORE', 'define(\'CAKE_CORE', $result); + } + if (!file_put_contents($filename, $result)) { + return false; + } + if ($count == 0) { + return false; + } + return true; + } + /** * Enables Configure::read('Routing.prefixes') in /app/Config/core.php * diff --git a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php index 2602fc17e..5daeb0c1f 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php @@ -118,37 +118,42 @@ class ProjectTaskTest extends CakeTestCase { $path = $this->Task->args[0] = TMP . 'tests' . DS . 'bake_test_app'; $this->Task->params['skel'] = CAKE . 'Console' . DS . 'Templates' . DS . 'skel'; $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y')); - $this->Task->expects($this->at(3))->method('in')->will($this->returnValue('n')); $this->Task->execute(); $this->assertTrue(is_dir($this->Task->args[0]), 'No project dir'); $file = new File($path . DS . 'webroot' . DS . 'index.php'); $contents = $file->read(); - $this->assertPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', ROOT/', $contents); + $this->assertPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents); $file = new File($path . DS . 'webroot' . DS . 'test.php'); $contents = $file->read(); - $this->assertPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', ROOT/', $contents); + $this->assertPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents); } /** - * test bake with setting CAKE_CORE_INCLUDE_PATH in webroot/index.php + * test bake with CakePHP on the include path. The constants should remain commented out. * * @return void */ - public function testExecuteWithSettingIncludePath() { + public function testExecuteWithCakeOnIncludePath() { + if (!function_exists('ini_set')) { + $this->markTestAsSkipped('Not access to ini_set, cannot proceed.'); + } + $restore = ini_get('include_path'); + ini_set('include_path', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . $restore); + $path = $this->Task->args[0] = TMP . 'tests' . DS . 'bake_test_app'; $this->Task->params['skel'] = CAKE . 'Console' . DS . 'Templates' . DS . 'skel'; $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y')); - $this->Task->expects($this->at(3))->method('in')->will($this->returnValue('y')); $this->Task->execute(); $this->assertTrue(is_dir($this->Task->args[0]), 'No project dir'); - $file = new File($path . DS . 'webroot' . DS . 'index.php'); - $contents = $file->read(); - $this->assertNoPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', ROOT/', $contents); - $file = new File($path . DS . 'webroot' . DS . 'test.php'); - $contents = $file->read(); - $this->assertNoPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', ROOT/', $contents); + $contents = file_get_contents($path . DS . 'webroot' . DS . 'index.php'); + $this->assertRegExp('#//define\(\'CAKE_CORE_INCLUDE_PATH#', $contents); + + $contents = file_get_contents($path . DS . 'webroot' . DS . 'test.php'); + $this->assertRegExp('#//define\(\'CAKE_CORE_INCLUDE_PATH#', $contents); + + ini_set('include_path', $restore); } /** From b362afee0695da3cd74f9792655e20651ef2c39e Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 31 Jul 2011 15:15:43 -0400 Subject: [PATCH 10/33] Changing assertPattern to assertRegExp. --- lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php index 5daeb0c1f..baec53707 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php @@ -123,10 +123,10 @@ class ProjectTaskTest extends CakeTestCase { $this->assertTrue(is_dir($this->Task->args[0]), 'No project dir'); $file = new File($path . DS . 'webroot' . DS . 'index.php'); $contents = $file->read(); - $this->assertPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents); + $this->assertRegExp('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents); $file = new File($path . DS . 'webroot' . DS . 'test.php'); $contents = $file->read(); - $this->assertPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents); + $this->assertRegExp('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents); } /** From b45e8eb0cd860b7c10ca351be5d01cc9da128e20 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 31 Jul 2011 15:26:43 -0400 Subject: [PATCH 11/33] Adding comments about CAKE_CORE_INCLUDE_PATH. Removing ini_set() blocks that don't need to exist. --- app/webroot/index.php | 2 ++ app/webroot/test.php | 2 ++ lib/Cake/Console/Templates/skel/webroot/index.php | 5 ++--- lib/Cake/Console/Templates/skel/webroot/test.php | 5 ++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/webroot/index.php b/app/webroot/index.php index 31901c223..b5b1d6392 100644 --- a/app/webroot/index.php +++ b/app/webroot/index.php @@ -53,6 +53,8 @@ * * For ease of development CakePHP uses PHP's include_path. If you * cannot modify your include_path set this value. + * + * Leaving this constant undefined will result in it being defined in Cake/bootstrap.php */ //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); diff --git a/app/webroot/test.php b/app/webroot/test.php index f48bfb593..b6caa107f 100644 --- a/app/webroot/test.php +++ b/app/webroot/test.php @@ -50,6 +50,8 @@ ini_set('display_errors', 1); * * For ease of development CakePHP uses PHP's include_path. If you * need to cannot modify your include_path, you can set this path. + * + * Leaving this constant undefined will result in it being defined in Cake/bootstrap.php */ //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); diff --git a/lib/Cake/Console/Templates/skel/webroot/index.php b/lib/Cake/Console/Templates/skel/webroot/index.php index 824565bcc..ab9465402 100644 --- a/lib/Cake/Console/Templates/skel/webroot/index.php +++ b/lib/Cake/Console/Templates/skel/webroot/index.php @@ -53,6 +53,8 @@ * * For ease of development CakePHP uses PHP's include_path. If you * need to squeeze a bit more performance you can set this path. + * + * Leaving this constant undefined will result in it being defined in Cake/bootstrap.php */ //define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__); @@ -69,9 +71,6 @@ } if (!defined('CAKE_CORE_INCLUDE_PATH')) { - if (function_exists('ini_set')) { - ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); - } if (!include('Cake' . DS . 'bootstrap.php')) { $failed = true; } diff --git a/lib/Cake/Console/Templates/skel/webroot/test.php b/lib/Cake/Console/Templates/skel/webroot/test.php index 9f83f4315..4931b069f 100644 --- a/lib/Cake/Console/Templates/skel/webroot/test.php +++ b/lib/Cake/Console/Templates/skel/webroot/test.php @@ -50,6 +50,8 @@ ini_set('display_errors', 1); * * For ease of development CakePHP uses PHP's include_path. If you * need to cannot modify your include_path, you can set this path. + * + * Leaving this constant undefined will result in it being defined in Cake/bootstrap.php */ //define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__); @@ -66,9 +68,6 @@ if (!defined('WWW_ROOT')) { } if (!defined('CAKE_CORE_INCLUDE_PATH')) { - if (function_exists('ini_set')) { - ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); - } if (!include('Cake' . DS . 'bootstrap.php')) { $failed = true; } From c1b0eb8f21533dd7f36b2997d017e91d9fc8d85e Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 3 Aug 2011 21:56:24 -0400 Subject: [PATCH 12/33] Updating output of project task to better reflect what happened. --- lib/Cake/Console/Command/Task/ProjectTask.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php index 49d8fb099..aa7727e13 100644 --- a/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -99,19 +99,24 @@ class ProjectTask extends Shell { } $hardCode = false; - if (!$this->cakeOnIncludePath()) { + if ($this->cakeOnIncludePath()) { + $this->out(__d('cake_console', 'CakePHP is on your `include_path`. CAKE_CORE_INCLUDE_PATH will be set, but commented out.')); + } else { $this->out(__d('cake_console', 'CakePHP is not on your `include_path`, CAKE_CORE_INCLUDE_PATH will be hard coded.')); $this->out(__d('cake_console', 'You can fix this by adding CakePHP to your `include_path`.')); $hardCode = true; } - if ($this->corePath($path, $hardCode) === true) { + $success = $this->corePath($path, $hardCode) === true; + if ($success) { $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH)); $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php', CAKE_CORE_INCLUDE_PATH)); - $this->out(__d('cake_console', ' * Remember to check these values after moving to production server')); } else { $this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' .DS .'index.php')); $success = false; } + if ($success && $hardCode) { + $this->out(__d('cake_console', ' * Remember to check these values after moving to production server')); + } $Folder = new Folder($path); if (!$Folder->chmod($path . 'tmp', 0777)) { From 5f84b4846c0c95a745d637ae6ee6ca28f0cc21e1 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 6 Aug 2011 09:44:49 -0400 Subject: [PATCH 13/33] Making long options & arguments replaced with short forms. Fixes #1882 --- lib/Cake/Console/HelpFormatter.php | 28 ++++++++++- .../Test/Case/Console/HelpFormatterTest.php | 50 ++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Console/HelpFormatter.php b/lib/Cake/Console/HelpFormatter.php index b5667f0aa..88f73caa5 100644 --- a/lib/Cake/Console/HelpFormatter.php +++ b/lib/Cake/Console/HelpFormatter.php @@ -29,6 +29,20 @@ App::uses('String', 'Utility'); * @since CakePHP(tm) v 2.0 */ class HelpFormatter { +/** + * The maximum number of arguments shown when generating usage. + * + * @var integer + */ + protected $_maxArgs = 6; + +/** + * The maximum number of options shown when generating usage. + * + * @var integer + */ + protected $_maxOptions = 6; + /** * Build the help formatter for a an OptionParser * @@ -122,12 +136,22 @@ class HelpFormatter { if (!empty($subcommands)) { $usage[] = '[subcommand]'; } + $options = array(); foreach ($this->_parser->options() as $option) { - $usage[] = $option->usage(); + $options[] = $option->usage(); } + if (count($options) > $this->_maxOptions){ + $options = array('[options]'); + } + $usage = array_merge($usage, $options); + $args = array(); foreach ($this->_parser->arguments() as $argument) { - $usage[] = $argument->usage(); + $args[] = $argument->usage(); } + if (count($args) > $this->_maxArgs) { + $args = array('[arguments]'); + } + $usage = array_merge($usage, $args); return implode(' ', $usage); } diff --git a/lib/Cake/Test/Case/Console/HelpFormatterTest.php b/lib/Cake/Test/Case/Console/HelpFormatterTest.php index 718db6818..60598c7b6 100644 --- a/lib/Cake/Test/Case/Console/HelpFormatterTest.php +++ b/lib/Cake/Test/Case/Console/HelpFormatterTest.php @@ -210,6 +210,54 @@ TEXT; $this->assertEquals($expected, $result, 'Help does not match'); } +/** + * Test that a long set of options doesn't make useless output. + * + * @return void + */ + public function testHelpWithLotsOfOptions() { + $parser = new ConsoleOptionParser('mycommand', false); + $parser + ->addOption('test', array('help' => 'A test option.')) + ->addOption('test2', array('help' => 'A test option.')) + ->addOption('test3', array('help' => 'A test option.')) + ->addOption('test4', array('help' => 'A test option.')) + ->addOption('test5', array('help' => 'A test option.')) + ->addOption('test6', array('help' => 'A test option.')) + ->addOption('test7', array('help' => 'A test option.')) + ->addArgument('model', array('help' => 'The model to make.', 'required' => true)) + ->addArgument('other_longer', array('help' => 'Another argument.')); + + $formatter = new HelpFormatter($parser); + $result = $formatter->text(); + $expected = 'cake mycommand [options] []'; + $this->assertContains($expected, $result); + } + +/** + * Test that a long set of arguments doesn't make useless output. + * + * @return void + */ + public function testHelpWithLotsOfArguments() { + $parser = new ConsoleOptionParser('mycommand', false); + $parser + ->addArgument('test', array('help' => 'A test option.')) + ->addArgument('test2', array('help' => 'A test option.')) + ->addArgument('test3', array('help' => 'A test option.')) + ->addArgument('test4', array('help' => 'A test option.')) + ->addArgument('test5', array('help' => 'A test option.')) + ->addArgument('test6', array('help' => 'A test option.')) + ->addArgument('test7', array('help' => 'A test option.')) + ->addArgument('model', array('help' => 'The model to make.', 'required' => true)) + ->addArgument('other_longer', array('help' => 'Another argument.')); + + $formatter = new HelpFormatter($parser); + $result = $formatter->text(); + $expected = 'cake mycommand [-h] [arguments]'; + $this->assertContains($expected, $result); + } + /** * test help() with options and arguments that have choices. * @@ -437,4 +485,4 @@ TEXT; $result = $formatter->xml(false); $this->assertInstanceOf('SimpleXmlElement', $result); } -} \ No newline at end of file +} From fb756c5aee34309f9e1c7caab6323ae7b7ee7e7c Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 6 Aug 2011 09:52:07 -0400 Subject: [PATCH 14/33] Fixing incorrectly inflected shell names in help. --- lib/Cake/Console/ConsoleOptionParser.php | 4 ++-- .../Test/Case/Console/ConsoleOptionParserTest.php | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Console/ConsoleOptionParser.php b/lib/Cake/Console/ConsoleOptionParser.php index 16a78112d..56a44197d 100644 --- a/lib/Cake/Console/ConsoleOptionParser.php +++ b/lib/Cake/Console/ConsoleOptionParser.php @@ -124,7 +124,7 @@ class ConsoleOptionParser { * this to false will prevent the addition of `--verbose` & `--quiet` options. */ public function __construct($command = null, $defaultOptions = true) { - $this->_command = $command; + $this->command($command); $this->addOption('help', array( 'short' => 'h', @@ -206,7 +206,7 @@ class ConsoleOptionParser { */ public function command($text = null) { if ($text !== null) { - $this->_command = $text; + $this->_command = Inflector::underscore($text); return $this; } return $this->_command; diff --git a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php index 9d9828ae6..1712b0d35 100644 --- a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php +++ b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php @@ -496,6 +496,16 @@ TEXT; $this->assertEquals('factory', $parser->command()); } +/** + * test that command() inflects the command name. + * + * @return void + */ + public function testCommandInflection() { + $parser = new ConsoleOptionParser('CommandLine'); + $this->assertEquals('command_line', $parser->command()); + } + /** * test that parse() takes a subcommand argument, and that the subcommand parser * is used. @@ -529,4 +539,4 @@ TEXT; $this->assertEquals($expected, $result, 'Sub parser did not parse request.'); } -} \ No newline at end of file +} From 10c78c54204581400b0735fe09e98e8712f4a5db Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 6 Aug 2011 13:45:55 -0400 Subject: [PATCH 15/33] Fixing bad include on text reporter. Fixing bad includes and updating usage in text coverage reports. --- lib/Cake/TestSuite/Coverage/TextCoverageReport.php | 4 ++-- lib/Cake/TestSuite/Reporter/CakeTextReporter.php | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/Cake/TestSuite/Coverage/TextCoverageReport.php b/lib/Cake/TestSuite/Coverage/TextCoverageReport.php index ceeb5ac6e..1739ef020 100644 --- a/lib/Cake/TestSuite/Coverage/TextCoverageReport.php +++ b/lib/Cake/TestSuite/Coverage/TextCoverageReport.php @@ -16,7 +16,7 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once dirname(__FILE__) . '/base_coverage_report.php'; +App::uses('BaseCoverageReport', 'TestSuite/Coverage'); PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); @@ -56,4 +56,4 @@ class TextCoverageReport extends BaseCoverageReport { return "$filename : $percentCovered%\n"; } -} \ No newline at end of file +} diff --git a/lib/Cake/TestSuite/Reporter/CakeTextReporter.php b/lib/Cake/TestSuite/Reporter/CakeTextReporter.php index 4c37530c4..763d880cc 100644 --- a/lib/Cake/TestSuite/Reporter/CakeTextReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeTextReporter.php @@ -17,7 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -include_once dirname(__FILE__) . DS . 'cake_base_reporter.php'; +App::uses('CakeBaseReporter', 'TestSuite/Reporter'); +App::uses('TextCoverageReport', 'TestSuite/Coverage'); PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); @@ -91,7 +92,7 @@ class CakeTextReporter extends CakeBaseReporter { echo 'Peak memory: ' . number_format(memory_get_peak_usage()) . " bytes\n"; if (isset($this->params['codeCoverage']) && $this->params['codeCoverage']) { - $coverage = $result->getCodeCoverageInformation(); + $coverage = $result->getCodeCoverage()->getSummary(); echo $this->paintCoverage($coverage); } } @@ -184,8 +185,6 @@ class CakeTextReporter extends CakeBaseReporter { * @return string */ public function paintCoverage($coverage) { - $file = dirname(dirname(__FILE__)) . '/coverage/text_coverage_report.php'; - include $file; $reporter = new TextCoverageReport($coverage, $this); echo $reporter->report(); } From b7391274fb7c16224b84f2fd23a9d6298e0cdede Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 6 Aug 2011 15:21:42 -0400 Subject: [PATCH 16/33] Adding an exception when a short option is longer than one character. Having long short options breaks parsing, and doesn't make sense with how short options are used. --- lib/Cake/Console/ConsoleInputOption.php | 5 +++++ lib/Cake/Console/ConsoleOptionParser.php | 12 +++++++++++- .../Test/Case/Console/ConsoleOptionParserTest.php | 12 ++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Console/ConsoleInputOption.php b/lib/Cake/Console/ConsoleInputOption.php index da1c69b0e..67b7d61a8 100644 --- a/lib/Cake/Console/ConsoleInputOption.php +++ b/lib/Cake/Console/ConsoleInputOption.php @@ -89,6 +89,11 @@ class ConsoleInputOption { $this->_default = $default; $this->_choices = $choices; } + if (strlen($this->_short) > 1) { + throw new ConsoleException( + __d('cake_console', 'Short options must be one letter.') + ); + } } /** diff --git a/lib/Cake/Console/ConsoleOptionParser.php b/lib/Cake/Console/ConsoleOptionParser.php index 56a44197d..2ce5ed918 100644 --- a/lib/Cake/Console/ConsoleOptionParser.php +++ b/lib/Cake/Console/ConsoleOptionParser.php @@ -41,7 +41,8 @@ App::uses('HelpFormatter', 'Console'); * * Options can be defined with both long and short forms. By using `$parser->addOption()` * you can define new options. The name of the option is used as its long form, and you - * can supply an additional short form, with the `short` option. + * can supply an additional short form, with the `short` option. Short options should + * only be one letter long. Using more than one letter for a short option will raise an exception. * * Calling options can be done using syntax similar to most *nix command line tools. Long options * cane either include an `=` or leave it out. @@ -52,6 +53,15 @@ App::uses('HelpFormatter', 'Console'); * * `cake myshell command -cn` * + * Short options can be combined into groups as seen above. Each letter in a group + * will be treated as a separate option. The previous example is equivalent to: + * + * `cake myshell command -c -n` + * + * Short options can also accept values: + * + * `cake myshell command -c default` + * * ### Positional arguments * * If no positional arguments are defined, all of them will be parsed. If you define positional diff --git a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php index 1712b0d35..88bad6fb0 100644 --- a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php +++ b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php @@ -139,6 +139,18 @@ class ConsoleOptionParserTest extends CakeTestCase { $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Short parameter did not parse out'); } +/** + * Test that adding an option using a two letter short value causes an exception. + * As they will not parse correctly. + * + * @expectedException ConsoleException + * @return void + */ + public function testAddOptionShortOneLetter() { + $parser = new ConsoleOptionParser('test', false); + $parser->addOption('test', array('short' => 'te')); + } + /** * test adding and using boolean options. * From 5d3c47087142cf2ddd588115d4c895bed65fd86b Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 6 Aug 2011 15:43:41 -0400 Subject: [PATCH 17/33] Fixing issues where option values started with '-'. --- lib/Cake/Console/ConsoleOptionParser.php | 19 ++++++++++++++++++- .../Case/Console/ConsoleOptionParserTest.php | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Console/ConsoleOptionParser.php b/lib/Cake/Console/ConsoleOptionParser.php index 2ce5ed918..4db276d65 100644 --- a/lib/Cake/Console/ConsoleOptionParser.php +++ b/lib/Cake/Console/ConsoleOptionParser.php @@ -572,7 +572,7 @@ class ConsoleOptionParser { $option = $this->_options[$name]; $isBoolean = $option->isBoolean(); $nextValue = $this->_nextToken(); - if (!$isBoolean && !empty($nextValue) && $nextValue{0} != '-') { + if (!$isBoolean && !empty($nextValue) && !$this->_optionExists($nextValue)) { array_shift($this->_tokens); $value = $nextValue; } elseif ($isBoolean) { @@ -586,6 +586,23 @@ class ConsoleOptionParser { } } + +/** + * Check to see if $name has an option (short/long) defined for it. + * + * @param string $name The name of the option. + * @return boolean + */ + protected function _optionExists($name) { + if (substr($name, 0, 2) === '--') { + return isset($this->_options[substr($name, 2)]); + } + if ($name{0} === '-' && $name{1} !== '-') { + return isset($this->_shortOptions[$name{1}]); + } + return false; + } + /** * Parse an argument, and ensure that the argument doesn't exceed the number of arguments * and that the argument is a valid choice. diff --git a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php index 88bad6fb0..bc702a745 100644 --- a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php +++ b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php @@ -267,6 +267,21 @@ class ConsoleOptionParserTest extends CakeTestCase { $result = $parser->parse(array('--name', 'jimmy')); } +/** + * Ensure that option values can start with - + * + * @return void + */ + public function testOptionWithValueStartingWithMinus() { + $parser = new ConsoleOptionParser('test', false); + $parser->addOption('name') + ->addOption('age'); + + $result = $parser->parse(array('--name', '-foo', '--age', 'old')); + $expected = array('name' => '-foo', 'age' => 'old', 'help' => false); + $this->assertEquals($expected, $result[0], 'Option values starting with "-" are broken.'); + } + /** * test positional argument parsing. * From 2f079b33dda893cd4bc734b18da784e981295309 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sat, 6 Aug 2011 16:26:58 -0400 Subject: [PATCH 18/33] Fixing issues output xml help. --- lib/Cake/Console/Shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Shell.php b/lib/Cake/Console/Shell.php index 2e1bd59e2..9d2ba2950 100644 --- a/lib/Cake/Console/Shell.php +++ b/lib/Cake/Console/Shell.php @@ -389,7 +389,7 @@ class Shell extends Object { $format = 'text'; if (!empty($this->args[0]) && $this->args[0] == 'xml') { $format = 'xml'; - $this->output->outputAs(ConsoleOutput::RAW); + $this->stdout->outputAs(ConsoleOutput::RAW); } else { $this->_welcome(); } From be262f30f093765c26e5e4ac15cf85218b1a2f2d Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 6 Aug 2011 21:12:48 -0400 Subject: [PATCH 19/33] Fixing notice errors caused by undefined property. --- lib/Cake/Console/ConsoleOptionParser.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/Cake/Console/ConsoleOptionParser.php b/lib/Cake/Console/ConsoleOptionParser.php index 4db276d65..063ba9eff 100644 --- a/lib/Cake/Console/ConsoleOptionParser.php +++ b/lib/Cake/Console/ConsoleOptionParser.php @@ -126,6 +126,13 @@ class ConsoleOptionParser { */ protected $_subcommands = array(); +/** + * Command name. + * + * @var string + */ + protected $_command = ''; + /** * Construct an OptionParser so you can define its behavior * From e4a7c8f3d79a44238b90dcb75ac038156d4d8b73 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 6 Aug 2011 21:15:31 -0400 Subject: [PATCH 20/33] Cleanup of minor issues found with phpmd. --- lib/Cake/Controller/Controller.php | 4 ++-- lib/Cake/Core/Configure.php | 2 +- lib/Cake/Log/CakeLog.php | 2 +- lib/Cake/Network/CakeRequest.php | 2 +- lib/Cake/Network/CakeResponse.php | 1 - lib/Cake/Routing/Route/CakeRoute.php | 9 ++++----- lib/Cake/Utility/Set.php | 21 --------------------- 7 files changed, 9 insertions(+), 32 deletions(-) diff --git a/lib/Cake/Controller/Controller.php b/lib/Cake/Controller/Controller.php index a9ef54f20..079c83c4b 100644 --- a/lib/Cake/Controller/Controller.php +++ b/lib/Cake/Controller/Controller.php @@ -491,7 +491,7 @@ class Controller extends Object { if (!$privateAction && !empty($prefixes)) { if (empty($request->params['prefix']) && strpos($request->params['action'], '_') > 0) { - list($prefix, $action) = explode('_', $request->params['action']); + list($prefix) = explode('_', $request->params['action']); $privateAction = in_array($prefix, $prefixes); } } @@ -877,7 +877,7 @@ class Controller extends Object { $currentObject = ClassRegistry::getObject($currentModel); if (is_a($currentObject, 'Model')) { $className = get_class($currentObject); - list($plugin, $package) = pluginSplit(App::location($className)); + list($plugin) = pluginSplit(App::location($className)); $this->request->params['models'][$currentObject->alias] = compact('plugin', 'className'); $View->validationErrors[$currentObject->alias] =& $currentObject->validationErrors; } diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php index 0add376a2..d91ee6d96 100644 --- a/lib/Cake/Core/Configure.php +++ b/lib/Cake/Core/Configure.php @@ -320,7 +320,7 @@ class Configure { */ public static function version() { if (!isset(self::$_values['Cake']['version'])) { - require(CAKE . 'Config' . DS . 'config.php'); + require CAKE . 'Config' . DS . 'config.php'; self::write($config); } return self::$_values['Cake']['version']; diff --git a/lib/Cake/Log/CakeLog.php b/lib/Cake/Log/CakeLog.php index 5bc37ae05..ecb685dbf 100644 --- a/lib/Cake/Log/CakeLog.php +++ b/lib/Cake/Log/CakeLog.php @@ -190,7 +190,7 @@ class CakeLog { if (empty(self::$_streams)) { self::_autoConfig(); } - foreach (self::$_streams as $key => $logger) { + foreach (self::$_streams as $logger) { $logger->write($type, $message); } return true; diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php index eff630f1f..257d8ae30 100644 --- a/lib/Cake/Network/CakeRequest.php +++ b/lib/Cake/Network/CakeRequest.php @@ -613,7 +613,7 @@ class CakeRequest implements ArrayAccess { $acceptTypes = explode(',', $this->header('accept')); foreach ($acceptTypes as $i => $accepted) { if (strpos($accepted, ';') !== false) { - list($accepted, $prefValue) = explode(';', $accepted); + list($accepted) = explode(';', $accepted); $acceptTypes[$i] = $accepted; } } diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 57a6d9f6d..fe9534fe2 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -572,7 +572,6 @@ class CakeResponse { if (is_array($ctype)) { return array_map(array($this, 'mapType'), $ctype); } - $keys = array_keys($this->_mimeTypes); foreach ($this->_mimeTypes as $alias => $types) { if (is_array($types) && in_array($ctype, $types)) { diff --git a/lib/Cake/Routing/Route/CakeRoute.php b/lib/Cake/Routing/Route/CakeRoute.php index 79ae86bd0..23c473848 100644 --- a/lib/Cake/Routing/Route/CakeRoute.php +++ b/lib/Cake/Routing/Route/CakeRoute.php @@ -156,7 +156,7 @@ class CakeRoute { } $names[] = $name; } - if (preg_match('#\/\*$#', $route, $m)) { + if (preg_match('#\/\*$#', $route)) { $parsed = preg_replace('#/\\\\\*$#', '(?:/(?P<_args_>.*))?', $parsed); $this->_greedy = true; } @@ -281,7 +281,7 @@ class CakeRoute { if ((!isset($this->options['named']) || !empty($this->options['named'])) && $separatorIsPresent) { list($key, $val) = explode($namedConfig['separator'], $param, 2); $hasRule = isset($rules[$key]); - $passIt = (!$hasRule && !$greedy) || ($hasRule && !$this->_matchNamed($key, $val, $rules[$key], $context)); + $passIt = (!$hasRule && !$greedy) || ($hasRule && !$this->_matchNamed($val, $rules[$key], $context)); if ($passIt) { $pass[] = $param; } else { @@ -314,13 +314,12 @@ class CakeRoute { * Return true if a given named $param's $val matches a given $rule depending on $context. Currently implemented * rule types are controller, action and match that can be combined with each other. * - * @param string $param The name of the named parameter * @param string $val The value of the named parameter * @param array $rule The rule(s) to apply, can also be a match string * @param string $context An array with additional context information (controller / action) * @return boolean */ - protected function _matchNamed($param, $val, $rule, $context) { + protected function _matchNamed($val, $rule, $context) { if ($rule === true || $rule === false) { return $rule; } @@ -512,4 +511,4 @@ class CakeRoute { return $out; } -} \ No newline at end of file +} diff --git a/lib/Cake/Utility/Set.php b/lib/Cake/Utility/Set.php index bd4c742ed..4efd43563 100644 --- a/lib/Cake/Utility/Set.php +++ b/lib/Cake/Utility/Set.php @@ -130,27 +130,6 @@ class Set { return Set::__map($val, $class); } -/** - * Get the array value of $array. If $array is null, it will return - * the current array Set holds. If it is an object of type Set, it - * will return its value. If it is another object, its object variables. - * If it is anything else but an array, it will return an array whose first - * element is $array. - * - * @param mixed $array Data from where to get the array. - * @return array Array from $array. - */ - private function __array($array) { - if (empty($array)) { - $array = array(); - } elseif (is_object($array)) { - $array = get_object_vars($array); - } elseif (!is_array($array)) { - $array = array($array); - } - return $array; - } - /** * Maps the given value as an object. If $value is an object, * it returns $value. Otherwise it maps $value as an object of From 5330096019f10315d64df662738aa24189c10577 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 7 Aug 2011 09:14:16 -0400 Subject: [PATCH 21/33] Fixing parameter name in RssHelper docs. Fixes #1888 --- lib/Cake/View/Helper/RssHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/View/Helper/RssHelper.php b/lib/Cake/View/Helper/RssHelper.php index 5fbc8c2b6..686a096ea 100644 --- a/lib/Cake/View/Helper/RssHelper.php +++ b/lib/Cake/View/Helper/RssHelper.php @@ -187,7 +187,7 @@ class RssHelper extends AppHelper { /** * Converts an array into an `` element and its contents * - * @param array $attrib The attributes of the `` element + * @param array $att The attributes of the `` element * @param array $elements The list of elements contained in this `` * @return string An RSS `` element */ From 4ab9dedd58987bc9e04a8dd6b16deb17639060e9 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 7 Aug 2011 14:31:14 -0400 Subject: [PATCH 22/33] Updating doc blocks in Debugger and CakeLog. --- lib/Cake/Log/CakeLog.php | 19 ++++++++++++++----- lib/Cake/Utility/Debugger.php | 31 ++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lib/Cake/Log/CakeLog.php b/lib/Cake/Log/CakeLog.php index ecb685dbf..120247ca1 100644 --- a/lib/Cake/Log/CakeLog.php +++ b/lib/Cake/Log/CakeLog.php @@ -42,6 +42,19 @@ * using CakeLogs's methods. If you don't configure any adapters, and write to the logs * a default FileLog will be autoconfigured for you. * + * ### Configuring Log adapters + * + * You can configure log adapters in your applications `bootstrap.php` file. A sample configuration + * would look like: + * + * `CakeLog::config('my_log', array('engine' => 'FileLog'));` + * + * See the documentation on CakeLog::config() for more detail. + * + * ### Writing to the log + * + * You write to the logs using CakeLog::write(). See its documentation for more information. + * * @package Cake.Log */ class CakeLog { @@ -69,11 +82,7 @@ class CakeLog { * * Will configure a FileLog instance to use the specified path. All options that are not `engine` * are passed onto the logging adapter, and handled there. Any class can be configured as a logging - * adapter as long as it implements a `write` method with the following signature. - * - * `write($type, $message)` - * - * For an explaination of these parameters, see CakeLog::write() + * adapter as long as it implements the methods in CakeLogInterface. * * @param string $key The keyname for this logger, used to remove the logger later. * @param array $config Array of configuration information for the logger diff --git a/lib/Cake/Utility/Debugger.php b/lib/Cake/Utility/Debugger.php index 69dd68511..a44fad5d2 100644 --- a/lib/Cake/Utility/Debugger.php +++ b/lib/Cake/Utility/Debugger.php @@ -191,14 +191,15 @@ class Debugger { } /** - * Formats and outputs the contents of the supplied variable. + * Recursively formats and outputs the contents of the supplied variable. + * * * @param $var mixed the variable to dump * @return void * @see Debugger::exportVar() * @static * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class -*/ + */ public static function dump($var) { pr(self::exportVar($var)); } @@ -405,12 +406,22 @@ class Debugger { } /** - * Grabs an excerpt from a file and highlights a given line of code + * Grabs an excerpt from a file and highlights a given line of code. + * + * Usage: + * + * `Debugger::excerpt('/path/to/file', 100, 4);` + * + * The above would return an array of 8 items. The 4th item would be the provided line, + * and would be wrapped in ``. All of the lines + * are processed with highlight_string() as well, so they have basic PHP syntax highlighting + * applied. * * @param string $file Absolute path to a PHP file * @param integer $line Line number to highlight * @param integer $context Number of lines of context to extract above and below $line * @return array Set of lines highlighted + * @see http://php.net/highlight_string * @static * @link http://book.cakephp.org/view/1191/Using-the-Debugger-Class */ @@ -441,6 +452,20 @@ class Debugger { /** * Converts a variable to a string for debug output. * + * *Note:* The following keys will have their contents replaced with + * `*****`: + * + * - password + * - login + * - host + * - database + * - port + * - prefix + * - schema + * + * This is done to protect database credentials, which could be accidentally + * shown in an error message if CakePHP is deployed in development mode. + * * @param string $var Variable to convert * @return string Variable as a formatted string * @static From a268eea24fc13c5544ef8bba9b15f20155e286de Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 7 Aug 2011 18:16:21 -0400 Subject: [PATCH 23/33] Expanding docs on HtmlHelper. --- lib/Cake/View/Helper/HtmlHelper.php | 74 +++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/lib/Cake/View/Helper/HtmlHelper.php b/lib/Cake/View/Helper/HtmlHelper.php index 52297543f..b609a03c7 100644 --- a/lib/Cake/View/Helper/HtmlHelper.php +++ b/lib/Cake/View/Helper/HtmlHelper.php @@ -156,7 +156,16 @@ class HtmlHelper extends AppHelper { ); /** - * Default Constructor + * Constructor + * + * ### Settings + * + * - `configFile` A file containing an array of tags you wish to redefine. + * + * ### Customizing tag sets + * + * Using the `configFile` option you can redefine the tag HtmlHelper will use. + * The file named should be compatible with HtmlHelper::loadConfig(). * * @param View $View The View this helper is being attached to. * @param array $settings Configuration settings for the helper. @@ -357,6 +366,20 @@ class HtmlHelper extends AppHelper { /** * Creates a link element for CSS stylesheets. * + * ### Usage + * + * Include one CSS file: + * + * `echo $this->Html->css('styles.css');` + * + * Include multiple CSS files: + * + * `echo $this->Html->css(array('one.css', 'two.css'));` + * + * Add the stylesheet to the `$scripts_for_layout` layout var: + * + * `$this->Html->css('styles.css', null, array('inline' => false));` + * * ### Options * * - `inline` If set to false, the generated tag appears in the head tag of the layout. Defaults to true @@ -427,7 +450,20 @@ class HtmlHelper extends AppHelper { * If the filename is prefixed with "/", the path will be relative to the base path of your * application. Otherwise, the path will be relative to your JavaScript path, usually webroot/js. * - * Can include one or many Javascript files. + * + * ### Usage + * + * Include one script file: + * + * `echo $this->Html->script('styles.js');` + * + * Include multiple script files: + * + * `echo $this->Html->script(array('one.js', 'two.js'));` + * + * Add the script file to the `$scripts_for_layout` layout var: + * + * `$this->Html->script('styles.js', null, array('inline' => false));` * * ### Options * @@ -922,7 +958,39 @@ class HtmlHelper extends AppHelper { } /** - * Load Html configs + * Load Html tag configuration. + * + * Loads a file from APP/Config that contains tag data. By default the file is expected + * to be compatible with PhpReader: + * + * `$this->Html->loadConfig('tags.php');` + * + * tags.php could look like: + * + * {{{ + * $tags = array( + * 'meta' => '' + * ); + * }}} + * + * If you wish to store tag definitions in another format you can give an array + * containing the file name, and reader class name: + * + * `$this->Html->loadConfig(array('tags.ini', 'ini'));` + * + * Its expected that the `tags` index will exist from any configuration file that is read. + * You can also specify the path to read the configuration file from, if APP/Config is not + * where the file is. + * + * `$this->Html->loadConfig('tags.php', APP . 'Lib' . DS);` + * + * Configuration files can define the following sections: + * + * - `tags` The tags to replace. + * - `minimizedAttributes` The attributes that are represented like `disabled="disabled"` + * - `docTypes` Additional doctypes to use. + * - `attributeFormat` Format for long attributes e.g. `'%s="%s"'` + * - `minimizedAttributeFormat` Format for minimized attributes e.g. `'%s="%s"'` * * @param mixed $configFile String with the config file (load using PhpReader) or an array with file and reader name * @param string $path Path with config file From 95f3eb48f9d8a938e48d61402fa2287ee9aa48c9 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 7 Aug 2011 18:17:06 -0400 Subject: [PATCH 24/33] Fixing plugin option + locations subcommand. --- lib/Cake/Console/Command/UpgradeShell.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Cake/Console/Command/UpgradeShell.php b/lib/Cake/Console/Command/UpgradeShell.php index 1f6ec682c..0c393faec 100644 --- a/lib/Cake/Console/Command/UpgradeShell.php +++ b/lib/Cake/Console/Command/UpgradeShell.php @@ -71,6 +71,10 @@ class UpgradeShell extends Shell { public function locations() { $cwd = getcwd(); + if (!empty($this->params['plugin'])) { + chdir(App::pluginPath($this->params['plugin'])); + } + if (is_dir('plugins')) { $Folder = new Folder('plugins'); From 7ab1805bd95e3b314580569da76d64ffcb2ab196 Mon Sep 17 00:00:00 2001 From: Maggion Emmanuel Date: Tue, 9 Aug 2011 13:03:32 +0300 Subject: [PATCH 25/33] Adding `cake_dev` domain --- lib/Cake/Model/Behavior/AclBehavior.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Model/Behavior/AclBehavior.php b/lib/Cake/Model/Behavior/AclBehavior.php index 692f0d150..72624fb7e 100644 --- a/lib/Cake/Model/Behavior/AclBehavior.php +++ b/lib/Cake/Model/Behavior/AclBehavior.php @@ -73,7 +73,7 @@ class AclBehavior extends ModelBehavior { if (empty($type)) { $type = $this->__typeMaps[$this->settings[$model->name]['type']]; if (is_array($type)) { - trigger_error(__('AclBehavior is setup with more then one type, please specify type parameter for node()', true), E_USER_WARNING); + trigger_error(__d('cake_dev', 'AclBehavior is setup with more then one type, please specify type parameter for node()'), E_USER_WARNING); return null; } } From cb5f57f0ed88bb1103713b3e921b5774b941d804 Mon Sep 17 00:00:00 2001 From: Maggion Emmanuel Date: Tue, 9 Aug 2011 17:02:00 +0300 Subject: [PATCH 26/33] Adding support for url input --- lib/Cake/View/Helper/FormHelper.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 7c9bc4062..c81ec95a5 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1072,6 +1072,11 @@ class FormHelper extends AppHelper { case 'textarea': $input = $this->textarea($fieldName, $options + array('cols' => '30', 'rows' => '6')); break; + case 'url': + $options = $this->_initInputField($fieldName, $options); + $options['type'] = 'url'; + $input = $this->Html->useTag('input', $options['name'], $options); + break; default: $input = $this->{$type}($fieldName, $options); } From 48e681424f97e8cee17cb11548873c318a3491d9 Mon Sep 17 00:00:00 2001 From: Majna Date: Tue, 9 Aug 2011 16:24:41 +0200 Subject: [PATCH 27/33] Fix for wrong 'cake_dev' i18n domain param. --- lib/Cake/Utility/Folder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Utility/Folder.php b/lib/Cake/Utility/Folder.php index 1bce16e05..d4d733e47 100644 --- a/lib/Cake/Utility/Folder.php +++ b/lib/Cake/Utility/Folder.php @@ -368,7 +368,7 @@ class Folder { if (@chmod($fullpath, intval($mode, 8))) { $this->__messages[] = __d('cake_dev', '%s changed to %s', $fullpath, $mode); } else { - $this->__errors[] = __d('cake_deverloper', '%s NOT changed to %s', $fullpath, $mode); + $this->__errors[] = __d('cake_dev', '%s NOT changed to %s', $fullpath, $mode); } } } From 6cd89b09925e1bd9d8b946627106be5b2f1d46b6 Mon Sep 17 00:00:00 2001 From: Maggion Emmanuel Date: Tue, 9 Aug 2011 17:59:55 +0300 Subject: [PATCH 28/33] Edited lib/Cake/View/Helper/FormHelper.php via GitHub --- lib/Cake/View/Helper/FormHelper.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index c81ec95a5..a696aecbc 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1073,9 +1073,7 @@ class FormHelper extends AppHelper { $input = $this->textarea($fieldName, $options + array('cols' => '30', 'rows' => '6')); break; case 'url': - $options = $this->_initInputField($fieldName, $options); - $options['type'] = 'url'; - $input = $this->Html->useTag('input', $options['name'], $options); + $input = $this->text($fieldName, array('type' => 'url') + $options); break; default: $input = $this->{$type}($fieldName, $options); From 27734507e4aab0b76d1aa0aa179a7ad371bd5af0 Mon Sep 17 00:00:00 2001 From: Maggion Emmanuel Date: Tue, 9 Aug 2011 20:47:25 +0300 Subject: [PATCH 29/33] Adding test case --- lib/Cake/Test/Case/View/Helper/FormHelperTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index a1f15255a..b0a9240cd 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -7318,6 +7318,12 @@ class FormHelperTest extends CakeTestCase { 'input' => array('type' => 'text', 'name' => 'data[User][query]', 'id' => 'UserQuery', 'value' => 'test') ); $this->assertTags($result, $expected); + + $result = $this->Form->input('User.website', array('type' => 'url', 'value' => 'http://domain.tld', 'div' => false, 'label' => false)); + $expected = array( + 'input' => array('type' => 'url', 'name' => 'data[User][website]', 'id' => 'UserWebsite', 'value' => 'http://domain.tld') + ); + $this->assertTags($result, $expected); } /** From 826001adc7de69e13a5520455f3b302f00d673a3 Mon Sep 17 00:00:00 2001 From: Majna Date: Wed, 10 Aug 2011 16:55:05 +0200 Subject: [PATCH 30/33] Added doc blocks for WincacheEngine. Fixed Memcache doc block. --- app/Config/core.php | 17 +++++++++++------ lib/Cake/Cache/Cache.php | 3 ++- lib/Cake/Console/Templates/skel/Config/core.php | 17 +++++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/app/Config/core.php b/app/Config/core.php index ebe0ece58..dcbe655ba 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -247,7 +247,6 @@ * 'serialize' => true, [optional] * )); * - * * APC (http://pecl.php.net/package/APC) * * Cache::config('default', array( @@ -263,12 +262,11 @@ * 'engine' => 'Xcache', //[required] * 'duration'=> 3600, //[optional] * 'probability'=> 100, //[optional] - * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string + * '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) + * 'password' => 'password', //plaintext password (xcache.admin.pass) * )); * - * * Memcache (http://www.danga.com/memcached/) * * Cache::config('default', array( @@ -281,9 +279,16 @@ * ), //[optional] * 'persistent' => true, // [optional] set this to false for non-persistent connections * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory) - * 'persistent' => true, // [optional] set this to false for non-persistent connections * )); + * + * 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 + * )); */ /** @@ -315,7 +320,7 @@ Cache::config('_cake_core_', array( )); /** - * Configure the cache for model, and datasource caches. This cache configuration + * Configure the cache for model and datasource caches. This cache configuration * is used to store schema descriptions, and table listings in connections. */ Cache::config('_cake_model_', array( diff --git a/lib/Cake/Cache/Cache.php b/lib/Cake/Cache/Cache.php index 5cb7c1a52..ee3a937ad 100644 --- a/lib/Cake/Cache/Cache.php +++ b/lib/Cake/Cache/Cache.php @@ -82,7 +82,7 @@ class Cache { * * `Cache::config('default');` * - * There are 4 built-in caching engines: + * There are 5 built-in caching engines: * * - `FileEngine` - Uses simple files to store content. Poor performance, but good for * storing large objects, or things that are not IO sensitive. @@ -90,6 +90,7 @@ class Cache { * - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage. * Fast reads/writes, and benefits from memcache being distributed. * - `XcacheEngine` - Uses the Xcache extension, an alternative to APC. + * - `WincacheEngine` - Uses Windows Cache Extension for PHP. Supports wincache 1.1.0 and higher. * * The following keys are used in core cache engines: * diff --git a/lib/Cake/Console/Templates/skel/Config/core.php b/lib/Cake/Console/Templates/skel/Config/core.php index f201304ba..418285638 100644 --- a/lib/Cake/Console/Templates/skel/Config/core.php +++ b/lib/Cake/Console/Templates/skel/Config/core.php @@ -247,7 +247,6 @@ * 'serialize' => true, [optional] * )); * - * * APC (http://pecl.php.net/package/APC) * * Cache::config('default', array( @@ -263,12 +262,11 @@ * 'engine' => 'Xcache', //[required] * 'duration'=> 3600, //[optional] * 'probability'=> 100, //[optional] - * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string + * '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) + * 'password' => 'password', //plaintext password (xcache.admin.pass) * )); * - * * Memcache (http://www.danga.com/memcached/) * * Cache::config('default', array( @@ -281,9 +279,16 @@ * ), //[optional] * 'persistent' => true, // [optional] set this to false for non-persistent connections * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory) - * 'persistent' => true, // [optional] set this to false for non-persistent connections * )); + * + * 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 + * )); */ /** @@ -315,7 +320,7 @@ Cache::config('_cake_core_', array( )); /** - * Configure the cache for model, and datasource caches. This cache configuration + * Configure the cache for model and datasource caches. This cache configuration * is used to store schema descriptions, and table listings in connections. */ Cache::config('_cake_model_', array( From e9382d08972b9d483bab775a5b06f3d8262b4a10 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 10 Aug 2011 21:40:53 -0400 Subject: [PATCH 31/33] Fixing failing tests. --- lib/Cake/Test/Case/View/Helper/FormHelperTest.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index b0a9240cd..d82dfbc16 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -1703,7 +1703,7 @@ class FormHelperTest extends CakeTestCase { 'label' => array('for'), 'Balance', '/label', - 'input' => array('name', 'type' => 'text', 'maxlength' => 8, 'id'), + 'input' => array('name', 'type' => 'number', 'maxlength' => 8, 'id'), '/div', ); $this->assertTags($result, $expected); @@ -2508,6 +2508,8 @@ class FormHelperTest extends CakeTestCase { '*/div', array('div' => array('class' => 'input datetime')), '*/div', + array('div' => array('class' => 'input number')), + '*/div', array('div' => array('class' => 'input select')), '*/div', ); @@ -2531,6 +2533,8 @@ class FormHelperTest extends CakeTestCase { '*/div', array('div' => array('class' => 'input datetime')), '*/div', + array('div' => array('class' => 'input number')), + '*/div', array('div' => array('class' => 'input select')), '*/div', ); @@ -2555,6 +2559,8 @@ class FormHelperTest extends CakeTestCase { '*/div', array('div' => array('class' => 'input datetime')), '*/div', + array('div' => array('class' => 'input number')), + '*/div', array('div' => array('class' => 'input select')), '*/div', '/fieldset' @@ -2579,6 +2585,8 @@ class FormHelperTest extends CakeTestCase { '*/div', array('div' => array('class' => 'input datetime')), '*/div', + array('div' => array('class' => 'input number')), + '*/div', array('div' => array('class' => 'input select')), '*/div', ); @@ -2606,6 +2614,8 @@ class FormHelperTest extends CakeTestCase { '*/div', array('div' => array('class' => 'input datetime')), '*/div', + array('div' => array('class' => 'input number')), + '*/div', array('div' => array('class' => 'input select')), '*/div', '/fieldset' @@ -2634,6 +2644,8 @@ class FormHelperTest extends CakeTestCase { '*/div', array('div' => array('class' => 'input datetime')), '*/div', + array('div' => array('class' => 'input number')), + '*/div', array('div' => array('class' => 'input select')), '*/div', '/fieldset' From 2ce2d06de2f27fc9d228415a25a7e49276561d7c Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 10 Aug 2011 21:53:33 -0400 Subject: [PATCH 32/33] Fixing issue where postLink() would fail when used with SecurityComponent. --- .../Test/Case/View/Helper/FormHelperTest.php | 34 ++++++++++++--- lib/Cake/View/Helper/FormHelper.php | 41 +++++++++++++------ 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index d82dfbc16..e6a988a0d 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -5713,9 +5713,7 @@ class FormHelperTest extends CakeTestCase { 'method' => 'post', 'action' => '/posts/delete/1', 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;' ), - 'div' => array('style' => 'display:none;'), 'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST'), - '/div', '/form', 'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'), 'Delete', @@ -5728,9 +5726,7 @@ class FormHelperTest extends CakeTestCase { 'method' => 'post', 'action' => '/posts/delete/1', 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;' ), - 'div' => array('style' => 'display:none;'), 'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST'), - '/div', '/form', 'a' => array('href' => '#', 'onclick' => 'preg:/if \(confirm\('Confirm\?'\)\) \{ document\.post_\w+\.submit\(\); \} event\.returnValue = false; return false;/'), 'Delete', @@ -5738,7 +5734,35 @@ class FormHelperTest extends CakeTestCase { )); $result = $this->Form->postLink('Delete', '/posts/delete', array('data' => array('id' => 1))); - $this->assertTrue(strpos($result, '') !== false); + $this->assertContains('', $result); + } + +/** + * Test that postLink adds _Token fields. + * + * @return void + */ + public function testSecurePostLink() { + $this->Form->request->params['_Token'] = array('key' => 'testkey'); + + $result = $this->Form->postLink('Delete', '/posts/delete/1'); + $expected = array( + 'form' => array( + 'method' => 'post', 'action' => '/posts/delete/1', + 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;' + ), + array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')), + 'div' => array('style' => 'display:none;'), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), + '/div', + '/form', + 'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'), + 'Delete', + '/a' + ); + $this->assertTags($result, $expected); } /** diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index a696aecbc..a721e15cf 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -439,18 +439,7 @@ class FormHelper extends AppHelper { $htmlAttributes = array_merge($options, $htmlAttributes); $this->fields = array(); - if (!empty($this->request->params['_Token'])) { - $append .= $this->hidden('_Token.key', array( - 'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(), - 'secure' => self::SECURE_SKIP - )); - - if (!empty($this->request['_Token']['unlockedFields'])) { - foreach ((array)$this->request['_Token']['unlockedFields'] as $unlocked) { - $this->_unlockedFields[] = $unlocked; - } - } - } + $append .= $this->_csrfField(); if (!empty($append)) { $append = $this->Html->useTag('block', ' style="display:none;"', $append); @@ -462,6 +451,27 @@ class FormHelper extends AppHelper { return $this->Html->useTag('form', $action, $htmlAttributes) . $append; } +/** + * Return a CSRF input if the _Token is present. + * Used to secure forms in conjunction with SecurityComponent + * + * @return string + */ + protected function _csrfField() { + if (empty($this->request->params['_Token'])) { + return ''; + } + if (!empty($this->request['_Token']['unlockedFields'])) { + foreach ((array)$this->request['_Token']['unlockedFields'] as $unlocked) { + $this->_unlockedFields[] = $unlocked; + } + } + return $this->hidden('_Token.key', array( + 'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(), + 'secure' => self::SECURE_SKIP + )); + } + /** * Closes an HTML form, cleans up values set by FormHelper::create(), and writes hidden * input fields where appropriate. @@ -1511,13 +1521,18 @@ class FormHelper extends AppHelper { $formName = uniqid('post_'); $formUrl = $this->url($url); $out = $this->Html->useTag('form', $formUrl, array('name' => $formName, 'id' => $formName, 'style' => 'display:none;', 'method' => 'post')); - $out .= $this->Html->useTag('block', ' style="display:none;"', $this->Html->useTag('hidden', '_method', ' value="POST"')); + $out .= $this->Html->useTag('hidden', '_method', ' value="POST"'); + $out .= $this->_csrfField(); + + $fields = array(); if (isset($options['data']) && is_array($options['data'])) { foreach ($options['data'] as $key => $value) { + $fields[$key] = $value; $out .= $this->hidden($key, array('value' => $value, 'id' => false)); } unset($options['data']); } + $out .= $this->secure($fields); $out .= $this->Html->useTag('formend'); $url = '#'; From 6026aa4019d152c44f0347146d89173850924191 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 10 Aug 2011 22:00:02 -0400 Subject: [PATCH 33/33] Adding tests for FormHelper::postButton() and SecurityComponent. --- .../Test/Case/View/Helper/FormHelperTest.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index e6a988a0d..9474332e9 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -5701,6 +5701,35 @@ class FormHelperTest extends CakeTestCase { $this->assertTrue(strpos($result, '') !== false); } +/** + * Test that postButton adds _Token fields. + * + * @return void + */ + public function testSecurePostButton() { + $this->Form->request->params['_Token'] = array('key' => 'testkey'); + + $result = $this->Form->postButton('Delete', '/posts/delete/1'); + $expected = array( + 'form' => array( + 'method' => 'post', 'action' => '/posts/delete/1', 'accept-charset' => 'utf-8', + 'style' => 'display:none;' + ), + array('div' => array('style' => 'display:none;')), + array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')), + '/div', + 'button' => array('type' => 'submit'), + 'Delete', + '/button', + array('div' => array('style' => 'display:none;')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')), + array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), + '/div', + '/form', + ); + $this->assertTags($result, $expected); + } /** * testPostLink method *