Skip to content
Browse files

Adding test for validation of with models canceling a save.

Adding initial implementation of Model::__validateWithModel().

Correcting error in previous commit.  Adding tests for saveAll and validating habtm with models.
  • Loading branch information...
1 parent 33038c7 commit a490e249fa76b1076ab5ee255636f1f533560842 @markstory markstory committed Dec 14, 2009
Showing with 134 additions and 2 deletions.
  1. +40 −2 cake/libs/model/model.php
  2. +94 −0 cake/tests/cases/libs/model/model_validation.test.php
View
42 cake/libs/model/model.php
@@ -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.
*
@@ -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
@@ -2499,6 +2503,40 @@ function invalidFields($options = array()) {
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.
*
View
94 cake/tests/cases/libs/model/model_validation.test.php
@@ -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.
Something went wrong with that request. Please try again.