Skip to content

Commit

Permalink
Adding test for validation of with models canceling a save.
Browse files Browse the repository at this point in the history
Adding initial implementation of Model::__validateWithModel().

Correcting error in previous commit.  Adding tests for saveAll and validating habtm with models.
  • Loading branch information
markstory committed Dec 16, 2009
1 parent 33038c7 commit a490e24
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 2 deletions.
42 changes: 40 additions & 2 deletions cake/libs/model/model.php
Expand Up @@ -2331,7 +2331,8 @@ function query() {
return call_user_func_array(array(&$db, 'query'), $params);
}
/**
* 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.
*
Expand All @@ -2342,13 +2343,16 @@ function query() {
*/
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;
}
return $errors;
}
/**
* 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
Expand Down Expand Up @@ -2498,6 +2502,40 @@ function invalidFields($options = array()) {
$this->validate = $_validate;
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->data as $assoc => $data) {
if (isset($this->hasAndBelongsToMany[$assoc]) && !empty($this->hasAndBelongsToMany[$assoc]['with'])) {
list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
$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.
Expand Down
94 changes: 94 additions & 0 deletions cake/tests/cases/libs/model/model_validation.test.php
Expand Up @@ -121,6 +121,100 @@ function testInvalidFieldsWithFieldListParams() {

$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');
}
}
?>

0 comments on commit a490e24

Please sign in to comment.