Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added option['deep'] to saveAll, to save unlimited levels associated …

…data

Squashed commit of the following:

commit 45caa54
Author: Ceeram <c33ram@gmail.com>
Date:   Sun Feb 12 22:29:33 2012 +0100

    update docblocks for deep save

commit 6f3c3b9
Merge: 1d32698 1dd0ff1
Author: Ceeram <c33ram@gmail.com>
Date:   Sun Feb 12 18:17:34 2012 +0100

    Merge branch '2.1' into 2.1-saveAllTheThings

commit 1d32698
Author: Ceeram <c33ram@gmail.com>
Date:   Sun Feb 12 18:16:57 2012 +0100

    Revert "adding info in docblock about associated model fieldList"

    This reverts commit 7cc10a2.

commit 7cc10a2
Author: Ceeram <c33ram@gmail.com>
Date:   Sun Feb 12 18:05:18 2012 +0100

    adding info in docblock about associated model fieldList

commit db2ad27
Author: Ceeram <c33ram@gmail.com>
Date:   Sun Feb 12 17:51:44 2012 +0100

    add tests for deep saveAll respecting fieldList option

commit 14123fc
Merge: cfdf25d 2afb05b
Author: Ceeram <c33ram@gmail.com>
Date:   Sun Feb 12 16:51:26 2012 +0100

    Merge branch '2.1' into 2.1-saveAllTheThings

commit cfdf25d
Author: Ceeram <c33ram@gmail.com>
Date:   Tue Feb 7 13:54:59 2012 +0100

    Make saveAllTheThings fully BC, use $options['deep'] = true, to save infinite recursive data

commit 6e8c438
Merge: 203c7e1 95aa7e3
Author: Ceeram <c33ram@gmail.com>
Date:   Wed Jan 25 14:22:26 2012 +0100

    Merge branch '2.1' into 2.1-saveAllTheThings

commit 203c7e1
Author: Ceeram <c33ram@gmail.com>
Date:   Wed Jan 25 14:19:25 2012 +0100

    validate all the things as well

commit d920d00
Merge: d648f6a 4f1be12
Author: Ceeram <c33ram@gmail.com>
Date:   Mon Jan 23 18:22:12 2012 +0100

    Merge branch '2.1' into 2.1-saveAllTheThings

commit d648f6a
Author: Ceeram <c33ram@gmail.com>
Date:   Fri Dec 9 15:11:52 2011 +0100

    making saveAll, saveMany and saveAssociated not limited to only save directly related models
  • Loading branch information...
commit bc07ba3839db17d6ffd1a6c19c0f53a209af49a1 1 parent 1dd0ff1
@ceeram ceeram authored
View
98 lib/Cake/Model/Model.php
@@ -1974,6 +1974,7 @@ protected function _prepareUpdateFields($data) {
* 'AssociatedModel' => array('field', 'otherfield')
* )
* }}}
+ * - deep: see saveMany/saveAssociated
*
* @param array $data Record data to save. This can be either a numerically-indexed array (for saving multiple
* records of the same type), or an array indexed by association name.
@@ -1993,11 +1994,7 @@ public function saveAll($data = null, $options = array()) {
return $this->saveMany($data, $options);
}
if ($options['validate'] === 'only') {
- $validatesAssoc = $this->validateAssociated($data, $options);
- if (isset($this->validationErrors[$this->alias]) && $this->validationErrors[$this->alias] === false) {
- return false;
- }
- return $validatesAssoc;
+ return $this->validateAssociated($data, $options);
}
return $this->saveAssociated($data, $options);
}
@@ -2012,6 +2009,7 @@ public function saveAll($data = null, $options = array()) {
* - atomic: If true (default), will attempt to save all records in a single transaction.
* Should be set to false if database/table does not support transactions.
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
+ * - deep: If set to true, all associated data will be saved as well.
*
* @param array $data Record data to save. This should be a numerically-indexed array
* @param array $options Options to use when saving record data, See $options above.
@@ -2025,7 +2023,7 @@ public function saveMany($data = null, $options = array()) {
$data = $this->data;
}
- $options = array_merge(array('validate' => 'first', 'atomic' => true), $options);
+ $options = array_merge(array('validate' => 'first', 'atomic' => true, 'deep' => false), $options);
$this->validationErrors = $validationErrors = array();
if (empty($data) && $options['validate'] !== false) {
@@ -2046,12 +2044,21 @@ public function saveMany($data = null, $options = array()) {
}
$return = array();
foreach ($data as $key => $record) {
- $validates = ($this->create(null) !== null && $this->save($record, $options));
+ $validates = $this->create(null) !== null;
+ $saved = false;
+ if ($validates) {
+ if ($options['deep']) {
+ $saved = $this->saveAssociated($record, array_merge($options, array('atomic' => false)));
+ } else {
+ $saved = $this->save($record, $options);
+ }
+ }
+ $validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
if (!$validates) {
$validationErrors[$key] = $this->validationErrors;
}
if (!$options['atomic']) {
- $return[] = $validates;
+ $return[$key] = $validates;
} elseif (!$validates) {
break;
}
@@ -2079,6 +2086,7 @@ public function saveMany($data = null, $options = array()) {
*
* - atomic: If true (default), returns boolean. If false returns array.
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
+ * - deep: If set to true, all associated data will be validated as well.
*
* @param array $data Record data to validate. This should be a numerically-indexed array
* @param array $options Options to use when validating record data (see above), See also $options of validates().
@@ -2088,14 +2096,21 @@ public function saveMany($data = null, $options = array()) {
* depending on whether each record validated successfully.
*/
public function validateMany($data, $options = array()) {
- $options = array_merge(array('atomic' => true), $options);
+ $options = array_merge(array('atomic' => true, 'deep' => false), $options);
$this->validationErrors = $validationErrors = $return = array();
foreach ($data as $key => $record) {
- $validates = $this->create($record) && $this->validates($options);
- if (!$validates) {
+ if ($options['deep']) {
+ $validates = $this->validateAssociated($record, $options);
+ } else {
+ $validates = $this->create($record) && $this->validates($options);
+ }
+ if ($validates === false || (is_array($validates) && in_array(false, $validates, true))) {
$validationErrors[$key] = $this->validationErrors;
+ $validates = false;
+ } else {
+ $validates = true;
}
- $return[] = $validates;
+ $return[$key] = $validates;
}
$this->validationErrors = $validationErrors;
if (!$options['atomic']) {
@@ -2124,6 +2139,7 @@ public function validateMany($data, $options = array()) {
* 'AssociatedModel' => array('field', 'otherfield')
* )
* }}}
+ * - deep: If set to true, not only directly associated data is saved, but deeper nested associated data as well.
*
* @param array $data Record data to save. This should be an array indexed by association name.
* @param array $options Options to use when saving record data, See $options above.
@@ -2137,7 +2153,7 @@ public function saveAssociated($data = null, $options = array()) {
$data = $this->data;
}
- $options = array_merge(array('validate' => 'first', 'atomic' => true), $options);
+ $options = array_merge(array('validate' => 'first', 'atomic' => true, 'deep' => false), $options);
$this->validationErrors = $validationErrors = array();
if (empty($data) && $options['validate'] !== false) {
@@ -2160,13 +2176,26 @@ public function saveAssociated($data = null, $options = array()) {
$validates = true;
foreach ($data as $association => $values) {
if (isset($associations[$association]) && $associations[$association] === 'belongsTo') {
- if ($this->{$association}->create(null) !== null && $this->{$association}->save($values, $options)) {
- $data[$this->alias][$this->belongsTo[$association]['foreignKey']] = $this->{$association}->id;
+ $validates = $this->{$association}->create(null) !== null;
+ $saved = false;
+ if ($validates) {
+ if ($options['deep']) {
+ $saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
+ } else {
+ $saved = $this->{$association}->save($values, array_merge($options, array('atomic' => false)));
+ }
+ $validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
+ }
+ if ($validates) {
+ if (!empty($data[$this->alias])) {
+ $data[$this->alias][$this->belongsTo[$association]['foreignKey']] = $this->{$association}->id;
+ } else {
+ $data[$this->belongsTo[$association]['foreignKey']] = $this->{$association}->id;
+ }
} else {
$validationErrors[$association] = $this->{$association}->validationErrors;
- $validates = false;
}
- $return[$association][] = $validates;
+ $return[$association] = $validates;
}
}
if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
@@ -2184,11 +2213,20 @@ public function saveAssociated($data = null, $options = array()) {
switch ($type) {
case 'hasOne':
$values[$this->{$type}[$association]['foreignKey']] = $this->id;
- if (!($this->{$association}->create(null) !== null && $this->{$association}->save($values, $options))) {
+ $validates = $this->{$association}->create(null) !== null;
+ $saved = false;
+ if ($validates) {
+ if ($options['deep']) {
+ $saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
+ } else {
+ $saved = $this->{$association}->save($values, $options);
+ }
+ }
+ $validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
+ if (!$validates) {
$validationErrors[$association] = $this->{$association}->validationErrors;
- $validates = false;
}
- $return[$association][] = $validates;
+ $return[$association] = $validates;
break;
case 'hasMany':
foreach ($values as $i => $value) {
@@ -2231,6 +2269,7 @@ public function saveAssociated($data = null, $options = array()) {
*
* - atomic: If true (default), returns boolean. If false returns array.
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
+ * - deep: If set to true, not only directly associated data , but deeper nested associated data is validated as well.
*
* @param array $data Record data to validate. This should be an array indexed by association name.
* @param array $options Options to use when validating record data (see above), See also $options of validates().
@@ -2239,7 +2278,7 @@ public function saveAssociated($data = null, $options = array()) {
* depending on whether each record validated successfully.
*/
public function validateAssociated($data, $options = array()) {
- $options = array_merge(array('atomic' => true), $options);
+ $options = array_merge(array('atomic' => true, 'deep' => false), $options);
$this->validationErrors = $validationErrors = $return = array();
if (!($this->create($data) && $this->validates($options))) {
$validationErrors[$this->alias] = $this->validationErrors;
@@ -2248,12 +2287,23 @@ public function validateAssociated($data, $options = array()) {
$return[$this->alias] = true;
}
$associations = $this->getAssociated();
- $validates = true;
foreach ($data as $association => $values) {
+ $validates = true;
if (isset($associations[$association])) {
if (in_array($associations[$association], array('belongsTo', 'hasOne'))) {
- $validates = $this->{$association}->create($values) && $this->{$association}->validates($options);
- $return[$association][] = $validates;
+ if ($options['deep']) {
+ $validates = $this->{$association}->validateAssociated($values, $options);
+ } else {
+ $validates = $this->{$association}->create($values) !== null && $this->{$association}->validates($options);
+ }
+ if (is_array($validates)) {
+ if (in_array(false, $validates, true)) {
+ $validates = false;
+ } else {
+ $validates = true;
+ }
+ }
+ $return[$association] = $validates;
} elseif ($associations[$association] === 'hasMany') {
$validates = $this->{$association}->validateMany($values, $options);
$return[$association] = $validates;
View
957 lib/Cake/Test/Case/Model/ModelWriteTest.php
@@ -2973,72 +2973,841 @@ public function testSaveAllHasOneValidation() {
* @return void
*/
public function testSaveAllAtomic() {
- $this->loadFixtures('Article', 'User');
+ $this->loadFixtures('Article', 'User', 'Comment');
+ $TestModel = new Article();
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array(
+ 'title' => 'Post with Author',
+ 'body' => 'This post will be saved with an author',
+ 'user_id' => 2
+ ),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'user_id' => 2))
+ ), array('atomic' => false));
+
+ $this->assertSame($result, array('Article' => true, 'Comment' => array(true)));
+
+ $result = $TestModel->saveAll(array(
+ array(
+ 'id' => '1',
+ 'title' => 'Baleeted First Post',
+ 'body' => 'Baleeted!',
+ 'published' => 'N'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => 'Just update the title'
+ ),
+ array(
+ 'title' => 'Creating a fourth post',
+ 'body' => 'Fourth post body',
+ 'user_id' => 2
+ )
+ ), array('atomic' => false));
+ $this->assertSame($result, array(true, true, true));
+
+ $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric');
+ $result = $TestModel->saveAll(array(
+ array(
+ 'id' => '1',
+ 'title' => 'Un-Baleeted First Post',
+ 'body' => 'Not Baleeted!',
+ 'published' => 'Y'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => '',
+ 'body' => 'Trying to get away with an empty title'
+ )
+ ), array('validate' => true, 'atomic' => false));
+
+ $this->assertSame($result, array(true, false));
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'comment' => 'First new comment',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ),
+ array(
+ 'comment' => 'Second new comment',
+ 'published' => 'Y',
+ 'user_id' => 2
+ ))
+ ), array('validate' => true, 'atomic' => false));
+ $this->assertSame($result, array('Article' => true, 'Comment' => array(true, true)));
+ }
+
+/**
+ * testSaveAllDeepAssociated method
+ *
+ * @return void
+ */
+ public function testSaveAllDeepAssociated() {
+ $this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
+ $TestModel = new Article();
+ $TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
+ $TestModel->hasAndBelongsToMany = array();
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => 'newuser', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ), array('deep' => true));
+ $this->assertTrue($result);
+
+ $result = $TestModel->findById(2);
+ $expected = array(
+ 'First Comment for Second Article',
+ 'Second Comment for Second Article',
+ 'First new comment',
+ 'Second new comment'
+ );
+ $this->assertEquals($expected, Set::extract($result['Comment'], '{n}.comment'));
+
+ $result = $TestModel->Comment->User->field('id', array('user' => 'newuser', 'password' => 'newuserpass'));
+ $this->assertEquals(5, $result);
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => 'deepsaved'))
+ )
+ ), array('deep' => true));
+ $this->assertTrue($result);
+
+ $result = $TestModel->findById(2);
+ $expected = array(
+ 'First Comment for Second Article',
+ 'Second Comment for Second Article',
+ 'First new comment',
+ 'Second new comment',
+ 'Third new comment',
+ 'Fourth new comment'
+ );
+ $this->assertEquals($expected, Set::extract($result['Comment'], '{n}.comment'));
+
+ $result = $TestModel->Comment->Attachment->field('id', array('attachment' => 'deepsaved'));
+ $this->assertEquals(2, $result);
+ $data = array(
+ 'Attachment' => array(
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ 'user_id' => 5,
+ 'Article' => array(
+ 'title' => 'First Article deepsave insert',
+ 'body' => 'First Article Body deepsave insert',
+ 'User' => array(
+ 'user' => '',
+ 'password' => 'magic'
+ ),
+ ),
+ )
+ );
+
+ $TestModel->Comment->Attachment->create();
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('deep' => true));
+ $this->assertFalse($result);
+
+ $expected = array('User' => array('user' => array('This field cannot be left blank')));
+ $this->assertEquals($expected, $TestModel->validationErrors);
+
+ $data['Comment']['Article']['User']['user'] = 'deepsave';
+ $TestModel->Comment->Attachment->create();
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('deep' => true));
+ $this->assertTrue($result);
+
+ $result = $TestModel->Comment->Attachment->findById($TestModel->Comment->Attachment->id);
+ $expected = array(
+ 'Attachment' => array(
+ 'id' => '3',
+ 'comment_id' => '11',
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'id' => '11',
+ 'article_id' => '4',
+ 'user_id' => '5',
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ )
+ );
+ unset($result['Attachment']['created'], $result['Attachment']['updated']);
+ $this->assertEquals($expected['Attachment'], $result['Attachment']);
+
+ unset($result['Comment']['created'], $result['Comment']['updated']);
+ $this->assertEquals($result['Comment'], $expected['Comment']);
+
+ $result = $TestModel->findById($result['Comment']['article_id']);
+ $expected = array(
+ 'Article' => array(
+ 'id' => '4',
+ 'user_id' => '6',
+ 'title' => 'First Article deepsave insert',
+ 'body' => 'First Article Body deepsave insert',
+ 'published' => 'N',
+ ),
+ 'User' => array(
+ 'id' => '6',
+ 'user' => 'deepsave',
+ 'password' => 'magic',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '11',
+ 'article_id' => '4',
+ 'user_id' => '5',
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ )
+ )
+ );
+ unset(
+ $result['Article']['created'], $result['Article']['updated'],
+ $result['User']['created'], $result['User']['updated'],
+ $result['Comment'][0]['created'], $result['Comment'][0]['updated']
+ );
+ $this->assertEquals($result, $expected);
+ }
+
+/**
+ * testSaveAllDeepMany
+ * tests the validate methods with deeper recursive data
+ *
+ * @return void
+ */
+ public function testSaveAllDeepMany() {
+ $this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
+ $TestModel = new Article();
+ $TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
+ $TestModel->hasAndBelongsToMany = array();
+
+ $data = array(
+ array(
+ 'id' => 1, 'body' => '',
+ 'Comment' => array(
+ array('comment' => '', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'manysaved')),
+ array('comment' => 'Second comment deepsaved article 1', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First comment deepsaved article 2', 'published' => 'Y', 'User' => array('user' => 'savemore', 'password' => '')),
+ array('comment' => '', 'published' => 'Y', 'user_id' => 2)
+ )
+ )
+ );
+ $TestModel->Comment->validate['comment'] = 'notEmpty';
+ $result = $TestModel->saveAll($data, array('deep' => true));
+ $this->assertFalse($result);
+
+ $expected = array(
+ 0 => array(
+ 'body' => array('This field cannot be left blank')
+ ),
+ 1 => array(
+ 'Comment' => array(
+ 0 => array(
+ 'User' => array(
+ 'password' => array('This field cannot be left blank')
+ )
+ ),
+ 1 => array(
+ 'comment' => array('This field cannot be left blank')
+ )
+ )
+ )
+ );
+ $result = $TestModel->validationErrors;
+ $this->assertSame($expected, $result);
+
+ $data = array(
+ array(
+ 'Article' => array('id' => 1),
+ 'Comment' => array(
+ array('comment' => 'First comment deepsaved article 1', 'published' => 'Y', 'User' => array('user' => 'savemany', 'password' => 'manysaved')),
+ array('comment' => 'Second comment deepsaved article 1', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First comment deepsaved article 2', 'published' => 'Y', 'User' => array('user' => 'savemore', 'password' => 'moresaved')),
+ array('comment' => 'Second comment deepsaved article 2', 'published' => 'Y', 'user_id' => 2)
+ )
+ )
+ );
+ $result = $TestModel->saveAll($data, array('deep' => true));
+ $this->assertTrue($result);
+ }
+/**
+ * testSaveAllDeepValidateOnly
+ * tests the validate methods with deeper recursive data
+ *
+ * @return void
+ */
+ public function testSaveAllDeepValidateOnly() {
+ $this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
+ $TestModel = new Article();
+ $TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
+ $TestModel->hasAndBelongsToMany = array();
+ $TestModel->Comment->Attachment->validate['attachment'] = 'notEmpty';
+ $TestModel->Comment->validate['comment'] = 'notEmpty';
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => 'newuser', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array('validate' => 'only', 'deep' => true)
+ );
+ $this->assertTrue($result);
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array('validate' => 'only', 'deep' => true)
+ );
+ $this->assertFalse($result);
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => 'newuser', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array('validate' => 'only', 'atomic' => false, 'deep' => true)
+ );
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(
+ true,
+ true
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array('validate' => 'only', 'atomic' => false, 'deep' => true)
+ );
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(
+ false,
+ true
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => 'deepsaved'))
+ )
+ ),
+ array('validate' => 'only', 'deep' => true)
+ );
+ $this->assertTrue($result);
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
+ )
+ ),
+ array('validate' => 'only', 'deep' => true)
+ );
+ $this->assertFalse($result);
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => 'deepsave'))
+ )
+ ),
+ array('validate' => 'only', 'atomic' => false, 'deep' => true)
+ );
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(
+ true,
+ true
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
+ )
+ ),
+ array('validate' => 'only', 'atomic' => false, 'deep' => true)
+ );
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(
+ true,
+ false
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $expected = array(
+ 'Comment' => array(
+ 1 => array(
+ 'Attachment' => array(
+ 'attachment' => array('This field cannot be left blank')
+ )
+ )
+ )
+ );
+ $result = $TestModel->validationErrors;
+ $this->assertSame($expected, $result);
+
+ $data = array(
+ 'Attachment' => array(
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ 'user_id' => 5,
+ 'Article' => array(
+ 'title' => 'First Article deepsave insert',
+ 'body' => 'First Article Body deepsave insert',
+ 'User' => array(
+ 'user' => 'deepsave',
+ 'password' => 'magic'
+ ),
+ ),
+ )
+ );
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
+ $this->assertTrue($result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
+ $expected = array(
+ 'Attachment' => true,
+ 'Comment' => true
+ );
+ $this->assertSame($expected, $result);
+
+ $data = array(
+ 'Attachment' => array(
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ 'user_id' => 5,
+ 'Article' => array(
+ 'title' => 'First Article deepsave insert',
+ 'body' => 'First Article Body deepsave insert',
+ 'User' => array(
+ 'user' => '',
+ 'password' => 'magic'
+ ),
+ ),
+ )
+ );
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->Attachment->validationErrors;
+ $expected = array(
+ 'Comment' => array(
+ 'Article' => array(
+ 'User' => array(
+ 'user' => array('This field cannot be left blank')
+ )
+ )
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
+ $expected = array(
+ 'Attachment' => true,
+ 'Comment' => false
+ );
+ $this->assertEquals($expected, $result);
+
+ $data['Comment']['Article']['body'] = '';
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->Attachment->validationErrors;
+ $expected = array(
+ 'Comment' => array(
+ 'Article' => array(
+ 'body' => array('This field cannot be left blank')
+ )
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
+ $expected = array(
+ 'Attachment' => true,
+ 'Comment' => false
+ );
+ $this->assertEquals($expected, $result);
+
+ $data['Comment']['comment'] = '';
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->Attachment->validationErrors;
+ $expected = array(
+ 'Comment' => array(
+ 'comment' => array('This field cannot be left blank')
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
+ $expected = array(
+ 'Attachment' => true,
+ 'Comment' => false
+ );
+ $this->assertEquals($expected, $result);
+
+ $data['Attachment']['attachment'] = '';
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->Attachment->validationErrors;
+ $expected = array('attachment' => array('This field cannot be left blank'));
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->validationErrors;
+ $expected = array('comment' => array('This field cannot be left blank'));
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
+ $expected = array(
+ 'Attachment' => false,
+ 'Comment' => false
+ );
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testSaveAllNotDeepAssociated method
+ * test that only directly associated data gets saved
+ *
+ * @return void
+ */
+ public function testSaveAllNotDeepAssociated() {
+ $this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
$TestModel = new Article();
+ $TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
+ $TestModel->hasAndBelongsToMany = array();
$result = $TestModel->saveAll(array(
- 'Article' => array(
- 'title' => 'Post with Author',
- 'body' => 'This post will be saved with an author',
- 'user_id' => 2
- ),
+ 'Article' => array('id' => 2),
'Comment' => array(
- array('comment' => 'First new comment', 'user_id' => 2))
- ), array('atomic' => false));
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => 'newuser', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ), array('deep' => false));
+ $this->assertTrue($result);
- $this->assertSame($result, array('Article' => true, 'Comment' => array(true)));
+ $result = $TestModel->Comment->User->field('id', array('user' => 'newuser', 'password' => 'newuserpass'));
+ $this->assertFalse($result);
$result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 4),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => 'deepsaved'))
+ )
+ ), array('deep' => false));
+ $this->assertTrue($result);
+
+ $result = $TestModel->Comment->Attachment->field('id', array('attachment' => 'deepsaved'));
+ $this->assertFalse($result);
+
+ $data = array(
+ 'Attachment' => array(
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ 'user_id' => 4,
+ 'Article' => array(
+ 'title' => 'First Article deepsave insert',
+ 'body' => 'First Article Body deepsave insert',
+ 'User' => array(
+ 'user' => 'deepsave',
+ 'password' => 'magic'
+ ),
+ ),
+ )
+ );
+ $expected = $TestModel->User->find('count');
+
+ $TestModel->Comment->Attachment->create();
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('deep' => false));
+ $this->assertTrue($result);
+
+ $result = $TestModel->User->find('count');
+ $this->assertEquals($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->findById($TestModel->Comment->Attachment->id);
+ $expected = array(
+ 'Attachment' => array(
+ 'id' => '2',
+ 'comment_id' => '11',
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'id' => '11',
+ 'article_id' => '0',
+ 'user_id' => '4',
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ )
+ );
+ unset($result['Attachment']['created'], $result['Attachment']['updated']);
+ $this->assertEquals($expected['Attachment'], $result['Attachment']);
+
+ unset($result['Comment']['created'], $result['Comment']['updated']);
+ $this->assertEquals($expected['Comment'], $result['Comment']);
+ }
+
+/**
+ * testSaveAllNotDeepMany
+ * tests the save methods to not save deeper recursive data
+ *
+ * @return void
+ */
+ public function testSaveAllNotDeepMany() {
+ $this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
+ $TestModel = new Article();
+ $TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
+ $TestModel->hasAndBelongsToMany = array();
+
+ $data = array(
array(
- 'id' => '1',
- 'title' => 'Baleeted First Post',
- 'body' => 'Baleeted!',
- 'published' => 'N'
+ 'id' => 1, 'body' => '',
+ 'Comment' => array(
+ array('comment' => '', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'manysaved')),
+ array('comment' => 'Second comment deepsaved article 1', 'published' => 'Y', 'user_id' => 2)
+ )
),
array(
- 'id' => '2',
- 'title' => 'Just update the title'
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First comment deepsaved article 2', 'published' => 'Y', 'User' => array('user' => 'savemore', 'password' => '')),
+ array('comment' => '', 'published' => 'Y', 'user_id' => 2)
+ )
+ )
+ );
+ $TestModel->Comment->validate['comment'] = 'notEmpty';
+ $result = $TestModel->saveAll($data, array('deep' => false));
+ $this->assertFalse($result);
+
+ $expected = array(
+ 0 => array(
+ 'body' => array('This field cannot be left blank')
+ )
+ );
+ $result = $TestModel->validationErrors;
+ $this->assertSame($expected, $result);
+
+ $data = array(
+ array(
+ 'Article' => array('id' => 1, 'body' => 'Ignore invalid comment'),
+ 'Comment' => array(
+ array('comment' => '', 'published' => 'Y', 'user_id' => 2)
+ )
),
array(
- 'title' => 'Creating a fourth post',
- 'body' => 'Fourth post body',
- 'user_id' => 2
+ 'Article' => array('id' => 2, 'body' => 'Same here'),
+ 'Comment' => array(
+ array('comment' => '', 'published' => 'Y', 'user_id' => 2)
+ )
)
- ), array('atomic' => false));
- $this->assertSame($result, array(true, true, true));
+ );
+ $result = $TestModel->saveAll($data, array('deep' => false));
+ $this->assertTrue($result);
+ }
+/**
+ * testSaveAllNotDeepValidateOnly
+ * tests the validate methods to not validate deeper recursive data
+ *
+ * @return void
+ */
+ public function testSaveAllNotDeepValidateOnly() {
+ $this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
+ $TestModel = new Article();
+ $TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
+ $TestModel->hasAndBelongsToMany = array();
+ $TestModel->Comment->Attachment->validate['attachment'] = 'notEmpty';
+ $TestModel->Comment->validate['comment'] = 'notEmpty';
- $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric');
- $result = $TestModel->saveAll(array(
+ $result = $TestModel->saveAll(
array(
- 'id' => '1',
- 'title' => 'Un-Baleeted First Post',
- 'body' => 'Not Baleeted!',
- 'published' => 'Y'
+ 'Article' => array('id' => 2, 'body' => ''),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array('validate' => 'only', 'deep' => false)
+ );
+ $this->assertFalse($result);
+
+ $expected = array('body' => array('This field cannot be left blank'));
+ $result = $TestModel->validationErrors;
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2, 'body' => 'Ignore invalid user data'),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
),
+ array('validate' => 'only', 'deep' => false)
+ );
+ $this->assertTrue($result);
+
+ $result = $TestModel->saveAll(
array(
- 'id' => '2',
- 'title' => '',
- 'body' => 'Trying to get away with an empty title'
+ 'Article' => array('id' => 2, 'body' => 'Ignore invalid user data'),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ),
+ array('validate' => 'only', 'atomic' => false, 'deep' => false)
+ );
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(
+ true,
+ true
)
- ), array('validate' => true, 'atomic' => false));
+ );
+ $this->assertSame($expected, $result);
- $this->assertSame($result, array(true, false));
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2, 'body' => 'Ignore invalid attachment data'),
+ 'Comment' => array(
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
+ )
+ ),
+ array('validate' => 'only', 'deep' => false)
+ );
+ $this->assertTrue($result);
$result = $TestModel->saveAll(array(
- 'Article' => array('id' => 2),
+ 'Article' => array('id' => 2, 'body' => 'Ignore invalid attachment data'),
'Comment' => array(
- array(
- 'comment' => 'First new comment',
- 'published' => 'Y',
- 'user_id' => 1
+ array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
+ array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
+ )
+ ),
+ array('validate' => 'only', 'atomic' => false, 'deep' => false)
+ );
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(
+ true,
+ true
+ )
+ );
+ $this->assertSame($expected, $result);
+
+ $expected = array();
+ $result = $TestModel->validationErrors;
+ $this->assertSame($expected, $result);
+
+ $data = array(
+ 'Attachment' => array(
+ 'attachment' => 'deepsave insert',
+ ),
+ 'Comment' => array(
+ 'comment' => 'First comment deepsave insert',
+ 'published' => 'Y',
+ 'user_id' => 5,
+ 'Article' => array(
+ 'title' => 'First Article deepsave insert ignored',
+ 'body' => 'First Article Body deepsave insert',
+ 'User' => array(
+ 'user' => '',
+ 'password' => 'magic'
+ ),
),
- array(
- 'comment' => 'Second new comment',
- 'published' => 'Y',
- 'user_id' => 2
- ))
- ), array('validate' => true, 'atomic' => false));
- $this->assertSame($result, array('Article' => true, 'Comment' => array(true, true)));
+ )
+ );
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => false));
+ $this->assertTrue($result);
+
+ $result = $TestModel->Comment->Attachment->validationErrors;
+ $expected = array();
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => false));
+ $expected = array(
+ 'Attachment' => true,
+ 'Comment' => true
+ );
+ $this->assertEquals($expected, $result);
+
+ $data['Comment']['Article']['body'] = '';
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => false));
+ $this->assertTrue($result);
+
+ $result = $TestModel->Comment->Attachment->validationErrors;
+ $expected = array();
+ $this->assertSame($expected, $result);
+
+ $result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => false));
+ $expected = array(
+ 'Attachment' => true,
+ 'Comment' => true
+ );
+ $this->assertEquals($expected, $result);
}
/**
@@ -3212,7 +3981,7 @@ public function testSaveAllAssociatedTransactionNoRollback() {
$db->expects($this->once())->method('rollback');
$db->expects($this->any())->method('describe')
->will($this->returnValue(array(
- 'id' => array('type' => 'integer'),
+ 'id' => array('type' => 'integer', 'length' => 11),
'title' => array('type' => 'string'),
'body' => array('type' => 'text'),
'published' => array('type' => 'string')
@@ -4541,7 +5310,7 @@ public function testSaveAssociatedTransactionNoRollback() {
$db->expects($this->once())->method('rollback');
$db->expects($this->any())->method('describe')
->will($this->returnValue(array(
- 'id' => array('type' => 'integer'),
+ 'id' => array('type' => 'integer', 'length' => 11),
'title' => array('type' => 'string'),
'body' => array('type' => 'text'),
'published' => array('type' => 'string')
@@ -5512,11 +6281,11 @@ public function testPkInReturnArrayForCreate() {
}
/**
- * validateSaveAllFieldListBelongsTo
+ * testSaveAllFieldListValidateBelongsTo
*
* @return void
*/
- public function validateSaveAllFieldListBelongsTo() {
+ public function testSaveAllFieldListValidateBelongsTo() {
$this->loadFixtures('Post', 'Author', 'Comment', 'Attachment');
$TestModel = new Post();
@@ -5543,8 +6312,7 @@ public function validateSaveAllFieldListBelongsTo() {
$result = $TestModel->find('all');
$expected = array(
- 'Post' =>
- array (
+ 'Post' => array (
'id' => '4',
'author_id' => '5',
'title' => 'Post without body',
@@ -5553,8 +6321,7 @@ public function validateSaveAllFieldListBelongsTo() {
'created' => $ts,
'updated' => $ts,
),
- 'Author' =>
- array (
+ 'Author' => array (
'id' => '5',
'user' => 'bob',
'password' => NULL,
@@ -5683,4 +6450,92 @@ public function testSaveAllFieldListHasOne() {
$this->assertEmpty($TestModel->validationErrors);
}
+/**
+ * testSaveAllDeepFieldListValidateBelongsTo
+ *
+ * @return void
+ */
+ public function testSaveAllDeepFieldListValidateBelongsTo() {
+ $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment', 'Article', 'User');
+ $TestModel = new Post();
+ $TestModel->Author->bindModel(array('hasMany' => array('Comment' => array('foreignKey' => 'user_id'))), false);
+ $TestModel->recursive = 2;
+
+ $result = $TestModel->find('all');
+ $this->assertCount(3, $result);
+ $this->assertFalse(isset($result[3]));
+ $ts = date('Y-m-d H:i:s');
+
+ // test belongsTo
+ $fieldList = array(
+ 'Post' => array('title', 'author_id'),
+ 'Author' => array('user'),
+ 'Comment' => array('comment')
+ );
+ $TestModel->saveAll(array(
+ 'Post' => array(
+ 'title' => 'Post without body',
+ 'body' => 'This will not be saved',
+ ),
+ 'Author' => array(
+ 'user' => 'bob',
+ 'test' => 'This will not be saved',
+ 'Comment' => array(
+ array('id' => 5, 'comment' => 'I am still published', 'published' => 'N'))
+
+ )), array('fieldList' => $fieldList, 'deep' => true));
+
+ $result = $TestModel->Author->Comment->find('first', array(
+ 'conditions' => array('Comment.id' => 5),
+ 'fields' => array('comment', 'published')
+ ));
+ $expected = array(
+ 'Comment' => array(
+ 'comment' => 'I am still published',
+ 'published' => 'Y'
+ )
+ );
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testSaveAllDeepFieldListHasMany method
+ *
+ * return @void
+ */
+ public function testSaveAllDeepFieldListHasMany() {
+ $this->loadFixtures('Article', 'Comment', 'User');
+ $TestModel = new Article();
+ $TestModel->belongsTo = $TestModel->hasAndBelongsToMany = array();
+
+ $this->db->truncate($TestModel);
+ $this->db->truncate(new Comment());
+
+ $fieldList = array(
+ 'Article' => array('id'),
+ 'Comment' => array('article_id', 'user_id'),
+ 'User' => array('user')
+ );
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2, 'title' => 'I will not save'),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'user_id' => 1),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2, 'User' => array('user' => 'nopassword', 'password' => 'not saved'))
+ )
+ ), array('fieldList' => $fieldList, 'deep' => true));
+
+ $result = $TestModel->Comment->User->find('first', array(
+ 'conditions' => array('User.user' => 'nopassword'),
+ 'fields' => array('user', 'password')
+ ));
+ $expected = array(
+ 'User' => array(
+ 'user' => 'nopassword',
+ 'password' => ''
+ )
+ );
+ $this->assertEquals($expected, $result);
+ }
+
}
View
7 lib/Cake/Test/Case/Model/models.php
@@ -641,6 +641,13 @@ class Attachment extends CakeTestModel {
* @var string 'Attachment'
*/
public $name = 'Attachment';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ */
+ public $belongsTo = array('Comment');
}
/**

1 comment on commit bc07ba3

@jippi
Collaborator

Finally! Really been looking forward to this enhancement ! :D

Please sign in to comment.
Something went wrong with that request. Please try again.