Merge branch '1.2' into mergers

Conflicts:
	cake/libs/inflector.php
	cake/tests/cases/libs/model/model_validation.test.php
This commit is contained in:
Mark Story 2009-12-27 12:34:27 -05:00
commit 6b2154d961
14 changed files with 287 additions and 11 deletions

View file

@ -582,8 +582,12 @@ class Dispatcher extends Object {
App::import('View', 'View', false);
}
$controller = null;
$view =& new View($controller, false);
return $view->renderCache($filename, getMicrotime());
$view =& new View($controller);
$return = $view->renderCache($filename, getMicrotime());
if (!$return) {
ClassRegistry::removeObject('view');
}
return $return;
}
}

View file

@ -652,6 +652,10 @@ class SecurityComponent extends Object {
*/
function _generateToken(&$controller) {
if (isset($controller->params['requested']) && $controller->params['requested'] === 1) {
if ($this->Session->check('_Token')) {
$tokenData = unserialize($this->Session->read('_Token'));
$controller->params['_Token'] = $tokenData;
}
return false;
}
$authKey = Security::generateAuthKey();
@ -682,7 +686,6 @@ class SecurityComponent extends Object {
}
$controller->params['_Token'] = $token;
$this->Session->write('_Token', serialize($token));
return true;
}

View file

@ -398,7 +398,7 @@ class L10n extends Object {
* @access private
*/
function __autoLanguage() {
$_detectableLanguages = split('[,;]', env('HTTP_ACCEPT_LANGUAGE'));
$_detectableLanguages = preg_split('/[,;]/', env('HTTP_ACCEPT_LANGUAGE'));
foreach ($_detectableLanguages as $key => $langKey) {
$langKey = strtolower($langKey);
if (strpos($langKey, '_') !== false) {

View file

@ -535,20 +535,20 @@ class DboMysql extends DboMysqlBase {
*/
function connect() {
$config = $this->config;
$connect = $config['connect'];
$this->connected = false;
if (!$config['persistent']) {
$this->connection = mysql_connect($config['host'] . ':' . $config['port'], $config['login'], $config['password'], true);
$config['connect'] = 'mysql_connect';
} else {
$this->connection = $connect($config['host'] . ':' . $config['port'], $config['login'], $config['password']);
$this->connection = mysql_pconnect($config['host'] . ':' . $config['port'], $config['login'], $config['password']);
}
if (mysql_select_db($config['database'], $this->connection)) {
$this->connected = true;
}
if (isset($config['encoding']) && !empty($config['encoding'])) {
if (!empty($config['encoding'])) {
$this->setEncoding($config['encoding']);
}

View file

@ -1760,7 +1760,9 @@ class DboSource extends DataSource {
if ($count >= 1 && !in_array($fields[0], array('*', 'COUNT(*)'))) {
for ($i = 0; $i < $count; $i++) {
if (preg_match('/^\(.*\)\s' . $this->alias . '.*/i', $fields[$i])){
if (is_object($fields[$i]) && isset($fields[$i]->type) && $fields[$i]->type === 'expression') {
$fields[$i] = $fields[$i]->value;
} elseif (preg_match('/^\(.*\)\s' . $this->alias . '.*/i', $fields[$i])){
continue;
} elseif (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
$prepend = '';

View file

@ -2417,7 +2417,8 @@ class Model extends Overloadable {
}
/**
* Returns true if all fields pass validation.
* Returns true if all fields pass validation. Will validate hasAndBelongsToMany associations
* that use the 'with' key as well. Since __saveMulti is incapable of exiting a save operation.
*
* Will validate the currently set data. Use Model::set() or Model::create() to set the active data.
*
@ -2428,6 +2429,9 @@ class Model extends Overloadable {
*/
function validates($options = array()) {
$errors = $this->invalidFields($options);
if (empty($errors) && $errors !== false) {
$errors = $this->__validateWithModels($options);
}
if (is_array($errors)) {
return count($errors) === 0;
}
@ -2435,7 +2439,7 @@ class Model extends Overloadable {
}
/**
* Returns an array of fields that have failed validation.
* Returns an array of fields that have failed validation. On the current model.
*
* @param string $options An optional array of custom options to be made available in the beforeValidate callback
* @return array Array of invalid fields
@ -2593,6 +2597,43 @@ class Model extends Overloadable {
return $this->validationErrors;
}
/**
* Runs validation for hasAndBelongsToMany associations that have 'with' keys
* set. And data in the set() data set.
*
* @param array $options Array of options to use on Valdation of with models
* @return boolean Failure of validation on with models.
* @access private
* @see Model::validates()
*/
function __validateWithModels($options) {
$valid = true;
foreach ($this->hasAndBelongsToMany as $assoc => $association) {
if (empty($association['with']) || !isset($this->data[$assoc])) {
continue;
}
list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
$data = $this->data[$assoc];
$newData = array();
foreach ((array)$data as $row) {
if (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
$newData[] = $row;
} elseif (isset($row[$join]) && isset($row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
$newData[] = $row[$join];
}
}
if (empty($newData)) {
continue;
}
foreach ($newData as $data) {
$data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $this->id;
$this->{$join}->create($data);
$valid = ($valid && $this->{$join}->validates($options));
}
}
return $valid;
}
/**
* Marks a field as invalid, optionally setting the name of validation
* rule (in case of multiple validation for field) that was broken.

View file

@ -459,7 +459,7 @@ class Set {
$item = $items[$token];
$matches[] = array(
'trace' => array_merge($context['trace'], $ctext),
'key' => $key,
'key' => $token,
'item' => $item,
);
break;

View file

@ -490,6 +490,15 @@ class TestCachedPagesController extends AppController {
function view($id = null) {
$this->render('index');
}
/**
* test cached forms / tests view object being registered
*
* @return void
*/
function cache_form() {
$this->cacheAction = 10;
$this->helpers[] = 'Form';
}
}
/**
@ -2088,6 +2097,48 @@ class DispatcherTest extends CakeTestCase {
$filename = $this->__cachePath($dispatcher->here);
$this->assertTrue(file_exists($filename));
unlink($filename);
$url = 'TestCachedPages/test_nocache_tags';
}
/**
* test that cached() registers a view and un-registers it. Tests
* that helpers using ClassRegistry::getObject('view'); don't fail
*
* @return void
*/
function testCachedRegisteringViewObject() {
Configure::write('Cache.disable', false);
Configure::write('Cache.check', true);
Configure::write('debug', 2);
$_POST = array();
$_SERVER['PHP_SELF'] = '/';
Router::reload();
Configure::write('viewPaths', array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS));
$dispatcher =& new Dispatcher();
$dispatcher->base = false;
$url = 'test_cached_pages/cache_form';
ob_start();
$dispatcher->dispatch($url);
$out = ob_get_clean();
ClassRegistry::flush();
ob_start();
$dispatcher->cached($url);
$cached = ob_get_clean();
$result = str_replace(array("\t", "\r\n", "\n"), "", $out);
$cached = preg_replace('/<!--+[^<>]+-->/', '', $cached);
$expected = str_replace(array("\t", "\r\n", "\n"), "", $cached);
$this->assertEqual($result, $expected);
$filename = $this->__cachePath($dispatcher->here);
unlink($filename);
ClassRegistry::flush();
}
/**

View file

@ -1177,5 +1177,23 @@ DIGEST;
$this->assertEqual(count($this->Controller->testHeaders), 1);
$this->assertEqual(current($this->Controller->testHeaders), $expected);
}
/**
* test that a requestAction's controller will have the _Token appended to
* the params.
*
* @return void
* @see http://cakephp.lighthouseapp.com/projects/42648/tickets/68
*/
function testSettingTokenForRequestAction() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->params['_Token']['key'];
$this->Controller->params['requested'] = 1;
unset($this->Controller->params['_Token']);
$this->Controller->Security->startup($this->Controller);
$this->assertEqual($this->Controller->params['_Token']['key'], $key);
}
}
?>

View file

@ -2928,6 +2928,20 @@ class DboSourceTest extends CakeTestCase {
$this->assertEqual($result, $expected);
}
/**
* test that fields() will accept objects made from DboSource::expression
*
* @return void
*/
function testFieldsWithExpression() {
$expression =& $this->testDb->expression("CASE Sample.id WHEN 1 THEN 'Id One' ELSE 'Other Id' END AS case_col");
$result = $this->testDb->fields($this->Model, null, array("id", $expression));
$expected = array(
'`TestModel`.`id`',
"CASE Sample.id WHEN 1 THEN 'Id One' ELSE 'Other Id' END AS case_col"
);
$this->assertEqual($result, $expected);
}
/**
* testMergeAssociations method
*

View file

@ -119,6 +119,103 @@ class ModelValidationTest extends BaseModelTest {
$this->assertEqual($TestModel->validate, $validate);
}
/**
* test that validates() checks all the 'with' associations as well for validation
* as this can cause partial/wrong data insertion.
*
* @return void
*/
function testValidatesWithAssociations() {
$data = array(
'Something' => array(
'id' => 5,
'title' => 'Extra Fields',
'body' => 'Extra Fields Body',
'published' => '1'
),
'SomethingElse' => array(
array('something_else_id' => 1, 'doomed' => '')
)
);
$Something =& new Something();
$JoinThing =& $Something->JoinThing;
$JoinThing->validate = array('doomed' => array('rule' => 'notEmpty'));
$expectedError = array('doomed' => 'This field cannot be left blank');
$Something->create();
$result = $Something->save($data);
$this->assertFalse($result, 'Save occured even when with models failed. %s');
$this->assertEqual($JoinThing->validationErrors, $expectedError);
$count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
$this->assertIdentical($count, 0);
$data = array(
'Something' => array(
'id' => 5,
'title' => 'Extra Fields',
'body' => 'Extra Fields Body',
'published' => '1'
),
'SomethingElse' => array(
array('something_else_id' => 1, 'doomed' => 1),
array('something_else_id' => 1, 'doomed' => '')
)
);
$Something->create();
$result = $Something->save($data);
$this->assertFalse($result, 'Save occured even when with models failed. %s');
$joinRecords = $JoinThing->find('count', array(
'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
));
$this->assertEqual($joinRecords, 0, 'Records were saved on the join table. %s');
}
/**
* test that saveAll and with models with validation interact well
*
* @return void
*/
function testValidatesWithModelsAndSaveAll() {
$data = array(
'Something' => array(
'id' => 5,
'title' => 'Extra Fields',
'body' => 'Extra Fields Body',
'published' => '1'
),
'SomethingElse' => array(
array('something_else_id' => 1, 'doomed' => '')
)
);
$Something =& new Something();
$JoinThing =& $Something->JoinThing;
$JoinThing->validate = array('doomed' => array('rule' => 'notEmpty'));
$expectedError = array('doomed' => 'This field cannot be left blank');
$Something->create();
$result = $Something->saveAll($data, array('validate' => 'only'));
$this->assertFalse($result);
$this->assertEqual($JoinThing->validationErrors, $expectedError);
$Something->create();
$result = $Something->saveAll($data, array('validate' => 'first'));
$this->assertFalse($result);
$this->assertEqual($JoinThing->validationErrors, $expectedError);
$count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
$this->assertIdentical($count, 0);
$joinRecords = $JoinThing->find('count', array(
'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
));
$this->assertEqual($joinRecords, 0, 'Records were saved on the join table. %s');
}
/**
* Test that missing validation methods trigger errors in development mode.
* Helps to make developement easier.

View file

@ -1030,6 +1030,22 @@ class SetTest extends CakeTestCase {
$this->assertEqual($result, $expected);
}
/**
* testExtractWithArrays method
*
* @access public
* @return void
*/
function testExtractWithArrays() {
$data = array(
'Level1' => array(
'Level2' => array('test1', 'test2'),
'Level2bis' => array('test3', 'test4')
)
);
$this->assertEqual(Set::extract('/Level1/Level2', $data), array(array('Level2' => array('test1', 'test2'))));
$this->assertEqual(Set::extract('/Level1/Level2bis', $data), array(array('Level2bis' => array('test3', 'test4'))));
}
/**
* testMatches method
*

View file

@ -187,6 +187,22 @@ class XmlTest extends CakeTestCase {
$result = $xml->toString(false);
$expected = '<zero_string>0</zero_string><zero_integer>0</zero_integer>';
$this->assertEqual($expected, $result);
$data = array(
'Client' => array(
'id' => 3,
'object_id' => 9,
'key' => 'alt',
'name' => 'Client Two',
'created_by' => 4,
'status' => '0',
'num_projects' => 0
)
);
$xml = new Xml($data, array('format' => 'tags'));
$result = $xml->toString(array('format' => 'tags', 'header' => false));
$this->assertPattern('/<status>0<\/status>/', $result);
$this->assertPattern('/<num_projects>0<\/num_projects>/', $result);
}
/**
* testHeader method

View file

@ -0,0 +1,14 @@
<div class="users form">
<cake:nocache>
<?php echo $form->create('User');?>
<fieldset>
<legend><?php __('Add User');?></legend>
<?php
echo $form->input('username');
echo $form->input('email');
echo $form->input('password');
?>
</fieldset>
<?php echo $form->end('Submit');?>
</cake:nocache>
</div>