From 2e3b841d8983fb12b56579181ff2155baeee5c74 Mon Sep 17 00:00:00 2001 From: Jose Alejandro Alvarez Mendoza Date: Mon, 15 Jun 2015 17:41:38 -0430 Subject: [PATCH 1/2] Issue #138 Fixing SoftDeleteBehavior belongsTo when import users on fixture --- Model/Behavior/SoftDeleteBehavior.php | 784 ++++++++++---------- Test/Case/Model/Behavior/SoftDeleteTest.php | 429 ++++++----- Test/Fixture/ArticleFixture.php | 60 +- 3 files changed, 670 insertions(+), 603 deletions(-) diff --git a/Model/Behavior/SoftDeleteBehavior.php b/Model/Behavior/SoftDeleteBehavior.php index afb655c..4c30436 100644 --- a/Model/Behavior/SoftDeleteBehavior.php +++ b/Model/Behavior/SoftDeleteBehavior.php @@ -19,392 +19,400 @@ */ class SoftDeleteBehavior extends ModelBehavior { -/** - * Default settings - * - * @var array $default - */ - public $default = array( - 'deleted' => 'deleted_date' - ); - -/** - * Holds activity flags for models - * - * @var array $runtime - */ - public $runtime = array(); - -/** - * Setup callback - * - * @param Model $model - * @param array $settings - */ - public function setup(Model $model, $settings = array()) { - if (empty($settings)) { - $settings = $this->default; - } elseif (!is_array($settings)) { - $settings = array($settings); - } - - $error = __d('utils', 'SoftDeleteBehavior::setup(): model %s has no field!', $model->name); - $fields = $this->_normalizeFields($model, $settings); - foreach ($fields as $flag => $date) { - if ($model->hasField($flag)) { - if ($date && !$model->hasField($date)) { - trigger_error($error . $date, E_USER_NOTICE); - return; - } - continue; - } - trigger_error($error . $flag, E_USER_NOTICE); - return; - } - - $this->settings[$model->alias] = $fields; - $this->softDelete($model, true); - } - -/** - * Before find callback - * - * @param Model $model - * @param array $query - * @return array - */ - public function beforeFind(Model $model, $query) { - $runtime = $this->runtime[$model->alias]; - if ($runtime) { - if (!is_array($query['conditions'])) { - $query['conditions'] = array(); - } - $conditions = array_filter(array_keys($query['conditions'])); - - $fields = $this->_normalizeFields($model); - - foreach ($fields as $flag => $date) { - if (true === $runtime || $flag === $runtime) { - if (!in_array($flag, $conditions) && !in_array($model->name . '.' . $flag, $conditions)) { - $query['conditions'][$model->alias . '.' . $flag] = false; - } - - if ($flag === $runtime) { - break; - } - } - } - return $query; - } - } - -/** - * Check if a record exists for the given id - * - * @param Model $model - * @param id - * @return mixed - */ - public function existsAndNotDeleted(Model $model, $id) { - if ($id === null) { - $id = $model->getID(); - } - if ($id === false) { - return false; - } - $exists = $model->find('count', array( - 'contain' => array(), - 'recursive' => -1, - 'conditions' => array( - $model->alias . '.' . $model->primaryKey => $id - ) - )); - return ($exists ? true : false); - } - -/** - * Before delete callback - * - * @param Model $model - * @param boolean $cascade - * @return boolean - */ - public function beforeDelete(Model $model, $cascade = true) { - $runtime = $this->runtime[$model->alias]; - if ($runtime) { - if ($model->beforeDelete($cascade)) { - $this->delete($model, $model->id); - } - return false; - } - return true; - } - -/** - * Mark record as deleted - * - * @param object $model - * @param integer $id - * @return boolean - */ - public function delete($model, $id) { - $runtime = $this->runtime[$model->alias]; - - $data = array(); - $fields = $this->_normalizeFields($model); - foreach ($fields as $flag => $date) { - if (true === $runtime || $flag === $runtime) { - $data[$flag] = true; - if ($date) { - $data[$date] = date('Y-m-d H:i:s'); - } - if ($flag === $runtime) { - break; - } - } - } - - $record = $model->find('first', array( - 'fields' => $model->primaryKey, - 'conditions' => array($model->primaryKey => $id), - 'contain' => array(), - 'recursive' => -1 - )); - - if (!empty($record)) { - $model->set($model->primaryKey, $id); - unset($model->data[$model->alias]['modified']); - unset($model->data[$model->alias]['updated']); - $result = $model->save(array($model->alias => $data), false, array_keys($data)); - if (!$result) { - return false; - } - } - - return true; - } - -/** - * Mark record as not deleted - * - * @param object $model - * @param integer $id - * @return boolean - */ - public function undelete($model, $id) { - $runtime = $this->runtime[$model->alias]; - $this->softDelete($model, false); - - $data = array(); - $fields = $this->_normalizeFields($model); - foreach ($fields as $flag => $date) { - if (true === $runtime || $flag === $runtime) { - $data[$flag] = false; - if ($date) { - $data[$date] = null; - } - if ($flag === $runtime) { - break; - } - } - } - - $model->create(); - $model->set($model->primaryKey, $id); - $result = $model->save(array($model->alias => $data), false, array_keys($data)); - $this->softDelete($model, $runtime); - if ($result) { - return true; - } - return false; - } - -/** - * Enable/disable SoftDelete functionality - * - * Usage from model: - * $this->softDelete(false); deactivate this behavior for model - * $this->softDelete('field_two'); enabled only for this flag field - * $this->softDelete(true); enable again for all flag fields - * $config = $this->softDelete(null); for obtaining current setting - * - * @param object $model - * @param mixed $active - * @return mixed if $active is null, then current setting/null, or boolean if runtime setting for model was changed - */ - public function softDelete($model, $active) { - if (is_null($active)) { - return isset($this->runtime[$model->alias]) ? $this->runtime[$model->alias] : null; - } - - $result = !isset($this->runtime[$model->alias]) || $this->runtime[$model->alias] !== $active; - $this->runtime[$model->alias] = $active; - $this->_softDeleteAssociations($model, $active); - return $result; - } - -/** - * Returns number of outdated softdeleted records prepared for purge - * - * @param object $model - * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' - * @return integer - */ - public function purgeDeletedCount($model, $expiration = '-90 days') { - $runtime = $this->runtime[$model->alias]; - $this->softDelete($model, false); - $result = $model->find('count', array( - 'conditions' => $this->_purgeDeletedConditions($model, $expiration), - 'recursive' => -1, - 'contain' => array() - ) - ); - $this->runtime[$model->alias] = $runtime; - return $result; - } - -/** - * Purge table - * - * @param object $model - * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' - * @return boolean if there were some outdated records - */ - public function purgeDeleted($model, $expiration = '-90 days') { - $this->softDelete($model, false); - $records = $model->find('all', array( - 'conditions' => $this->_purgeDeletedConditions($model, $expiration), - 'fields' => array($model->primaryKey), - 'recursive' => -1 - )); - if ($records) { - foreach ($records as $record) { - $model->delete($record[$model->alias][$model->primaryKey]); - } - return true; - } - return false; - } - -/** - * Returns conditions for finding outdated records - * - * @param object $model - * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' - * @return array - */ - protected function _purgeDeletedConditions($model, $expiration = '-90 days') { - $purgeDate = date('Y-m-d H:i:s', strtotime($expiration)); - $conditions = array(); - foreach ($this->settings[$model->alias] as $flag => $date) { - $conditions[$model->alias . '.' . $flag] = true; - if ($date) { - $conditions[$model->alias . '.' . $date . ' <'] = $purgeDate; - } - } - return $conditions; - } - -/** - * Return normalized field array - * - * @param object $model - * @param array $settings - * @return array - */ - protected function _normalizeFields($model, $settings = array()) { - if (empty($settings)) { - $settings = $this->settings[$model->alias]; - } - $result = array(); - foreach ($settings as $flag => $date) { - if (is_numeric($flag)) { - $flag = $date; - $date = false; - } - $result[$flag] = $date; - } - return $result; - } - -/** - * Modifies conditions of hasOne and hasMany associations - * - * If multiple delete flags are configured for model, then $active = true doesn't - * do anything - you have to alter conditions in association definition - * - * @param Model $model - * @param mixed $active - */ - protected function _softDeleteAssociations(Model $model, $active) { - if (empty($model->belongsTo)) { - return; - } - - $fields = array_keys($this->_normalizeFields($model)); - $parentModels = array_keys($model->belongsTo); - - foreach ($parentModels as $parentModel) { - foreach (array('hasOne', 'hasMany') as $assocType) { - if (empty($model->{$parentModel}->{$assocType})) { - continue; - } - - foreach ($model->{$parentModel}->{$assocType} as $assoc => $assocConfig) { - $modelName = empty($assocConfig['className']) ? $assoc : @$assocConfig['className']; - if ((!empty($model->plugin) && strstr($model->plugin . '.', $model->alias) === false ? $model->plugin . '.' : '') . $model->alias !== $modelName) { - continue; - } - - $conditions =& $model->{$parentModel}->{$assocType}[$assoc]['conditions']; - if (!is_array($conditions)) { - $model->{$parentModel}->{$assocType}[$assoc]['conditions'] = array(); - } - - $multiFields = 1 < count($fields); - foreach ($fields as $field) { - if ($active) { - if (!isset($conditions[$field]) && !isset($conditions[$assoc . '.' . $field])) { - if (is_string($active)) { - if ($field == $active) { - $conditions[$assoc . '.' . $field] = false; - } elseif (isset($conditions[$assoc . '.' . $field])) { - unset($conditions[$assoc . '.' . $field]); - } - } elseif (!$multiFields) { - $conditions[$assoc . '.' . $field] = false; - } - } - } elseif (isset($conditions[$assoc . '.' . $field])) { - unset($conditions[$assoc . '.' . $field]); - } - } - } - } - } - } - -/** - * Soft delete all - * - * @param Model $model - * @param array $conditions - * @return void - */ - public function softDeleteAll(Model $model, $conditions = array()) { - $results = $model->find('all', array( - 'contain' => array(), - 'recursive' => -1, - 'conditions' => $conditions, - 'fields' => array( - $model->alias . '.' . $model->primaryKey - ) - )); - if (empty($results)) { - return; - } - foreach ($results as $result) { - $this->delete($model, $result[$model->alias][$model->primaryKey]); - } - } + /** + * Default settings + * + * @var array $default + */ + public $default = array( + 'deleted' => 'deleted_date' + ); + + /** + * Holds activity flags for models + * + * @var array $runtime + */ + public $runtime = array(); + + /** + * Setup callback + * + * @param Model $model + * @param array $settings + */ + public function setup(Model $model, $settings = array()) { + if (empty($settings)) { + $settings = $this->default; + } elseif (!is_array($settings)) { + $settings = array($settings); + } + + $error = __d('utils', 'SoftDeleteBehavior::setup(): model %s has no field!', $model->name); + $fields = $this->_normalizeFields($model, $settings); + foreach ($fields as $flag => $date) { + if ($model->hasField($flag)) { + if ($date && !$model->hasField($date)) { + trigger_error($error . $date, E_USER_NOTICE); + return; + } + continue; + } + trigger_error($error . $flag, E_USER_NOTICE); + return; + } + + $this->settings[$model->alias] = $fields; + $this->softDelete($model, true); + } + + /** + * Before find callback + * + * @param Model $model + * @param array $query + * @return array + */ + public function beforeFind(Model $model, $query) { + $runtime = $this->runtime[$model->alias]; + if ($runtime) { + if (!is_array($query['conditions'])) { + $query['conditions'] = array(); + } + $conditions = array_filter(array_keys($query['conditions'])); + + $fields = $this->_normalizeFields($model); + + foreach ($fields as $flag => $date) { + if (true === $runtime || $flag === $runtime) { + if (!in_array($flag, $conditions) && !in_array($model->name . '.' . $flag, $conditions)) { + $query['conditions'][$model->alias . '.' . $flag] = false; + } + + if ($flag === $runtime) { + break; + } + } + } + return $query; + } + } + + /** + * Check if a record exists for the given id + * + * @param Model $model + * @param id + * @return mixed + */ + public function existsAndNotDeleted(Model $model, $id) { + if ($id === null) { + $id = $model->getID(); + } + if ($id === false) { + return false; + } + $exists = $model->find('count', array( + 'contain' => array(), + 'recursive' => -1, + 'conditions' => array( + $model->alias . '.' . $model->primaryKey => $id + ) + )); + return ($exists ? true : false); + } + + /** + * Before delete callback + * + * @param Model $model + * @param boolean $cascade + * @return boolean + */ + public function beforeDelete(Model $model, $cascade = true) { + $runtime = $this->runtime[$model->alias]; + if ($runtime) { + if ($model->beforeDelete($cascade)) { + $this->delete($model, $model->id); + } + return false; + } + return true; + } + + /** + * Mark record as deleted + * + * @param object $model + * @param integer $id + * @return boolean + */ + public function delete($model, $id) { + $runtime = $this->runtime[$model->alias]; + + $data = array(); + $fields = $this->_normalizeFields($model); + foreach ($fields as $flag => $date) { + if (true === $runtime || $flag === $runtime) { + $data[$flag] = true; + if ($date) { + $data[$date] = date('Y-m-d H:i:s'); + } + if ($flag === $runtime) { + break; + } + } + } + + $record = $model->find('first', array( + 'fields' => $model->primaryKey, + 'conditions' => array($model->primaryKey => $id), + 'contain' => array(), + 'recursive' => -1 + )); + + if (!empty($record)) { + $model->set($model->primaryKey, $id); + unset($model->data[$model->alias]['modified']); + unset($model->data[$model->alias]['updated']); + $result = $model->save(array($model->alias => $data), false, array_keys($data)); + if (!$result) { + return false; + } + } + + return true; + } + + /** + * Mark record as not deleted + * + * @param object $model + * @param integer $id + * @return boolean + */ + public function undelete($model, $id) { + $runtime = $this->runtime[$model->alias]; + $this->softDelete($model, false); + + $data = array(); + $fields = $this->_normalizeFields($model); + foreach ($fields as $flag => $date) { + if (true === $runtime || $flag === $runtime) { + $data[$flag] = false; + if ($date) { + $data[$date] = null; + } + if ($flag === $runtime) { + break; + } + } + } + + $model->create(); + $model->set($model->primaryKey, $id); + $result = $model->save(array($model->alias => $data), false, array_keys($data)); + $this->softDelete($model, $runtime); + if ($result) { + return true; + } + return false; + } + + /** + * Enable/disable SoftDelete functionality + * + * Usage from model: + * $this->softDelete(false); deactivate this behavior for model + * $this->softDelete('field_two'); enabled only for this flag field + * $this->softDelete(true); enable again for all flag fields + * $config = $this->softDelete(null); for obtaining current setting + * + * @param object $model + * @param mixed $active + * @return mixed if $active is null, then current setting/null, or boolean if runtime setting for model was changed + */ + public function softDelete($model, $active) { + if (is_null($active)) { + return isset($this->runtime[$model->alias]) ? $this->runtime[$model->alias] : null; + } + + $result = !isset($this->runtime[$model->alias]) || $this->runtime[$model->alias] !== $active; + $this->runtime[$model->alias] = $active; + $this->_softDeleteAssociations($model, $active); + return $result; + } + + /** + * Returns number of outdated softdeleted records prepared for purge + * + * @param object $model + * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' + * @return integer + */ + public function purgeDeletedCount($model, $expiration = '-90 days') { + $runtime = $this->runtime[$model->alias]; + $this->softDelete($model, false); + $result = $model->find('count', array( + 'conditions' => $this->_purgeDeletedConditions($model, $expiration), + 'recursive' => -1, + 'contain' => array() + ) + ); + $this->runtime[$model->alias] = $runtime; + return $result; + } + + /** + * Purge table + * + * @param object $model + * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' + * @return boolean if there were some outdated records + */ + public function purgeDeleted($model, $expiration = '-90 days') { + $this->softDelete($model, false); + $records = $model->find('all', array( + 'conditions' => $this->_purgeDeletedConditions($model, $expiration), + 'fields' => array($model->primaryKey), + 'recursive' => -1 + )); + if ($records) { + foreach ($records as $record) { + $model->delete($record[$model->alias][$model->primaryKey]); + } + return true; + } + return false; + } + + /** + * Returns conditions for finding outdated records + * + * @param object $model + * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' + * @return array + */ + protected function _purgeDeletedConditions($model, $expiration = '-90 days') { + $purgeDate = date('Y-m-d H:i:s', strtotime($expiration)); + $conditions = array(); + foreach ($this->settings[$model->alias] as $flag => $date) { + $conditions[$model->alias . '.' . $flag] = true; + if ($date) { + $conditions[$model->alias . '.' . $date . ' <'] = $purgeDate; + } + } + return $conditions; + } + + /** + * Return normalized field array + * + * @param object $model + * @param array $settings + * @return array + */ + protected function _normalizeFields($model, $settings = array()) { + if (empty($settings)) { + $settings = $this->settings[$model->alias]; + } + $result = array(); + foreach ($settings as $flag => $date) { + if (is_numeric($flag)) { + $flag = $date; + $date = false; + } + $result[$flag] = $date; + } + return $result; + } + + /** + * Modifies conditions of hasOne and hasMany associations + * + * If multiple delete flags are configured for model, then $active = true doesn't + * do anything - you have to alter conditions in association definition + * + * @param Model $model + * @param mixed $active + */ + protected function _softDeleteAssociations(Model $model, $active) { + if (empty($model->belongsTo)) { + return; + } + + $fields = array_keys($this->_normalizeFields($model)); + $parentModels = array_keys($model->belongsTo); + + foreach ($parentModels as $parentModel) { + + list($plugin, $modelClass) = pluginSplit($parentModel, true); + App::uses($modelClass, $plugin . 'Model'); + if (!class_exists($modelClass)) { + throw new MissingModelException(array('class' => $modelClass)); + } + $model->{$parentModel} = new $parentModel(null, null, $model->useDbConfig); + + foreach (array('hasOne', 'hasMany') as $assocType) { + if (empty($model->{$parentModel}->{$assocType})) { + continue; + } + + foreach ($model->{$parentModel}->{$assocType} as $assoc => $assocConfig) { + $modelName = empty($assocConfig['className']) ? $assoc : @$assocConfig['className']; + if ((!empty($model->plugin) && strstr($model->plugin . '.', $model->alias) === false ? $model->plugin . '.' : '') . $model->alias !== $modelName) { + continue; + } + + $conditions =& $model->{$parentModel}->{$assocType}[$assoc]['conditions']; + if (!is_array($conditions)) { + $model->{$parentModel}->{$assocType}[$assoc]['conditions'] = array(); + } + + $multiFields = 1 < count($fields); + foreach ($fields as $field) { + if ($active) { + if (!isset($conditions[$field]) && !isset($conditions[$assoc . '.' . $field])) { + if (is_string($active)) { + if ($field == $active) { + $conditions[$assoc . '.' . $field] = false; + } elseif (isset($conditions[$assoc . '.' . $field])) { + unset($conditions[$assoc . '.' . $field]); + } + } elseif (!$multiFields) { + $conditions[$assoc . '.' . $field] = false; + } + } + } elseif (isset($conditions[$assoc . '.' . $field])) { + unset($conditions[$assoc . '.' . $field]); + } + } + } + } + } + } + + /** + * Soft delete all + * + * @param Model $model + * @param array $conditions + * @return void + */ + public function softDeleteAll(Model $model, $conditions = array()) { + $results = $model->find('all', array( + 'contain' => array(), + 'recursive' => -1, + 'conditions' => $conditions, + 'fields' => array( + $model->alias . '.' . $model->primaryKey + ) + )); + if (empty($results)) { + return; + } + foreach ($results as $result) { + $this->delete($model, $result[$model->alias][$model->primaryKey]); + } + } } diff --git a/Test/Case/Model/Behavior/SoftDeleteTest.php b/Test/Case/Model/Behavior/SoftDeleteTest.php index fc5ed1d..6d5b77c 100644 --- a/Test/Case/Model/Behavior/SoftDeleteTest.php +++ b/Test/Case/Model/Behavior/SoftDeleteTest.php @@ -29,26 +29,56 @@ */ class SoftDeletedPost extends CakeTestModel { -/** - * Use Table - * - * @var string - */ - public $useTable = 'posts'; + /** + * Use Table + * + * @var string + */ + public $useTable = 'posts'; -/** - * Behaviors - * - * @var array - */ - public $actsAs = array('Utils.SoftDelete'); + /** + * Behaviors + * + * @var array + */ + public $actsAs = array('Utils.SoftDelete'); + + /** + * Alias + * + * @var string + */ + public $alias = 'Post'; +} /** - * Alias + * SoftDeletedPost * - * @var string + * @package utils + * @subpackage utils.tests.cases.behaviors */ - public $alias = 'Post'; +class SoftDeletedArticle extends CakeTestModel { + + /** + * Use Table + * + * @var string + */ + public $useTable = 'articles'; + + /** + * Behaviors + * + * @var array + */ + public $actsAs = array('Utils.SoftDelete'); + + /** + * Alias + * + * @var string + */ + public $alias = 'Article'; } /** @@ -56,184 +86,211 @@ class SoftDeletedPost extends CakeTestModel { */ class SoftDeleteTest extends CakeTestCase { -/** - * fixtures property - * - * @var array - */ - public $fixtures = array('plugin.utils.post'); + /** + * fixtures property + * + * @var array + */ + public $fixtures = array( + 'plugin.utils.post', + 'plugin.utils.article' + ); -/** - * Creates the model instance - * - * @return void - */ - public function setUp() { - $this->Post = new SoftDeletedPost(); - } + /** + * Creates the model instance + * + * @return void + */ + public function setUp() { + $this->Post = new SoftDeletedPost(); + $this->Article = new SoftDeletedArticle(); + } -/** - * Destroy the model instance - * - * @return void - */ - public function tearDown() { - unset($this->Post); - ClassRegistry::flush(); - } + /** + * Destroy the model instance + * + * @return void + */ + public function tearDown() { + unset($this->Post); + ClassRegistry::flush(); + } -/** - * Test saving a item - * - * @return void - */ - public function testSoftDelete() { - $data = $this->Post->read(null, 1); - $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); - $result = $this->Post->delete(1); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertTrue(empty($data)); - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], true); - $this->assertTrue(!empty($data['Post']['deleted_date'])); - } + /** + * Test saving a item + * + * @return void + */ + public function testSoftDelete() { + $data = $this->Post->read(null, 1); + $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); + $result = $this->Post->delete(1); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertTrue(empty($data)); + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], true); + $this->assertTrue(!empty($data['Post']['deleted_date'])); + } -/** - * testSoftDeleteWhenModelDataIsEmpty - * - * @return void - */ - public function testSoftDeleteWhenModelDataIsEmpty() { - $data = $this->Post->find('first', array('conditions' => array($this->Post->primaryKey => 1))); - $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); - $this->assertTrue(empty($this->Post->data)); - $result = $this->Post->delete(1); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertTrue(empty($data)); - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], true); - $this->assertTrue(!empty($data['Post']['deleted_date'])); - } + /** + * testSoftDeleteWhenModelDataIsEmpty + * + * @return void + */ + public function testSoftDeleteWhenModelDataIsEmpty() { + $data = $this->Post->find('first', array('conditions' => array($this->Post->primaryKey => 1))); + $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); + $this->assertTrue(empty($this->Post->data)); + $result = $this->Post->delete(1); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertTrue(empty($data)); + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], true); + $this->assertTrue(!empty($data['Post']['deleted_date'])); + } -/** - * testSoftDeleteUsingIdThatDoesNotExist - * - * @return void - */ - public function testSoftDeleteUsingIdThatDoesNotExist() { - $data = $this->Post->read(null, 222); - $this->assertTrue(empty($data)); - $result = $this->Post->delete(222); - $this->assertFalse($result); // consistent with Model->delete() - // previous implementation would try to create a new record - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 222); - $this->assertTrue(empty($data)); - } + /** + * testSoftDeleteUsingIdThatDoesNotExist + * + * @return void + */ + public function testSoftDeleteUsingIdThatDoesNotExist() { + $data = $this->Post->read(null, 222); + $this->assertTrue(empty($data)); + $result = $this->Post->delete(222); + $this->assertFalse($result); // consistent with Model->delete() + // previous implementation would try to create a new record + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 222); + $this->assertTrue(empty($data)); + } -/** - * testUnDelete - * - * @return void - */ - public function testUnDelete() { - $data = $this->Post->read(null, 1); - $result = $this->Post->delete(1); - $result = $this->Post->undelete(1); - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], false); - } + /** + * testUnDelete + * + * @return void + */ + public function testUnDelete() { + $data = $this->Post->read(null, 1); + $result = $this->Post->delete(1); + $result = $this->Post->undelete(1); + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], false); + } -/** - * testSoftDeletePurge - * - * @return void - */ - public function testSoftDeletePurge() { - $this->Post->Behaviors->disable('SoftDelete'); - $data = $this->Post->read(null, 3); - $this->assertTrue(!empty($data)); - $this->Post->Behaviors->enable('SoftDelete'); - $data = $this->Post->read(null, 3); - $this->assertTrue(empty($data)); - $count = $this->Post->purgeDeletedCount(); - $this->assertEquals($count, 1); - $this->Post->purgeDeleted(); - - $data = $this->Post->read(null, 3); - $this->assertTrue(empty($data)); - $this->Post->Behaviors->disable('SoftDelete'); - $data = $this->Post->read(null, 3); - $this->assertTrue(empty($data)); - } + /** + * testSoftDeletePurge + * + * @return void + */ + public function testSoftDeletePurge() { + $this->Post->Behaviors->disable('SoftDelete'); + $data = $this->Post->read(null, 3); + $this->assertTrue(!empty($data)); + $this->Post->Behaviors->enable('SoftDelete'); + $data = $this->Post->read(null, 3); + $this->assertTrue(empty($data)); + $count = $this->Post->purgeDeletedCount(); + $this->assertEquals($count, 1); + $this->Post->purgeDeleted(); -/** - * testExistsAndNotDeleted - * - * @return void - */ - public function testExistsAndNotDeleted() { - $data = $this->Post->read(null, 1); - $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); - $result = $this->Post->delete(1); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertTrue(empty($data)); - $this->assertFalse($this->Post->existsAndNotDeleted(1)); - $this->Post->undelete(1); - $this->assertTrue($this->Post->existsAndNotDeleted(1)); - } + $data = $this->Post->read(null, 3); + $this->assertTrue(empty($data)); + $this->Post->Behaviors->disable('SoftDelete'); + $data = $this->Post->read(null, 3); + $this->assertTrue(empty($data)); + } -/** - * testSoftDeleteAll - * - * @return void - */ - public function testSoftDeleteAll() { - $this->Post->saveAll(array( - array('title' => 'Test softDeleteAll'), - array('title' => 'Test softDeleteAll'), - array('title' => 'Test softDeleteAll') - )); - $this->Post->softDeleteAll(array( - 'Post.title' => 'Test softDeleteAll' - )); - $this->Post->Behaviors->unload('SoftDelete'); - $result = $this->Post->find('all', array( - 'conditions' => array( - 'Post.title' => 'Test softDeleteAll' - ), - 'fields' => array( - 'Post.title', - 'Post.deleted', - ) - )); - $expected = array( - 0 => array( - 'Post' => array( - 'title' => 'Test softDeleteAll', - 'deleted' => true - ) - ), - 1 => array( - 'Post' => array( - 'title' => 'Test softDeleteAll', - 'deleted' => true - ) - ), - 2 => array( - 'Post' => array( - 'title' => 'Test softDeleteAll', - 'deleted' => true - ) - ) - ); - $this->assertEquals($result, $expected); - } + /** + * testExistsAndNotDeleted + * + * @return void + */ + public function testExistsAndNotDeleted() { + $data = $this->Post->read(null, 1); + $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); + $result = $this->Post->delete(1); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertTrue(empty($data)); + $this->assertFalse($this->Post->existsAndNotDeleted(1)); + $this->Post->undelete(1); + $this->assertTrue($this->Post->existsAndNotDeleted(1)); + } -} + /** + * testSoftDeleteAll + * + * @return void + */ + public function testSoftDeleteAll() { + $this->Post->saveAll(array( + array('title' => 'Test softDeleteAll'), + array('title' => 'Test softDeleteAll'), + array('title' => 'Test softDeleteAll') + )); + $this->Post->softDeleteAll(array( + 'Post.title' => 'Test softDeleteAll' + )); + $this->Post->Behaviors->unload('SoftDelete'); + $result = $this->Post->find('all', array( + 'conditions' => array( + 'Post.title' => 'Test softDeleteAll' + ), + 'fields' => array( + 'Post.title', + 'Post.deleted', + ) + )); + $expected = array( + 0 => array( + 'Post' => array( + 'title' => 'Test softDeleteAll', + 'deleted' => true + ) + ), + 1 => array( + 'Post' => array( + 'title' => 'Test softDeleteAll', + 'deleted' => true + ) + ), + 2 => array( + 'Post' => array( + 'title' => 'Test softDeleteAll', + 'deleted' => true + ) + ) + ); + $this->assertEquals($result, $expected); + } + + public function testModelHasManyRelation() { + $this->Post->bindModel(array( + 'belongsTo' => array( + 'Article' => array( + 'foreignKey' => 'article_id' + ) + ) + )); + $this->Article->bindModel(array( + 'hasMany' => array( + 'Post' => array( + 'foreignKey' => 'article_id' + ) + ) + )); + $result = $this->Post->delete(1); + $this->Post->Behaviors->unload('SoftDelete'); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], true); + $this->assertTrue(!empty($data['Post']['deleted_date'])); + } + +} \ No newline at end of file diff --git a/Test/Fixture/ArticleFixture.php b/Test/Fixture/ArticleFixture.php index 095d03e..4b3a30b 100644 --- a/Test/Fixture/ArticleFixture.php +++ b/Test/Fixture/ArticleFixture.php @@ -7,36 +7,38 @@ */ class ArticleFixture extends CakeTestFixture { -/** - * name property - * - * @var string 'AnotherArticle' - */ - public $name = 'Article'; + /** + * name property + * + * @var string 'AnotherArticle' + */ + public $name = 'Article'; -/** - * fields property - * - * @var array - */ - public $fields = array( - 'id' => array('type' => 'integer', 'key' => 'primary'), - 'title' => array('type' => 'string', 'null' => false), - 'slug' => array('type' => 'string', 'null' => true), - 'tiny_slug' => array('type' => 'string', 'null' => true), - 'position' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10), - 'created' => 'datetime', - 'updated' => 'datetime'); + /** + * fields property + * + * @var array + */ + public $fields = array( + 'id' => array('type' => 'integer', 'key' => 'primary'), + 'title' => array('type' => 'string', 'null' => false), + 'slug' => array('type' => 'string', 'null' => true), + 'tiny_slug' => array('type' => 'string', 'null' => true), + 'position' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10), + 'deleted' => array('type' => 'boolean', 'null' => false, 'default' => '0'), + 'deleted_date' => 'datetime', + 'created' => 'datetime', + 'updated' => 'datetime'); -/** - * Records property - * - * @var array - */ - public $records = array( - array('id' => 1, 'title' => 'First Article', 'slug' => 'first_article', 'tiny_slug' => '0', 'position' => 1, 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'), - array('id' => 2, 'title' => 'Second Article', 'slug' => 'second_article', 'tiny_slug' => '1', 'position' => 2, 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), - array('id' => 3, 'title' => 'Third Article', 'slug' => 'third_article', 'tiny_slug' => '2', 'position' => 3, 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31') - ); + /** + * Records property + * + * @var array + */ + public $records = array( + array('id' => 1, 'title' => 'First Article', 'slug' => 'first_article', 'tiny_slug' => '0', 'position' => 1, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'), + array('id' => 2, 'title' => 'Second Article', 'slug' => 'second_article', 'tiny_slug' => '1', 'position' => 2, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), + array('id' => 3, 'title' => 'Third Article', 'slug' => 'third_article', 'tiny_slug' => '2', 'position' => 3, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31') + ); } \ No newline at end of file From d1fdbf797ddb26b7a60d77c1e939ca6cc29022f2 Mon Sep 17 00:00:00 2001 From: Jose Alejandro Alvarez Mendoza Date: Wed, 17 Jun 2015 17:31:18 -0430 Subject: [PATCH 2/2] Fixing code standards --- Model/Behavior/SoftDeleteBehavior.php | 794 ++++++++++---------- Test/Case/Model/Behavior/SoftDeleteTest.php | 463 ++++++------ Test/Fixture/ArticleFixture.php | 63 +- Test/Fixture/AssetFixture.php | 8 +- Test/Fixture/BArticleFixture.php | 47 +- Test/Fixture/BinaryArticleFixture.php | 3 +- Test/Fixture/CommentFixture.php | 36 +- Test/Fixture/ContentFixture.php | 21 +- Test/Fixture/ImageFixture.php | 4 +- Test/Fixture/LinkFixture.php | 16 +- Test/Fixture/PostFixture.php | 6 +- Test/Fixture/ProductFixture.php | 10 +- Test/Fixture/UsersAddonFixture.php | 22 +- 13 files changed, 753 insertions(+), 740 deletions(-) diff --git a/Model/Behavior/SoftDeleteBehavior.php b/Model/Behavior/SoftDeleteBehavior.php index 4c30436..b2fa860 100644 --- a/Model/Behavior/SoftDeleteBehavior.php +++ b/Model/Behavior/SoftDeleteBehavior.php @@ -19,400 +19,400 @@ */ class SoftDeleteBehavior extends ModelBehavior { - /** - * Default settings - * - * @var array $default - */ - public $default = array( - 'deleted' => 'deleted_date' - ); - - /** - * Holds activity flags for models - * - * @var array $runtime - */ - public $runtime = array(); - - /** - * Setup callback - * - * @param Model $model - * @param array $settings - */ - public function setup(Model $model, $settings = array()) { - if (empty($settings)) { - $settings = $this->default; - } elseif (!is_array($settings)) { - $settings = array($settings); - } - - $error = __d('utils', 'SoftDeleteBehavior::setup(): model %s has no field!', $model->name); - $fields = $this->_normalizeFields($model, $settings); - foreach ($fields as $flag => $date) { - if ($model->hasField($flag)) { - if ($date && !$model->hasField($date)) { - trigger_error($error . $date, E_USER_NOTICE); - return; - } - continue; - } - trigger_error($error . $flag, E_USER_NOTICE); - return; - } - - $this->settings[$model->alias] = $fields; - $this->softDelete($model, true); - } - - /** - * Before find callback - * - * @param Model $model - * @param array $query - * @return array - */ - public function beforeFind(Model $model, $query) { - $runtime = $this->runtime[$model->alias]; - if ($runtime) { - if (!is_array($query['conditions'])) { - $query['conditions'] = array(); - } - $conditions = array_filter(array_keys($query['conditions'])); - - $fields = $this->_normalizeFields($model); - - foreach ($fields as $flag => $date) { - if (true === $runtime || $flag === $runtime) { - if (!in_array($flag, $conditions) && !in_array($model->name . '.' . $flag, $conditions)) { - $query['conditions'][$model->alias . '.' . $flag] = false; - } - - if ($flag === $runtime) { - break; - } - } - } - return $query; - } - } - - /** - * Check if a record exists for the given id - * - * @param Model $model - * @param id - * @return mixed - */ - public function existsAndNotDeleted(Model $model, $id) { - if ($id === null) { - $id = $model->getID(); - } - if ($id === false) { - return false; - } - $exists = $model->find('count', array( - 'contain' => array(), - 'recursive' => -1, - 'conditions' => array( - $model->alias . '.' . $model->primaryKey => $id - ) - )); - return ($exists ? true : false); - } - - /** - * Before delete callback - * - * @param Model $model - * @param boolean $cascade - * @return boolean - */ - public function beforeDelete(Model $model, $cascade = true) { - $runtime = $this->runtime[$model->alias]; - if ($runtime) { - if ($model->beforeDelete($cascade)) { - $this->delete($model, $model->id); - } - return false; - } - return true; - } - - /** - * Mark record as deleted - * - * @param object $model - * @param integer $id - * @return boolean - */ - public function delete($model, $id) { - $runtime = $this->runtime[$model->alias]; - - $data = array(); - $fields = $this->_normalizeFields($model); - foreach ($fields as $flag => $date) { - if (true === $runtime || $flag === $runtime) { - $data[$flag] = true; - if ($date) { - $data[$date] = date('Y-m-d H:i:s'); - } - if ($flag === $runtime) { - break; - } - } - } - - $record = $model->find('first', array( - 'fields' => $model->primaryKey, - 'conditions' => array($model->primaryKey => $id), - 'contain' => array(), - 'recursive' => -1 - )); - - if (!empty($record)) { - $model->set($model->primaryKey, $id); - unset($model->data[$model->alias]['modified']); - unset($model->data[$model->alias]['updated']); - $result = $model->save(array($model->alias => $data), false, array_keys($data)); - if (!$result) { - return false; - } - } - - return true; - } - - /** - * Mark record as not deleted - * - * @param object $model - * @param integer $id - * @return boolean - */ - public function undelete($model, $id) { - $runtime = $this->runtime[$model->alias]; - $this->softDelete($model, false); - - $data = array(); - $fields = $this->_normalizeFields($model); - foreach ($fields as $flag => $date) { - if (true === $runtime || $flag === $runtime) { - $data[$flag] = false; - if ($date) { - $data[$date] = null; - } - if ($flag === $runtime) { - break; - } - } - } - - $model->create(); - $model->set($model->primaryKey, $id); - $result = $model->save(array($model->alias => $data), false, array_keys($data)); - $this->softDelete($model, $runtime); - if ($result) { - return true; - } - return false; - } - - /** - * Enable/disable SoftDelete functionality - * - * Usage from model: - * $this->softDelete(false); deactivate this behavior for model - * $this->softDelete('field_two'); enabled only for this flag field - * $this->softDelete(true); enable again for all flag fields - * $config = $this->softDelete(null); for obtaining current setting - * - * @param object $model - * @param mixed $active - * @return mixed if $active is null, then current setting/null, or boolean if runtime setting for model was changed - */ - public function softDelete($model, $active) { - if (is_null($active)) { - return isset($this->runtime[$model->alias]) ? $this->runtime[$model->alias] : null; - } - - $result = !isset($this->runtime[$model->alias]) || $this->runtime[$model->alias] !== $active; - $this->runtime[$model->alias] = $active; - $this->_softDeleteAssociations($model, $active); - return $result; - } - - /** - * Returns number of outdated softdeleted records prepared for purge - * - * @param object $model - * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' - * @return integer - */ - public function purgeDeletedCount($model, $expiration = '-90 days') { - $runtime = $this->runtime[$model->alias]; - $this->softDelete($model, false); - $result = $model->find('count', array( - 'conditions' => $this->_purgeDeletedConditions($model, $expiration), - 'recursive' => -1, - 'contain' => array() - ) - ); - $this->runtime[$model->alias] = $runtime; - return $result; - } - - /** - * Purge table - * - * @param object $model - * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' - * @return boolean if there were some outdated records - */ - public function purgeDeleted($model, $expiration = '-90 days') { - $this->softDelete($model, false); - $records = $model->find('all', array( - 'conditions' => $this->_purgeDeletedConditions($model, $expiration), - 'fields' => array($model->primaryKey), - 'recursive' => -1 - )); - if ($records) { - foreach ($records as $record) { - $model->delete($record[$model->alias][$model->primaryKey]); - } - return true; - } - return false; - } - - /** - * Returns conditions for finding outdated records - * - * @param object $model - * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' - * @return array - */ - protected function _purgeDeletedConditions($model, $expiration = '-90 days') { - $purgeDate = date('Y-m-d H:i:s', strtotime($expiration)); - $conditions = array(); - foreach ($this->settings[$model->alias] as $flag => $date) { - $conditions[$model->alias . '.' . $flag] = true; - if ($date) { - $conditions[$model->alias . '.' . $date . ' <'] = $purgeDate; - } - } - return $conditions; - } - - /** - * Return normalized field array - * - * @param object $model - * @param array $settings - * @return array - */ - protected function _normalizeFields($model, $settings = array()) { - if (empty($settings)) { - $settings = $this->settings[$model->alias]; - } - $result = array(); - foreach ($settings as $flag => $date) { - if (is_numeric($flag)) { - $flag = $date; - $date = false; - } - $result[$flag] = $date; - } - return $result; - } - - /** - * Modifies conditions of hasOne and hasMany associations - * - * If multiple delete flags are configured for model, then $active = true doesn't - * do anything - you have to alter conditions in association definition - * - * @param Model $model - * @param mixed $active - */ - protected function _softDeleteAssociations(Model $model, $active) { - if (empty($model->belongsTo)) { - return; - } - - $fields = array_keys($this->_normalizeFields($model)); - $parentModels = array_keys($model->belongsTo); - - foreach ($parentModels as $parentModel) { - - list($plugin, $modelClass) = pluginSplit($parentModel, true); - App::uses($modelClass, $plugin . 'Model'); - if (!class_exists($modelClass)) { - throw new MissingModelException(array('class' => $modelClass)); - } - $model->{$parentModel} = new $parentModel(null, null, $model->useDbConfig); - - foreach (array('hasOne', 'hasMany') as $assocType) { - if (empty($model->{$parentModel}->{$assocType})) { - continue; - } - - foreach ($model->{$parentModel}->{$assocType} as $assoc => $assocConfig) { - $modelName = empty($assocConfig['className']) ? $assoc : @$assocConfig['className']; - if ((!empty($model->plugin) && strstr($model->plugin . '.', $model->alias) === false ? $model->plugin . '.' : '') . $model->alias !== $modelName) { - continue; - } - - $conditions =& $model->{$parentModel}->{$assocType}[$assoc]['conditions']; - if (!is_array($conditions)) { - $model->{$parentModel}->{$assocType}[$assoc]['conditions'] = array(); - } - - $multiFields = 1 < count($fields); - foreach ($fields as $field) { - if ($active) { - if (!isset($conditions[$field]) && !isset($conditions[$assoc . '.' . $field])) { - if (is_string($active)) { - if ($field == $active) { - $conditions[$assoc . '.' . $field] = false; - } elseif (isset($conditions[$assoc . '.' . $field])) { - unset($conditions[$assoc . '.' . $field]); - } - } elseif (!$multiFields) { - $conditions[$assoc . '.' . $field] = false; - } - } - } elseif (isset($conditions[$assoc . '.' . $field])) { - unset($conditions[$assoc . '.' . $field]); - } - } - } - } - } - } - - /** - * Soft delete all - * - * @param Model $model - * @param array $conditions - * @return void - */ - public function softDeleteAll(Model $model, $conditions = array()) { - $results = $model->find('all', array( - 'contain' => array(), - 'recursive' => -1, - 'conditions' => $conditions, - 'fields' => array( - $model->alias . '.' . $model->primaryKey - ) - )); - if (empty($results)) { - return; - } - foreach ($results as $result) { - $this->delete($model, $result[$model->alias][$model->primaryKey]); - } - } -} +/** + * Default settings + * + * @var array $default + */ + public $default = array( + 'deleted' => 'deleted_date' + ); + +/** + * Holds activity flags for models + * + * @var array $runtime + */ + public $runtime = array(); + +/** + * Setup callback + * + * @param Model $model + * @param array $settings + */ + public function setup(Model $model, $settings = array()) { + if (empty($settings)) { + $settings = $this->default; + } elseif (!is_array($settings)) { + $settings = array($settings); + } + + $error = __d('utils', 'SoftDeleteBehavior::setup(): model %s has no field!', $model->name); + $fields = $this->_normalizeFields($model, $settings); + foreach ($fields as $flag => $date) { + if ($model->hasField($flag)) { + if ($date && !$model->hasField($date)) { + trigger_error($error . $date, E_USER_NOTICE); + return; + } + continue; + } + trigger_error($error . $flag, E_USER_NOTICE); + return; + } + + $this->settings[$model->alias] = $fields; + $this->softDelete($model, true); + } + +/** + * Before find callback + * + * @param Model $model + * @param array $query + * @return array + */ + public function beforeFind(Model $model, $query) { + $runtime = $this->runtime[$model->alias]; + if ($runtime) { + if (!is_array($query['conditions'])) { + $query['conditions'] = array(); + } + $conditions = array_filter(array_keys($query['conditions'])); + + $fields = $this->_normalizeFields($model); + + foreach ($fields as $flag => $date) { + if (true === $runtime || $flag === $runtime) { + if (!in_array($flag, $conditions) && !in_array($model->name . '.' . $flag, $conditions)) { + $query['conditions'][$model->alias . '.' . $flag] = false; + } + + if ($flag === $runtime) { + break; + } + } + } + return $query; + } + } + +/** + * Check if a record exists for the given id + * + * @param Model $model + * @param $id + * @return mixed + */ + public function existsAndNotDeleted(Model $model, $id) { + if ($id === null) { + $id = $model->getID(); + } + if ($id === false) { + return false; + } + $exists = $model->find('count', array( + 'contain' => array(), + 'recursive' => -1, + 'conditions' => array( + $model->alias . '.' . $model->primaryKey => $id + ) + )); + return ($exists ? true : false); + } + +/** + * Before delete callback + * + * @param Model $model + * @param bool $cascade + * @return bool + */ + public function beforeDelete(Model $model, $cascade = true) { + $runtime = $this->runtime[$model->alias]; + if ($runtime) { + if ($model->beforeDelete($cascade)) { + $this->delete($model, $model->id); + } + return false; + } + return true; + } + +/** + * Mark record as deleted + * + * @param object $model + * @param int $id + * @return bool + */ + public function delete($model, $id) { + $runtime = $this->runtime[$model->alias]; + + $data = array(); + $fields = $this->_normalizeFields($model); + foreach ($fields as $flag => $date) { + if (true === $runtime || $flag === $runtime) { + $data[$flag] = true; + if ($date) { + $data[$date] = date('Y-m-d H:i:s'); + } + if ($flag === $runtime) { + break; + } + } + } + + $record = $model->find('first', array( + 'fields' => $model->primaryKey, + 'conditions' => array($model->primaryKey => $id), + 'contain' => array(), + 'recursive' => -1 + )); + + if (!empty($record)) { + $model->set($model->primaryKey, $id); + unset($model->data[$model->alias]['modified']); + unset($model->data[$model->alias]['updated']); + $result = $model->save(array($model->alias => $data), false, array_keys($data)); + if (!$result) { + return false; + } + } + + return true; + } + +/** + * Mark record as not deleted + * + * @param object $model + * @param int $id + * @return bool + */ + public function undelete($model, $id) { + $runtime = $this->runtime[$model->alias]; + $this->softDelete($model, false); + + $data = array(); + $fields = $this->_normalizeFields($model); + foreach ($fields as $flag => $date) { + if (true === $runtime || $flag === $runtime) { + $data[$flag] = false; + if ($date) { + $data[$date] = null; + } + if ($flag === $runtime) { + break; + } + } + } + + $model->create(); + $model->set($model->primaryKey, $id); + $result = $model->save(array($model->alias => $data), false, array_keys($data)); + $this->softDelete($model, $runtime); + if ($result) { + return true; + } + return false; + } + +/** + * Enable/disable SoftDelete functionality + * + * Usage from model: + * $this->softDelete(false); deactivate this behavior for model + * $this->softDelete('field_two'); enabled only for this flag field + * $this->softDelete(true); enable again for all flag fields + * $config = $this->softDelete(null); for obtaining current setting + * + * @param object $model + * @param mixed $active + * @return mixed if $active is null, then current setting/null, or boolean if runtime setting for model was changed + */ + public function softDelete($model, $active) { + if (is_null($active)) { + return isset($this->runtime[$model->alias]) ? $this->runtime[$model->alias] : null; + } + + $result = !isset($this->runtime[$model->alias]) || $this->runtime[$model->alias] !== $active; + $this->runtime[$model->alias] = $active; + $this->_softDeleteAssociations($model, $active); + return $result; + } + +/** + * Returns number of outdated softdeleted records prepared for purge + * + * @param object $model + * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' + * @return int + */ + public function purgeDeletedCount($model, $expiration = '-90 days') { + $runtime = $this->runtime[$model->alias]; + $this->softDelete($model, false); + $result = $model->find('count', array( + 'conditions' => $this->_purgeDeletedConditions($model, $expiration), + 'recursive' => -1, + 'contain' => array() + ) + ); + $this->runtime[$model->alias] = $runtime; + return $result; + } + +/** + * Purge table + * + * @param object $model + * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' + * @return bool if there were some outdated records + */ + public function purgeDeleted($model, $expiration = '-90 days') { + $this->softDelete($model, false); + $records = $model->find('all', array( + 'conditions' => $this->_purgeDeletedConditions($model, $expiration), + 'fields' => array($model->primaryKey), + 'recursive' => -1 + )); + if ($records) { + foreach ($records as $record) { + $model->delete($record[$model->alias][$model->primaryKey]); + } + return true; + } + return false; + } + +/** + * Returns conditions for finding outdated records + * + * @param object $model + * @param mixed $expiration anything parseable by strtotime(), by default '-90 days' + * @return array + */ + protected function _purgeDeletedConditions($model, $expiration = '-90 days') { + $purgeDate = date('Y-m-d H:i:s', strtotime($expiration)); + $conditions = array(); + foreach ($this->settings[$model->alias] as $flag => $date) { + $conditions[$model->alias . '.' . $flag] = true; + if ($date) { + $conditions[$model->alias . '.' . $date . ' <'] = $purgeDate; + } + } + return $conditions; + } + +/** + * Return normalized field array + * + * @param object $model + * @param array $settings + * @return array + */ + protected function _normalizeFields($model, $settings = array()) { + if (empty($settings)) { + $settings = $this->settings[$model->alias]; + } + $result = array(); + foreach ($settings as $flag => $date) { + if (is_numeric($flag)) { + $flag = $date; + $date = false; + } + $result[$flag] = $date; + } + return $result; + } + +/** + * Modifies conditions of hasOne and hasMany associations + * + * If multiple delete flags are configured for model, then $active = true doesn't + * do anything - you have to alter conditions in association definition + * + * @param Model $model + * @param mixed $active + * @return void + */ + protected function _softDeleteAssociations(Model $model, $active) { + if (empty($model->belongsTo)) { + return; + } + + $fields = array_keys($this->_normalizeFields($model)); + $parentModels = array_keys($model->belongsTo); + + foreach ($parentModels as $parentModel) { + list($plugin, $modelClass) = pluginSplit($parentModel, true); + App::uses($modelClass, $plugin . 'Model'); + if (!class_exists($modelClass)) { + throw new MissingModelException(array('class' => $modelClass)); + } + $model->{$parentModel} = new $parentModel(null, null, $model->useDbConfig); + + foreach (array('hasOne', 'hasMany') as $assocType) { + if (empty($model->{$parentModel}->{$assocType})) { + continue; + } + + foreach ($model->{$parentModel}->{$assocType} as $assoc => $assocConfig) { + $modelName = empty($assocConfig['className']) ? $assoc : @$assocConfig['className']; + if ((!empty($model->plugin) && strstr($model->plugin . '.', $model->alias) === false ? $model->plugin . '.' : '') . $model->alias !== $modelName) { + continue; + } + + $conditions =& $model->{$parentModel}->{$assocType}[$assoc]['conditions']; + if (!is_array($conditions)) { + $model->{$parentModel}->{$assocType}[$assoc]['conditions'] = array(); + } + + $multiFields = 1 < count($fields); + foreach ($fields as $field) { + if ($active) { + if (!isset($conditions[$field]) && !isset($conditions[$assoc . '.' . $field])) { + if (is_string($active)) { + if ($field == $active) { + $conditions[$assoc . '.' . $field] = false; + } elseif (isset($conditions[$assoc . '.' . $field])) { + unset($conditions[$assoc . '.' . $field]); + } + } elseif (!$multiFields) { + $conditions[$assoc . '.' . $field] = false; + } + } + } elseif (isset($conditions[$assoc . '.' . $field])) { + unset($conditions[$assoc . '.' . $field]); + } + } + } + } + } + } + +/** + * Soft delete all + * + * @param Model $model + * @param array $conditions + * @return void + */ + public function softDeleteAll(Model $model, $conditions = array()) { + $results = $model->find('all', array( + 'contain' => array(), + 'recursive' => -1, + 'conditions' => $conditions, + 'fields' => array( + $model->alias . '.' . $model->primaryKey + ) + )); + if (empty($results)) { + return; + } + foreach ($results as $result) { + $this->delete($model, $result[$model->alias][$model->primaryKey]); + } + } +} \ No newline at end of file diff --git a/Test/Case/Model/Behavior/SoftDeleteTest.php b/Test/Case/Model/Behavior/SoftDeleteTest.php index 6d5b77c..c72ac05 100644 --- a/Test/Case/Model/Behavior/SoftDeleteTest.php +++ b/Test/Case/Model/Behavior/SoftDeleteTest.php @@ -29,26 +29,26 @@ */ class SoftDeletedPost extends CakeTestModel { - /** - * Use Table - * - * @var string - */ - public $useTable = 'posts'; +/** + * Use Table + * + * @var string + */ + public $useTable = 'posts'; - /** - * Behaviors - * - * @var array - */ - public $actsAs = array('Utils.SoftDelete'); +/** + * Behaviors + * + * @var array + */ + public $actsAs = array('Utils.SoftDelete'); - /** - * Alias - * - * @var string - */ - public $alias = 'Post'; +/** + * Alias + * + * @var string + */ + public $alias = 'Post'; } /** @@ -59,26 +59,26 @@ class SoftDeletedPost extends CakeTestModel { */ class SoftDeletedArticle extends CakeTestModel { - /** - * Use Table - * - * @var string - */ - public $useTable = 'articles'; +/** + * Use Table + * + * @var string + */ + public $useTable = 'articles'; - /** - * Behaviors - * - * @var array - */ - public $actsAs = array('Utils.SoftDelete'); +/** + * Behaviors + * + * @var array + */ + public $actsAs = array('Utils.SoftDelete'); - /** - * Alias - * - * @var string - */ - public $alias = 'Article'; +/** + * Alias + * + * @var string + */ + public $alias = 'Article'; } /** @@ -86,211 +86,212 @@ class SoftDeletedArticle extends CakeTestModel { */ class SoftDeleteTest extends CakeTestCase { - /** - * fixtures property - * - * @var array - */ - public $fixtures = array( - 'plugin.utils.post', - 'plugin.utils.article' - ); +/** + * fixtures property + * + * @var array + */ + public $fixtures = array( + 'plugin.utils.post', + 'plugin.utils.article' + ); - /** - * Creates the model instance - * - * @return void - */ - public function setUp() { - $this->Post = new SoftDeletedPost(); - $this->Article = new SoftDeletedArticle(); - } +/** + * Creates the model instance + * + * @return void + */ + public function setUp() { + $this->Post = new SoftDeletedPost(); + $this->Article = new SoftDeletedArticle(); + } - /** - * Destroy the model instance - * - * @return void - */ - public function tearDown() { - unset($this->Post); - ClassRegistry::flush(); - } +/** + * Destroy the model instance + * + * @return void + */ + public function tearDown() { + unset($this->Post); + ClassRegistry::flush(); + } + +/** + * Test saving a item + * + * @return void + */ + public function testSoftDelete() { + $data = $this->Post->read(null, 1); + $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); + $result = $this->Post->delete(1); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertTrue(empty($data)); + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], true); + $this->assertTrue(!empty($data['Post']['deleted_date'])); + } - /** - * Test saving a item - * - * @return void - */ - public function testSoftDelete() { - $data = $this->Post->read(null, 1); - $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); - $result = $this->Post->delete(1); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertTrue(empty($data)); - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], true); - $this->assertTrue(!empty($data['Post']['deleted_date'])); - } +/** + * testSoftDeleteWhenModelDataIsEmpty + * + * @return void + */ + public function testSoftDeleteWhenModelDataIsEmpty() { + $data = $this->Post->find('first', array('conditions' => array($this->Post->primaryKey => 1))); + $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); + $this->assertTrue(empty($this->Post->data)); + $result = $this->Post->delete(1); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertTrue(empty($data)); + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], true); + $this->assertTrue(!empty($data['Post']['deleted_date'])); + } - /** - * testSoftDeleteWhenModelDataIsEmpty - * - * @return void - */ - public function testSoftDeleteWhenModelDataIsEmpty() { - $data = $this->Post->find('first', array('conditions' => array($this->Post->primaryKey => 1))); - $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); - $this->assertTrue(empty($this->Post->data)); - $result = $this->Post->delete(1); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertTrue(empty($data)); - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], true); - $this->assertTrue(!empty($data['Post']['deleted_date'])); - } +/** + * testSoftDeleteUsingIdThatDoesNotExist + * + * @return void + */ + public function testSoftDeleteUsingIdThatDoesNotExist() { + $data = $this->Post->read(null, 222); + $this->assertTrue(empty($data)); + $result = $this->Post->delete(222); + $this->assertFalse($result); // consistent with Model->delete() + // previous implementation would try to create a new record + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 222); + $this->assertTrue(empty($data)); + } - /** - * testSoftDeleteUsingIdThatDoesNotExist - * - * @return void - */ - public function testSoftDeleteUsingIdThatDoesNotExist() { - $data = $this->Post->read(null, 222); - $this->assertTrue(empty($data)); - $result = $this->Post->delete(222); - $this->assertFalse($result); // consistent with Model->delete() - // previous implementation would try to create a new record - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 222); - $this->assertTrue(empty($data)); - } +/** + * testUnDelete + * + * @return void + */ + public function testUnDelete() { + $data = $this->Post->read(null, 1); + $result = $this->Post->delete(1); + $result = $this->Post->undelete(1); + $this->Post->Behaviors->unload('SoftDelete'); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], false); + } - /** - * testUnDelete - * - * @return void - */ - public function testUnDelete() { - $data = $this->Post->read(null, 1); - $result = $this->Post->delete(1); - $result = $this->Post->undelete(1); - $this->Post->Behaviors->unload('SoftDelete'); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], false); - } +/** + * testSoftDeletePurge + * + * @return void + */ + public function testSoftDeletePurge() { + $this->Post->Behaviors->disable('SoftDelete'); + $data = $this->Post->read(null, 3); + $this->assertTrue(!empty($data)); + $this->Post->Behaviors->enable('SoftDelete'); + $data = $this->Post->read(null, 3); + $this->assertTrue(empty($data)); + $count = $this->Post->purgeDeletedCount(); + $this->assertEquals($count, 1); + $this->Post->purgeDeleted(); - /** - * testSoftDeletePurge - * - * @return void - */ - public function testSoftDeletePurge() { - $this->Post->Behaviors->disable('SoftDelete'); - $data = $this->Post->read(null, 3); - $this->assertTrue(!empty($data)); - $this->Post->Behaviors->enable('SoftDelete'); - $data = $this->Post->read(null, 3); - $this->assertTrue(empty($data)); - $count = $this->Post->purgeDeletedCount(); - $this->assertEquals($count, 1); - $this->Post->purgeDeleted(); + $data = $this->Post->read(null, 3); + $this->assertTrue(empty($data)); + $this->Post->Behaviors->disable('SoftDelete'); + $data = $this->Post->read(null, 3); + $this->assertTrue(empty($data)); + } - $data = $this->Post->read(null, 3); - $this->assertTrue(empty($data)); - $this->Post->Behaviors->disable('SoftDelete'); - $data = $this->Post->read(null, 3); - $this->assertTrue(empty($data)); - } +/** + * testExistsAndNotDeleted + * + * @return void + */ + public function testExistsAndNotDeleted() { + $data = $this->Post->read(null, 1); + $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); + $result = $this->Post->delete(1); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertTrue(empty($data)); + $this->assertFalse($this->Post->existsAndNotDeleted(1)); + $this->Post->undelete(1); + $this->assertTrue($this->Post->existsAndNotDeleted(1)); + } - /** - * testExistsAndNotDeleted - * - * @return void - */ - public function testExistsAndNotDeleted() { - $data = $this->Post->read(null, 1); - $this->assertEquals($data[$this->Post->alias][$this->Post->primaryKey], 1); - $result = $this->Post->delete(1); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertTrue(empty($data)); - $this->assertFalse($this->Post->existsAndNotDeleted(1)); - $this->Post->undelete(1); - $this->assertTrue($this->Post->existsAndNotDeleted(1)); - } +/** + * testSoftDeleteAll + * + * @return void + */ + public function testSoftDeleteAll() { + $this->Post->saveAll(array( + array('title' => 'Test softDeleteAll'), + array('title' => 'Test softDeleteAll'), + array('title' => 'Test softDeleteAll') + )); + $this->Post->softDeleteAll(array( + 'Post.title' => 'Test softDeleteAll' + )); + $this->Post->Behaviors->unload('SoftDelete'); + $result = $this->Post->find('all', array( + 'conditions' => array( + 'Post.title' => 'Test softDeleteAll' + ), + 'fields' => array( + 'Post.title', + 'Post.deleted', + ) + )); + $expected = array( + 0 => array( + 'Post' => array( + 'title' => 'Test softDeleteAll', + 'deleted' => true + ) + ), + 1 => array( + 'Post' => array( + 'title' => 'Test softDeleteAll', + 'deleted' => true + ) + ), + 2 => array( + 'Post' => array( + 'title' => 'Test softDeleteAll', + 'deleted' => true + ) + ) + ); + $this->assertEquals($result, $expected); + } - /** - * testSoftDeleteAll - * - * @return void - */ - public function testSoftDeleteAll() { - $this->Post->saveAll(array( - array('title' => 'Test softDeleteAll'), - array('title' => 'Test softDeleteAll'), - array('title' => 'Test softDeleteAll') - )); - $this->Post->softDeleteAll(array( - 'Post.title' => 'Test softDeleteAll' - )); - $this->Post->Behaviors->unload('SoftDelete'); - $result = $this->Post->find('all', array( - 'conditions' => array( - 'Post.title' => 'Test softDeleteAll' - ), - 'fields' => array( - 'Post.title', - 'Post.deleted', - ) - )); - $expected = array( - 0 => array( - 'Post' => array( - 'title' => 'Test softDeleteAll', - 'deleted' => true - ) - ), - 1 => array( - 'Post' => array( - 'title' => 'Test softDeleteAll', - 'deleted' => true - ) - ), - 2 => array( - 'Post' => array( - 'title' => 'Test softDeleteAll', - 'deleted' => true - ) - ) - ); - $this->assertEquals($result, $expected); - } + public function testModelHasManyRelation() { + $this->Post->bindModel(array( + 'belongsTo' => array( + 'Article' => array( + 'foreignKey' => 'article_id' + ) + ) + )); - public function testModelHasManyRelation() { - $this->Post->bindModel(array( - 'belongsTo' => array( - 'Article' => array( - 'foreignKey' => 'article_id' - ) - ) - )); - $this->Article->bindModel(array( - 'hasMany' => array( - 'Post' => array( - 'foreignKey' => 'article_id' - ) - ) - )); - $result = $this->Post->delete(1); - $this->Post->Behaviors->unload('SoftDelete'); - $this->assertFalse($result); - $data = $this->Post->read(null, 1); - $this->assertEquals($data['Post']['deleted'], true); - $this->assertTrue(!empty($data['Post']['deleted_date'])); - } + $this->Article->bindModel(array( + 'hasMany' => array( + 'Post' => array( + 'foreignKey' => 'article_id' + ) + ) + )); + $result = $this->Post->delete(1); + $this->Post->Behaviors->unload('SoftDelete'); + $this->assertFalse($result); + $data = $this->Post->read(null, 1); + $this->assertEquals($data['Post']['deleted'], true); + $this->assertTrue(!empty($data['Post']['deleted_date'])); + } } \ No newline at end of file diff --git a/Test/Fixture/ArticleFixture.php b/Test/Fixture/ArticleFixture.php index 4b3a30b..71c51ea 100644 --- a/Test/Fixture/ArticleFixture.php +++ b/Test/Fixture/ArticleFixture.php @@ -7,38 +7,37 @@ */ class ArticleFixture extends CakeTestFixture { - /** - * name property - * - * @var string 'AnotherArticle' - */ - public $name = 'Article'; - - /** - * fields property - * - * @var array - */ - public $fields = array( - 'id' => array('type' => 'integer', 'key' => 'primary'), - 'title' => array('type' => 'string', 'null' => false), - 'slug' => array('type' => 'string', 'null' => true), - 'tiny_slug' => array('type' => 'string', 'null' => true), - 'position' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10), - 'deleted' => array('type' => 'boolean', 'null' => false, 'default' => '0'), - 'deleted_date' => 'datetime', - 'created' => 'datetime', - 'updated' => 'datetime'); +/** + * name property + * + * @var string 'AnotherArticle' + */ + public $name = 'Article'; - /** - * Records property - * - * @var array - */ - public $records = array( - array('id' => 1, 'title' => 'First Article', 'slug' => 'first_article', 'tiny_slug' => '0', 'position' => 1, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'), - array('id' => 2, 'title' => 'Second Article', 'slug' => 'second_article', 'tiny_slug' => '1', 'position' => 2, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), - array('id' => 3, 'title' => 'Third Article', 'slug' => 'third_article', 'tiny_slug' => '2', 'position' => 3, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31') - ); +/** + * fields property + * + * @var array + */ + public $fields = array( + 'id' => array('type' => 'integer', 'key' => 'primary'), + 'title' => array('type' => 'string', 'null' => false), + 'slug' => array('type' => 'string', 'null' => true), + 'tiny_slug' => array('type' => 'string', 'null' => true), + 'position' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10), + 'deleted' => array('type' => 'boolean', 'null' => false, 'default' => '0'), + 'deleted_date' => 'datetime', + 'created' => 'datetime', + 'updated' => 'datetime'); +/** + * Records property + * + * @var array + */ + public $records = array( + array('id' => 1, 'title' => 'First Article', 'slug' => 'first_article', 'tiny_slug' => '0', 'position' => 1, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'), + array('id' => 2, 'title' => 'Second Article', 'slug' => 'second_article', 'tiny_slug' => '1', 'position' => 2, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), + array('id' => 3, 'title' => 'Third Article', 'slug' => 'third_article', 'tiny_slug' => '2', 'position' => 3, 'deleted' => 0, 'deleted_date' => null, 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31') + ); } \ No newline at end of file diff --git a/Test/Fixture/AssetFixture.php b/Test/Fixture/AssetFixture.php index 0948f7a..c6dba07 100644 --- a/Test/Fixture/AssetFixture.php +++ b/Test/Fixture/AssetFixture.php @@ -30,10 +30,10 @@ class AssetFixture extends CakeTestFixture { ); public $records = array( - array('id' => 1, 'title'=> 'soccuer image', 'description'=> 'amazing shot...'), - array('id' => 2, 'title'=> 'animal image', 'description'=> 'very disturbing'), - array('id' => 11, 'title'=> 'home page link', 'description' => 'link back to home page'), - array('id' => 12, 'title'=> 'google', 'description' => 'Google is the search engine'), + array('id' => 1, 'title' => 'soccuer image', 'description' => 'amazing shot...'), + array('id' => 2, 'title' => 'animal image', 'description' => 'very disturbing'), + array('id' => 11, 'title' => 'home page link', 'description' => 'link back to home page'), + array('id' => 12, 'title' => 'google', 'description' => 'Google is the search engine'), ); } \ No newline at end of file diff --git a/Test/Fixture/BArticleFixture.php b/Test/Fixture/BArticleFixture.php index 464fa2b..2708c96 100644 --- a/Test/Fixture/BArticleFixture.php +++ b/Test/Fixture/BArticleFixture.php @@ -24,9 +24,9 @@ class BArticleFixture extends CakeTestFixture { public $fields = array( 'id' => array('type' => 'integer', 'null' => false, 'length' => 11, 'key' => 'primary'), 'title' => array('type' => 'string', 'null' => false), - 'parent_id' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 36), - 'lft' => array('type' => 'integer', 'null' => false, 'default' => NULL), - 'rght' => array('type' => 'integer', 'null' => false, 'default' => NULL), + 'parent_id' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 36), + 'lft' => array('type' => 'integer', 'null' => false, 'default' => null), + 'rght' => array('type' => 'integer', 'null' => false, 'default' => null), 'created' => 'datetime', 'modified' => 'datetime'); @@ -34,37 +34,36 @@ class BArticleFixture extends CakeTestFixture { array( 'id' => 1, 'title' => 'First article', - 'parent_id' => NULL, + 'parent_id' => null, 'lft' => 65537, 'rght' => 65542, 'created' => '2010-02-03 16:44:34', 'modified' => '2010-02-03 16:44:34', ), - array( - 'id' => 2, - 'title' => 'First article - child 1', - 'parent_id' => 1, - 'lft' => 65538, - 'rght' => 65541, - 'created' => '2010-02-03 17:07:06', - 'modified' => '2010-02-03 17:07:06', - ), - array( - 'id' => 3, - 'title' => 'First article - child 1 - subchild 1', - 'parent_id' => 2, - 'lft' => 65539, - 'rght' => 65540, - 'created' => '2010-02-03 17:42:27', - 'modified' => '2010-02-03 17:42:27'), + array( + 'id' => 2, + 'title' => 'First article - child 1', + 'parent_id' => 1, + 'lft' => 65538, + 'rght' => 65541, + 'created' => '2010-02-03 17:07:06', + 'modified' => '2010-02-03 17:07:06', + ), + array( + 'id' => 3, + 'title' => 'First article - child 1 - subchild 1', + 'parent_id' => 2, + 'lft' => 65539, + 'rght' => 65540, + 'created' => '2010-02-03 17:42:27', + 'modified' => '2010-02-03 17:42:27'), array( 'id' => 4, 'title' => 'Second article', - 'parent_id' => NULL, + 'parent_id' => null, 'lft' => 131073, 'rght' => 131074, 'created' => '2010-02-03 17:46:47', 'modified' => '2010-02-03 17:46:47') ); -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/Test/Fixture/BinaryArticleFixture.php b/Test/Fixture/BinaryArticleFixture.php index 755f117..e9fb76d 100644 --- a/Test/Fixture/BinaryArticleFixture.php +++ b/Test/Fixture/BinaryArticleFixture.php @@ -42,5 +42,4 @@ class BinaryArticleFixture extends CakeTestFixture { array('id' => 5, 'parent_id' => 3, 'title' => 'Forth Article', 'position' => 256, 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), array('id' => 6, 'parent_id' => 3, 'title' => 'Fifth Article', 'position' => 512, 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), ); -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/Test/Fixture/CommentFixture.php b/Test/Fixture/CommentFixture.php index 08eb64c..ba06cc3 100755 --- a/Test/Fixture/CommentFixture.php +++ b/Test/Fixture/CommentFixture.php @@ -1,18 +1,22 @@ array('type' => 'integer', 'key' => 'primary'), - 'content_id' => array('type' => 'integer', 'null' => false), - 'body' => 'text', - 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'), - 'permalink' => array('type' => 'string'), - 'parent_id' => array('type' => 'integer'), - 'created' => 'datetime', - 'updated' => 'datetime' - ); - -} -?> \ No newline at end of file + + public $name = 'Comment'; + + public $fields = array( + 'id' => array('type' => 'integer', 'key' => 'primary'), + 'content_id' => array('type' => 'integer', 'null' => false), + 'body' => 'text', + 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'), + 'permalink' => array('type' => 'string'), + 'parent_id' => array('type' => 'integer'), + 'created' => 'datetime', + 'updated' => 'datetime' + ); +} \ No newline at end of file diff --git a/Test/Fixture/ContentFixture.php b/Test/Fixture/ContentFixture.php index 169a5b5..9c5855d 100644 --- a/Test/Fixture/ContentFixture.php +++ b/Test/Fixture/ContentFixture.php @@ -1,6 +1,12 @@ 1, 'parent_id' => 0, 'type'=>'Article', 'title'=> 'Unearthed rare monster in london', 'body'=> 'very strange discovery...', 'permalink'=> 'unearthed-rare-monster-in-london'), - array('id' => 2, 'parent_id' => 0, 'type'=>'Article', 'title'=> 'about us', 'body'=> 'history of our company', 'permalink'=> 'about-us'), + array('id' => 1, 'parent_id' => 0, 'type' => 'Article', 'title' => 'Unearthed rare monster in london', 'body' => 'very strange discovery...', 'permalink' => 'unearthed-rare-monster-in-london'), + array('id' => 2, 'parent_id' => 0, 'type' => 'Article', 'title' => 'about us', 'body' => 'history of our company', 'permalink' => 'about-us'), /* Pages */ - array('id' => 100, 'parent_id' => 0, 'type' => 'Page', 'title' => 'Home page', 'body'=>'welcome to my site', 'permalink'=>''), - array('id' => 101, 'parent_id' => 100, 'type'=>'Page', 'title'=> 'Frequent Asked Questions', 'body'=> 'questions and more...', 'permalink'=> 'faq'), - array('id' => 102, 'parent_id' => 101, 'type'=>'Page', 'title'=> 'about us', 'body'=> 'CakePHP is a MVC PHP framework that aids development of... ', 'permalink'=> 'about-us'), + array('id' => 100, 'parent_id' => 0, 'type' => 'Page', 'title' => 'Home page', 'body' => 'welcome to my site', 'permalink' => ''), + array('id' => 101, 'parent_id' => 100, 'type' => 'Page', 'title' => 'Frequent Asked Questions', 'body' => 'questions and more...', 'permalink' => 'faq'), + array('id' => 102, 'parent_id' => 101, 'type' => 'Page', 'title' => 'about us', 'body' => 'CakePHP is a MVC PHP framework that aids development of... ', 'permalink' => 'about-us'), ); -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/Test/Fixture/ImageFixture.php b/Test/Fixture/ImageFixture.php index bd7320e..ecfdd94 100644 --- a/Test/Fixture/ImageFixture.php +++ b/Test/Fixture/ImageFixture.php @@ -32,8 +32,8 @@ class ImageFixture extends CakeTestFixture { * @var array */ public $records = array( - array('id' => 1, 'file_name'=> 'soccer_worldcup.jpg', 'file_size' =>' 53422', 'content_type' => 'image/jpeg'), - array('id' => 2, 'file_name'=> 'dog.png', 'file_size'=>'431234', 'content_type'=>'image/png') + array('id' => 1, 'file_name' => 'soccer_worldcup.jpg', 'file_size' => ' 53422', 'content_type' => 'image/jpeg'), + array('id' => 2, 'file_name' => 'dog.png', 'file_size' => '431234', 'content_type' => 'image/png') ); } \ No newline at end of file diff --git a/Test/Fixture/LinkFixture.php b/Test/Fixture/LinkFixture.php index e7a68fb..4f41973 100644 --- a/Test/Fixture/LinkFixture.php +++ b/Test/Fixture/LinkFixture.php @@ -1,6 +1,13 @@ 11, 'url'=> 'http://cakephp.org'), - array('id' => 12, 'url'=> 'http://google.com'), - + array('id' => 11, 'url' => 'http://cakephp.org'), + array('id' => 12, 'url' => 'http://google.com'), ); - } \ No newline at end of file diff --git a/Test/Fixture/PostFixture.php b/Test/Fixture/PostFixture.php index 6b2e0c9..4fd4d13 100644 --- a/Test/Fixture/PostFixture.php +++ b/Test/Fixture/PostFixture.php @@ -26,7 +26,7 @@ class PostFixture extends CakeTestFixture { 'article_id' => array('type' => 'integer'), 'title' => array('type' => 'string', 'null' => false), 'deleted' => array('type' => 'boolean', 'null' => false, 'default' => '0'), - 'deleted_date' => 'datetime', + 'deleted_date' => 'datetime', 'created' => 'datetime', 'updated' => 'datetime'); @@ -62,6 +62,4 @@ class PostFixture extends CakeTestFixture { 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31')); -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/Test/Fixture/ProductFixture.php b/Test/Fixture/ProductFixture.php index 280508e..8ab4a07 100644 --- a/Test/Fixture/ProductFixture.php +++ b/Test/Fixture/ProductFixture.php @@ -5,6 +5,7 @@ * @package cake * @subpackage cake.tests.fixtures */ + class ProductFixture extends CakeTestFixture { /** @@ -24,10 +25,9 @@ class ProductFixture extends CakeTestFixture { ); public $records = array( - array('id' => 1, 'name'=> 'Foot Ball DVD', 'description' =>'The best footie matches ever', 'published' => 0, 'publish_date' => null), - array('id' => 2, 'name'=> 'Cook like Jamie DVD', 'description' =>'Learn to cook like Jamie Oliver', 'published' => 1, 'publish_date' => null), - array('id' => 3, 'name'=> 'Utimte Fishing', 'description' =>'Where to Fish in the UK', 'published' => 0, 'publish_date' => '2004-06-19 21:05:31'), - array('id' => 4, 'name'=> 'Nigella from the Heart', 'description' =>'Nigella Eat your heart out', 'published' => 1, 'publish_date' => '2005-12-29 08:00:43'), + array('id' => 1, 'name' => 'Foot Ball DVD', 'description' => 'The best footie matches ever', 'published' => 0, 'publish_date' => null), + array('id' => 2, 'name' => 'Cook like Jamie DVD', 'description' => 'Learn to cook like Jamie Oliver', 'published' => 1, 'publish_date' => null), + array('id' => 3, 'name' => 'Utimte Fishing', 'description' => 'Where to Fish in the UK', 'published' => 0, 'publish_date' => '2004-06-19 21:05:31'), + array('id' => 4, 'name' => 'Nigella from the Heart', 'description' => 'Nigella Eat your heart out', 'published' => 1, 'publish_date' => '2005-12-29 08:00:43'), ); } -?> \ No newline at end of file diff --git a/Test/Fixture/UsersAddonFixture.php b/Test/Fixture/UsersAddonFixture.php index b05acbc..99dc4d5 100644 --- a/Test/Fixture/UsersAddonFixture.php +++ b/Test/Fixture/UsersAddonFixture.php @@ -1,5 +1,6 @@ array('type'=>'string', 'null' => false, 'length' => 36, 'key' => 'primary'), - 'addon_id' => array('type'=>'string', 'null' => false, 'length' => 36, 'key' => 'index'), - 'user_id' => array('type'=>'string', 'null' => false, 'length' => 36), - 'position' => array('type'=>'float', 'null' => false, 'default' => '1', 'length' => 4), - 'active' => array('type'=>'boolean', 'null' => false, 'default' => '0'), - 'created' => array('type'=>'datetime', 'null' => true, 'default' => NULL), - 'modified' => array('type'=>'datetime', 'null' => true, 'default' => NULL), + 'id' => array('type' => 'string', 'null' => false, 'length' => 36, 'key' => 'primary'), + 'addon_id' => array('type' => 'string', 'null' => false, 'length' => 36, 'key' => 'index'), + 'user_id' => array('type' => 'string', 'null' => false, 'length' => 36), + 'position' => array('type' => 'float', 'null' => false, 'default' => '1', 'length' => 4), + 'active' => array('type' => 'boolean', 'null' => false, 'default' => '0'), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => null), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null), 'indexes' => array( - 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'PRIMARY' => array('column' => 'id', 'unique' => 1), 'UNIQUE_ADDON_USER' => array('column' => array('addon_id', 'user_id'), 'unique' => 1)) ); + /** * Records * @@ -63,4 +67,4 @@ class UsersAddonFixture extends CakeTestFixture { 'active' => 1, 'created' => '2008-03-25 01:35:35', 'modified' => '2008-03-25 01:35:35')); -} +} \ No newline at end of file