浏览代码

Add counter cache compatibility
Resolves #55

ndm2 11 年之前
父节点
当前提交
858437e3ee

+ 75 - 2
Model/Behavior/SoftDeleteBehavior.php

@@ -153,13 +153,22 @@ class SoftDeleteBehavior extends ModelBehavior {
 			}
 		}
 
+		$keys = $this->_getCounterCacheKeys($model, $id);
+
 		$model->create();
 		$model->set($model->primaryKey, $id);
 		$options = array(
 			'validate' => false,
-			'fieldList' => array_keys($data)
+			'fieldList' => array_keys($data),
+			'counterCache' => false
 		);
-		return (bool)$model->save(array($model->alias => $data), $options);
+		$result = (bool)$model->save(array($model->alias => $data), $options);
+
+		if ($result && !empty($keys[$model->alias])) {
+			$model->updateCounterCache($keys[$model->alias]);
+		}
+
+		return $result;
 	}
 
 	/**
@@ -195,6 +204,14 @@ class SoftDeleteBehavior extends ModelBehavior {
 		);
 		$result = $model->save(array($model->alias => $data), $options);
 		$this->softDelete($model, $runtime);
+
+		if ($result) {
+			$keys = $this->_getCounterCacheKeys($model, $id);
+			if (!empty($keys[$model->alias])) {
+				$model->updateCounterCache($keys[$model->alias]);
+			}
+		}
+
 		return $result;
 	}
 
@@ -354,4 +371,60 @@ class SoftDeleteBehavior extends ModelBehavior {
 		}
 	}
 
+	/**
+	 * Retrieves the foreign key values for the `belongsTo` associations
+	 * with enabled counter caching.
+	 *
+	 * The returned array has the following format:
+	 *
+	 * {{{
+	 * array(
+	 *     'ModelAlias' => array(
+	 *         'foreign_key_name' => foreign key value
+	 *     )
+	 * )
+	 * }}}
+	 *
+	 * @param Model $model
+	 * @param integer $id The ID of the current record
+	 * @return array|null
+	 */
+	protected function _getCounterCacheKeys(Model $model, $id) {
+		$keys = null;
+		if (!empty($model->belongsTo)) {
+			foreach ($model->belongsTo as $assoc) {
+				if (empty($assoc['counterCache'])) {
+					continue;
+				}
+
+				$keys = $model->find('first', array(
+					'fields' => $this->_collectForeignKeys($model),
+					'conditions' => array($model->alias . '.' . $model->primaryKey => $id),
+					'recursive' => -1,
+					'callbacks' => false
+				));
+				break;
+			}
+		}
+		return $keys;
+	}
+
+	/**
+	 * Collects foreign keys from `belongsTo` associations.
+	 *
+	 * @param Model $model
+	 * @return array
+	 */
+	protected function _collectForeignKeys(Model $model) {
+		$result = array();
+
+		foreach ($model->belongsTo as $assoc => $data) {
+			if (isset($data['foreignKey']) && is_string($data['foreignKey'])) {
+				$result[$assoc] = $data['foreignKey'];
+			}
+		}
+
+		return $result;
+	}
+
 }

+ 100 - 1
Test/Case/Model/Behavior/SoftDeleteBehaviorTest.php

@@ -23,7 +23,10 @@ class SoftDeleteBehaviorTest extends CakeTestCase {
 	 *
 	 * @var array
 	 */
-	public $fixtures = array('plugin.tools.soft_delete_post');
+	public $fixtures = array(
+		'plugin.tools.soft_delete_category',
+		'plugin.tools.soft_delete_post'
+	);
 
 	/**
 	 * Creates the model instance
@@ -126,6 +129,68 @@ class SoftDeleteBehaviorTest extends CakeTestCase {
 		$this->assertEmpty($data);
 	}
 
+	/**
+	 * testSoftDeleteWithCounterCache
+	 *
+	 * @return void
+	 */
+	public function testSoftDeleteWithCounterCache() {
+		$this->Post->Category->id = 1;
+		$count = $this->Post->Category->field('post_count');
+		$this->assertEquals(2, $count);
+
+		$this->assertFalse($this->Post->softDeleted);
+		$this->Post->delete(1);
+		$this->assertTrue($this->Post->softDeleted);
+
+		$count = $this->Post->Category->field('post_count');
+		$this->assertEquals(1, $count);
+	}
+
+	/**
+	 * testSoftDeleteWithoutCounterCache
+	 *
+	 * @return void
+	 */
+	public function testSoftDeleteWithoutCounterCache() {
+		$Post = $this->getMock('SoftDeletedPost', array('updateCounterCache'));
+		$Post->expects($this->never())->method('updateCounterCache');
+
+		$Post->belongsTo = array();
+		$Post->delete(1);
+	}
+
+	/**
+	 * testUnDeleteWithCounterCache
+	 *
+	 * @return void
+	 */
+	public function testUnDeleteWithCounterCache() {
+		$this->Post->Category->id = 2;
+		$count = $this->Post->Category->field('post_count');
+		$this->assertEquals($count, 0);
+
+		$this->assertEmpty($this->Post->read(null, 3));
+
+		$this->Post->undelete(3);
+
+		$count = $this->Post->Category->field('post_count');
+		$this->assertEquals(1, $count);
+	}
+
+	/**
+	 * testUnDeleteWithoutCounterCache
+	 *
+	 * @return void
+	 */
+	public function testUnDeleteWithoutCounterCache() {
+		$Post = $this->getMock('SoftDeletedPost', array('updateCounterCache'));
+		$Post->expects($this->never())->method('updateCounterCache');
+
+		$Post->belongsTo = array();
+		$Post->undelete(3);
+	}
+
 		// $result = $this->Model->read();
 		// $this->assertEquals($result['SoftDeletedPost']['slug'], 'fourth_Post');
 
@@ -155,6 +220,28 @@ class SoftDeleteTestBehavior extends SoftDeleteBehavior {
 }
 
 /**
+ * SoftDeleteCategory
+ *
+ */
+class SoftDeleteCategory extends CakeTestModel {
+
+	/**
+	 * Use Table
+	 *
+	 * @var string
+	 */
+	public $useTable = 'soft_delete_categories';
+
+	/**
+	 * Alias
+	 *
+	 * @var string
+	 */
+	public $alias = 'Category';
+
+}
+
+/**
  * SoftDeletedPost
  *
  */
@@ -181,6 +268,18 @@ class SoftDeletedPost extends CakeTestModel {
 	 */
 	public $alias = 'Post';
 
+	/**
+	 * belongsTo associations
+	 *
+	 * @var array
+	 */
+	public $belongsTo = array(
+		'Category' => array(
+			'className' => 'SoftDeleteCategory',
+			'counterCache' => true
+		)
+	);
+
 }
 
 /**

+ 33 - 0
Test/Fixture/SoftDeleteCategoryFixture.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * SoftDeleteCategoryFixture
+ *
+ */
+class SoftDeleteCategoryFixture extends CakeTestFixture {
+
+	/**
+	 * Fields property
+	 *
+	 * @var array
+	 */
+	public $fields = array(
+		'id' => array('type' => 'integer', 'key' => 'primary'),
+		'post_count' => array('type' => 'integer'),
+		'title' => array('type' => 'string', 'null' => false));
+
+	/**
+	 * Records property
+	 *
+	 * @var array
+	 */
+	public $records = array(
+		array(
+			'id' => 1,
+			'post_count' => 2,
+			'title' => 'Category A'),
+		array(
+			'id' => 2,
+			'post_count' => 0,
+			'title' => 'Category B'));
+
+}

+ 4 - 4
Test/Fixture/SoftDeletePostFixture.php

@@ -12,7 +12,7 @@ class SoftDeletePostFixture extends CakeTestFixture {
 	 */
 	public $fields = array(
 		'id' => array('type' => 'integer', 'key' => 'primary'),
-		'article_id' => array('type' => 'integer'),
+		'category_id' => array('type' => 'integer'),
 		'title' => array('type' => 'string', 'null' => false),
 		'deleted' => array('type' => 'boolean', 'null' => false, 'default' => '0'),
 		'deleted_date' => 'datetime',
@@ -27,7 +27,7 @@ class SoftDeletePostFixture extends CakeTestFixture {
 	public $records = array(
 		array(
 			'id' => 1,
-			'article_id' => 1,
+			'category_id' => 1,
 			'title' => 'First Post',
 			'deleted' => 0,
 			'deleted_date' => null,
@@ -35,7 +35,7 @@ class SoftDeletePostFixture extends CakeTestFixture {
 			'updated' => '2007-03-18 10:41:31'),
 		array(
 			'id' => 2,
-			'article_id' => 1,
+			'category_id' => 1,
 			'title' => 'Second Post',
 			'deleted' => 0,
 			'deleted_date' => null,
@@ -43,7 +43,7 @@ class SoftDeletePostFixture extends CakeTestFixture {
 			'updated' => '2007-03-18 10:43:31'),
 		array(
 			'id' => 3,
-			'article_id' => 2,
+			'category_id' => 2,
 			'title' => 'Third Post',
 			'deleted' => 1,
 			'deleted_date' => '2008-01-01 00:00:00',