Merge branch 'master' into 2.3

Conflicts:
	lib/Cake/Console/Command/Task/ModelTask.php
	lib/Cake/Model/Model.php
This commit is contained in:
mark_story 2013-01-26 21:16:26 -05:00
commit 4af6039107
23 changed files with 202 additions and 54 deletions

View file

@ -105,12 +105,22 @@ class ControllerTask extends BakeTask {
$this->listAll($this->connection, false);
ClassRegistry::config('Model', array('ds' => $this->connection));
$unitTestExists = $this->_checkUnitTest();
$admin = false;
if (!empty($this->params['admin'])) {
$admin = $this->Project->getPrefix();
}
foreach ($this->__tables as $table) {
$model = $this->_modelName($table);
$controller = $this->_controllerName($model);
App::uses($model, 'Model');
if (class_exists($model)) {
$actions = $this->bakeActions($controller);
if ($admin) {
$this->out(__d('cake_console', 'Adding %s methods', $admin));
$actions .= "\n" . $this->bakeActions($controller, $admin);
}
if ($this->bake($controller, $actions) && $unitTestExists) {
$this->bakeTest($controller);
}

View file

@ -619,21 +619,17 @@ class ModelTask extends BakeTask {
public function findHasAndBelongsToMany(Model $model, $associations) {
$foreignKey = $this->_modelKey($model->name);
foreach ($this->_tables as $otherTable) {
$tableName = null;
$offset = strpos($otherTable, $model->table . '_');
$otherOffset = strpos($otherTable, '_' . $model->table);
if ($offset !== false) {
$offset = strlen($model->table . '_');
$habtmName = $this->_modelName(substr($otherTable, $offset));
$associations['hasAndBelongsToMany'][] = array(
'alias' => $habtmName,
'className' => $habtmName,
'foreignKey' => $foreignKey,
'associationForeignKey' => $this->_modelKey($habtmName),
'joinTable' => $otherTable
);
} elseif ($otherOffset !== false) {
$habtmName = $this->_modelName(substr($otherTable, 0, $otherOffset));
if ($offset === 0) {
$tableName = substr($otherTable, strlen($model->table . '_'));
} elseif ($otherOffset === 0) {
$tableName = substr($otherTable, 0, $otherOffset);
}
if ($tableName && in_array($tableName, $this->_tables)) {
$habtmName = $this->_modelName($tableName);
$associations['hasAndBelongsToMany'][] = array(
'alias' => $habtmName,
'className' => $habtmName,

View file

@ -145,15 +145,17 @@ class PluginTask extends AppShell {
$controllerFileName = $plugin . 'AppController.php';
$out = "<?php\n\n";
$out .= "App::uses('AppController', 'Controller');\n\n";
$out .= "class {$plugin}AppController extends AppController {\n\n";
$out .= "}\n\n";
$out .= "}\n";
$this->createFile($this->path . $plugin . DS . 'Controller' . DS . $controllerFileName, $out);
$modelFileName = $plugin . 'AppModel.php';
$out = "<?php\n\n";
$out .= "App::uses('AppModel', 'Model');\n\n";
$out .= "class {$plugin}AppModel extends AppModel {\n\n";
$out .= "}\n\n";
$out .= "}\n";
$this->createFile($this->path . $plugin . DS . 'Model' . DS . $modelFileName, $out);
$this->_modifyBootstrap($plugin);

View file

@ -208,7 +208,8 @@ class CookieComponent extends Component {
* @param string|array $key Key for the value
* @param mixed $value Value
* @param boolean $encrypt Set to true to encrypt value, false otherwise
* @param integer|string $expires Can be either Unix timestamp, or date string
* @param integer|string $expires Can be either the number of seconds until a cookie
* expires, or a strtotime compatible time offset.
* @return void
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::write
*/

View file

@ -419,9 +419,10 @@ class CakeSession {
* @return void
*/
public static function destroy() {
if (self::started()) {
session_destroy();
if (!self::started()) {
self::start();
}
session_destroy();
self::clear();
}

View file

@ -1153,10 +1153,12 @@ class DboSource extends DataSource {
}
$linkedModel = $model->{$className};
$filtering[] = $className;
foreach ($results as &$result) {
foreach ($results as $key => &$result) {
$data = $linkedModel->afterFind(array(array($className => $result[$className])), false);
if (isset($data[0][$className])) {
$result[$className] = $data[0][$className];
} else {
unset($results[$key]);
}
}
}

View file

@ -988,7 +988,7 @@ class Model extends Object implements CakeEventListener {
$plugin = null;
if (is_numeric($assoc)) {
unset ($this->{$type}[$assoc]);
unset($this->{$type}[$assoc]);
$assoc = $value;
$value = array();
@ -1164,7 +1164,7 @@ class Model extends Object implements CakeEventListener {
foreach ($fieldSet as $fieldName => $fieldValue) {
if (isset($this->validationErrors[$fieldName])) {
unset ($this->validationErrors[$fieldName]);
unset($this->validationErrors[$fieldName]);
}
if ($modelName === $this->alias) {
@ -2525,7 +2525,7 @@ class Model extends Object implements CakeEventListener {
'fields' => "{$this->alias}.{$this->primaryKey}",
'recursive' => 0), compact('conditions'))
);
if ($ids === false) {
if ($ids === false || $ids === null) {
return false;
}

View file

@ -232,7 +232,12 @@ class CakeRequest implements ArrayAccess {
} elseif (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], '://') === false) {
$uri = $_SERVER['REQUEST_URI'];
} elseif (isset($_SERVER['REQUEST_URI'])) {
$qPosition = strpos($_SERVER['REQUEST_URI'], '?');
if ($qPosition !== false && strpos($_SERVER['REQUEST_URI'], '://') > $qPosition) {
$uri = $_SERVER['REQUEST_URI'];
} else {
$uri = substr($_SERVER['REQUEST_URI'], strlen(FULL_BASE_URL));
}
} elseif (isset($_SERVER['PHP_SELF']) && isset($_SERVER['SCRIPT_NAME'])) {
$uri = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['PHP_SELF']);
} elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {

View file

@ -90,6 +90,10 @@ class ControllerTaskTest extends CakeTestCase {
array($out, $out, $in)
);
$this->Task->Test = $this->getMock('TestTask', array(), array($out, $out, $in));
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Could not run as an Article, Tag or Comment model was already loaded.');
}
}
/**
@ -340,7 +344,6 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testBakeActionsUsingSessions() {
$this->skipIf(!defined('ARTICLE_MODEL_CREATED'), 'Testing bakeActions requires Article, Comment & Tag Model to be undefined.');
$result = $this->Task->bakeActions('BakeArticles', null, true);
@ -380,7 +383,6 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testBakeActionsWithNoSessions() {
$this->skipIf(!defined('ARTICLE_MODEL_CREATED'), 'Testing bakeActions requires Article, Tag, Comment Models to be undefined.');
$result = $this->Task->bakeActions('BakeArticles', null, false);
@ -513,9 +515,7 @@ class ControllerTaskTest extends CakeTestCase {
if ($count != count($this->fixtures)) {
$this->markTestSkipped('Additional tables detected.');
}
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Execute into all could not be run as an Article, Tag or Comment model was already loaded.');
}
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('all');
@ -532,15 +532,45 @@ class ControllerTaskTest extends CakeTestCase {
$this->Task->execute();
}
/**
* Test execute() with all and --admin
*
* @return void
*/
public function testExecuteIntoAllAdmin() {
$count = count($this->Task->listAll('test'));
if ($count != count($this->fixtures)) {
$this->markTestSkipped('Additional tables detected.');
}
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('all');
$this->Task->params['admin'] = true;
$this->Task->Project->expects($this->any())
->method('getPrefix')
->will($this->returnValue('admin_'));
$this->Task->expects($this->any())
->method('_checkUnitTest')
->will($this->returnValue(true));
$this->Task->Test->expects($this->once())->method('bake');
$filename = '/my/path/BakeArticlesController.php';
$this->Task->expects($this->once())->method('createFile')->with(
$filename,
$this->stringContains('function admin_index')
)->will($this->returnValue(true));
$this->Task->execute();
}
/**
* test that `cake bake controller foos` works.
*
* @return void
*/
public function testExecuteWithController() {
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Execute with scaffold param requires no Article, Tag or Comment model to be defined');
}
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('BakeArticles');
@ -572,9 +602,6 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testExecuteWithControllerNameVariations($name) {
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Execute with scaffold param requires no Article, Tag or Comment model to be defined.');
}
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array($name);
@ -592,9 +619,6 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testExecuteWithPublicParam() {
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Execute with public param requires no Article, Tag or Comment model to be defined.');
}
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('BakeArticles');
@ -614,9 +638,6 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testExecuteWithControllerAndBoth() {
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Execute with controller and both requires no Article, Tag or Comment model to be defined.');
}
$this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
@ -636,9 +657,6 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function testExecuteWithControllerAndAdmin() {
if (!defined('ARTICLE_MODEL_CREATED')) {
$this->markTestSkipped('Execute with controller and admin requires no Article, Tag or Comment model to be defined.');
}
$this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';

View file

@ -205,7 +205,7 @@ class SessionComponentTest extends CakeTestCase {
$this->assertEquals($Session->read('Test'), $array);
$Session->delete('Test');
$this->assertFalse($Session->write(array('Test'), 'some value'));
$this->assertTrue($Session->write(array('Test'), 'some value'));
$this->assertTrue($Session->write(array('Test' => 'some value')));
$this->assertEquals('some value', $Session->read('Test'));
$Session->delete('Test');

View file

@ -434,6 +434,26 @@ class ModelDeleteTest extends BaseModelTest {
$this->assertFalse($result, 'deleteAll returned true when find query generated sql error. %s');
}
/**
* testDeleteAllFailedFind method
*
* Eg: Behavior callback stops the event, find returns null
*
* @return void
*/
public function testDeleteAllFailedFind() {
$this->loadFixtures('Article');
$this->getMock('Article', array('find'), array(), 'ArticleDeleteAll');
$TestModel = new ArticleDeleteAll();
$TestModel->expects($this->once())
->method('find')
->will($this->returnValue(null));
$result = $TestModel->deleteAll(array('Article.user_id' => 999));
$this->assertFalse($result);
}
/**
* testRecursiveDel method
*

View file

@ -3005,6 +3005,30 @@ class ModelReadTest extends BaseModelTest {
$this->assertEquals($afterFindData, $noAfterFindData);
}
/**
* Test that afterFind can completely unset data.
*
* @return void
*/
public function testAfterFindUnset() {
$this->loadFixtures('Article', 'Comment', 'User');
$model = new CustomArticle();
$model->bindModel(array(
'hasMany' => array(
'ModifiedComment' => array(
'className' => 'ModifiedComment',
'foreignKey' => 'article_id',
)
)
));
$model->ModifiedComment->remove = true;
$result = $model->find('all');
$this->assertTrue(
empty($result[0]['ModifiedComment']),
'Zeroith row should be removed by afterFind'
);
}
/**
* testFindThreadedNoParent method
*

View file

@ -551,6 +551,13 @@ class ModifiedComment extends CakeTestModel {
*/
public $useTable = 'comments';
/**
* Property used to toggle filtering of results
*
* @var boolean
*/
public $remove = false;
/**
* belongsTo property
*
@ -567,6 +574,9 @@ class ModifiedComment extends CakeTestModel {
if (isset($results[0])) {
$results[0]['Comment']['callback'] = 'Fire';
}
if ($this->remove) {
return array();
}
return $results;
}

View file

@ -136,6 +136,14 @@ class CakeRequestTest extends CakeTestCase {
$_SERVER['REQUEST_URI'] = '/tasks/index/page:1/?ts=123456';
$request = new CakeRequest();
$this->assertEquals('tasks/index/page:1/', $request->url);
$_SERVER['REQUEST_URI'] = '/some/path?url=http://cakephp.org';
$request = new CakeRequest();
$this->assertEquals('some/path', $request->url);
$_SERVER['REQUEST_URI'] = FULL_BASE_URL . '/other/path?url=http://cakephp.org';
$request = new CakeRequest();
$this->assertEquals('other/path', $request->url);
}
/**

View file

@ -367,6 +367,12 @@ class CakeTimeTest extends CakeTestCase {
$time = time() + DAY;
$this->assertEquals('Tomorrow, ' . date('H:i', $time), $this->Time->niceShort($time));
$time = strtotime('+6 days');
$this->assertEquals('On ' . date('l F d, H:i', $time), $this->Time->niceShort($time));
$time = strtotime('-6 days');
$this->assertEquals(date('l F d, H:i', $time), $this->Time->niceShort($time));
date_default_timezone_set('Europe/London');
$result = $this->Time->niceShort('2005-01-15 10:00:00', new DateTimeZone('Europe/Brussels'));
$this->assertEquals('Jan 15th 2005, 11:00', $result);

View file

@ -170,6 +170,17 @@ class HashTest extends CakeTestCase {
* return void
*/
public function testGet() {
$data = array('abc', 'def');
$result = Hash::get($data, '0');
$this->assertEquals('abc', $result);
$result = Hash::get($data, 0);
$this->assertEquals('abc', $result);
$result = Hash::get($data, '1');
$this->assertEquals('def', $result);
$data = self::articleData();
$result = Hash::get(array(), '1.Article.title');

View file

@ -606,6 +606,23 @@ class FormHelperTest extends CakeTestCase {
$this->assertTags($result, $expected);
}
/**
* testFormCreateGetNoSecurity method
*
* Test form->create() with no security key as its a get form
*
* @return void
*/
public function testCreateEndGetNoSecurity() {
$this->Form->request['_Token'] = array('key' => 'testKey');
$encoding = strtolower(Configure::read('App.encoding'));
$result = $this->Form->create('Contact', array('type' => 'get', 'url' => '/contacts/add'));
$this->assertNotContains('Token', $result);
$result = $this->Form->end('Save');
$this->assertNotContains('Token', $result);
}
/**
* test that create() clears the fields property so it starts fresh
*
@ -3951,6 +3968,17 @@ class FormHelperTest extends CakeTestCase {
'/select'
);
$this->assertTags($result, $expected);
$this->Form->request->data['Model']['field'] = 50;
$result = $this->Form->select('Model.field', array('50f5c0cf' => 'Stringy', '50' => 'fifty'));
$expected = array(
'select' => array('name' => 'data[Model][field]', 'id' => 'ModelField'),
array('option' => array('value' => '')), '/option',
array('option' => array('value' => '50f5c0cf')), 'Stringy', '/option',
array('option' => array('value' => '50', 'selected' => 'selected')), 'fifty', '/option',
'/select'
);
$this->assertTags($result, $expected);
}
/**

View file

@ -56,7 +56,7 @@ class CakeTime {
* @var string
* @see CakeTime::niceShort()
*/
public static $niceShortFormat = '%d/%m, %H:%M';
public static $niceShortFormat = '%B %d, %H:%M';
/**
* The format to use when formatting a time using `CakeTime::timeAgoInWords()`

View file

@ -39,10 +39,10 @@ class Hash {
* @return mixed The value fetched from the array, or null.
*/
public static function get(array $data, $path) {
if (empty($data) || empty($path)) {
if (empty($data)) {
return null;
}
if (is_string($path)) {
if (is_string($path) || is_numeric($path)) {
$parts = explode('.', $path);
} else {
$parts = $path;

View file

@ -101,7 +101,7 @@ class Xml {
} elseif (file_exists($input)) {
return self::_loadXml(file_get_contents($input), $options);
} elseif (strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) {
$socket = new HttpSocket();
$socket = new HttpSocket(array('request' => array('redirect' => 10)));
$response = $socket->get($input);
if (!$response->isOk()) {
throw new XmlException(__d('cake_dev', 'XML cannot be read.'));

View file

@ -433,7 +433,9 @@ class FormHelper extends AppHelper {
$htmlAttributes = array_merge($options, $htmlAttributes);
$this->fields = array();
if ($this->requestType !== 'get') {
$append .= $this->_csrfField();
}
if (!empty($append)) {
$append = $this->Html->useTag('hiddenblock', $append);
@ -504,7 +506,11 @@ class FormHelper extends AppHelper {
}
$out .= $this->submit($submit, $submitOptions);
}
if (isset($this->request['_Token']) && !empty($this->request['_Token'])) {
if (
$this->requestType !== 'get' &&
isset($this->request['_Token']) &&
!empty($this->request['_Token'])
) {
$out .= $this->secure($this->fields);
$this->fields = array();
}
@ -2602,7 +2608,7 @@ class FormHelper extends AppHelper {
if ($name !== null) {
if (
(!$selectedIsArray && !$selectedIsEmpty && (string)$attributes['value'] == (string)$name) ||
($selectedIsArray && in_array($name, $attributes['value']))
($selectedIsArray && in_array($name, $attributes['value'], true))
) {
if ($attributes['style'] === 'checkbox') {
$htmlOptions['checked'] = true;

View file

@ -616,7 +616,7 @@ class HtmlHelper extends AppHelper {
* ### Usage:
*
* {{{
* echo $html->style(array('margin' => '10px', 'padding' => '10px'), true);
* echo $this->Html->style(array('margin' => '10px', 'padding' => '10px'), true);
*
* // creates
* 'margin:10px;padding:10px;'
@ -760,11 +760,11 @@ class HtmlHelper extends AppHelper {
*
* Create a regular image:
*
* `echo $html->image('cake_icon.png', array('alt' => 'CakePHP'));`
* `echo $this->Html->image('cake_icon.png', array('alt' => 'CakePHP'));`
*
* Create an image link:
*
* `echo $html->image('cake_icon.png', array('alt' => 'CakePHP', 'url' => 'http://cakephp.org'));`
* `echo $this->Html->image('cake_icon.png', array('alt' => 'CakePHP', 'url' => 'http://cakephp.org'));`
*
* ### Options:
*