diff --git a/src/Model/Behavior/Version/VersionTrait.php b/src/Model/Behavior/Version/VersionTrait.php index 10c1785..b7e72bc 100644 --- a/src/Model/Behavior/Version/VersionTrait.php +++ b/src/Model/Behavior/Version/VersionTrait.php @@ -37,11 +37,16 @@ public function versions($reset = false) } $table = TableRegistry::get($this->source()); - $primaryKey = $table->primaryKey(); - - $conditions = [$primaryKey => $this->id]; - $entities = $table->find('versions', ['conditions' => $conditions]) - ->all(); + $primaryKey = (array)$table->primaryKey(); + + $query = $table->find('versions'); + $pkValue = $this->extract($primaryKey); + $conditions = []; + foreach ($pkValue as $key => $value) { + $field = current($query->aliasField($key)); + $conditions[$field] = $value; + } + $entities = $query->where($conditions)->all(); if (empty($entities)) { return []; diff --git a/src/Model/Behavior/VersionBehavior.php b/src/Model/Behavior/VersionBehavior.php index 04db157..bc1118e 100644 --- a/src/Model/Behavior/VersionBehavior.php +++ b/src/Model/Behavior/VersionBehavior.php @@ -56,7 +56,8 @@ class VersionBehavior extends Behavior 'implementedFinders' => ['versions' => 'findVersions'], 'versionTable' => 'version', 'versionField' => 'version_id', - 'fields' => null + 'fields' => null, + 'foreignKey' => 'foreign_key' ]; /** @@ -95,7 +96,7 @@ public function setupFieldAssociations($table) $this->_table->hasOne($name, [ 'targetTable' => $target, - 'foreignKey' => 'foreign_key', + 'foreignKey' => $this->_config['foreignKey'], 'joinType' => 'LEFT', 'conditions' => [ $name . '.model' => $alias, @@ -106,7 +107,7 @@ public function setupFieldAssociations($table) } $this->_table->hasMany($table, [ - 'foreignKey' => 'foreign_key', + 'foreignKey' => $this->_config['foreignKey'], 'strategy' => 'subquery', 'conditions' => ["$table.model" => $alias], 'propertyName' => '__version', @@ -134,16 +135,14 @@ public function beforeSave(Event $event, Entity $entity, ArrayObject $options) $model = $this->_table->alias(); $primaryKey = (array)$this->_table->primaryKey(); - $primaryKey = current($primaryKey); - $foreignKey = $entity->get($primaryKey); + $foreignKey = $this->_extractForeignKey($entity); $versionField = $this->_config['versionField']; $preexistent = TableRegistry::get($table)->find() ->select(['version_id']) ->where([ - 'foreign_key' => $foreignKey, 'model' => $model - ]) + ] + $foreignKey) ->order(['id desc']) ->limit(1) ->hydrate(false) @@ -153,18 +152,17 @@ public function beforeSave(Event $event, Entity $entity, ArrayObject $options) $created = new Time(); foreach ($values as $field => $content) { - if ($field == $primaryKey || $field == $versionField) { + if (in_array($field, $primaryKey) || $field == $versionField) { continue; } $data = [ 'version_id' => $versionId, 'model' => $model, - 'foreign_key' => $foreignKey, 'field' => $field, 'content' => $content, 'created' => $created, - ]; + ] + $foreignKey; $event = new Event('Model.Version.beforeSave', $this, $options); $userData = EventManager::instance()->dispatch($event); @@ -179,7 +177,7 @@ public function beforeSave(Event $event, Entity $entity, ArrayObject $options) } $entity->set('__version', $new); - if (!empty($versionField) && in_array($versionField, $fields)) { + if (!empty($versionField) && in_array($versionField, $this->_table->schema()->columns())) { $entity->set($this->_config['versionField'], $versionId); } } @@ -216,14 +214,20 @@ public function findVersions(Query $query, array $options) { $table = $this->_config['versionTable']; return $query - ->contain([$table => function ($q) use ($table, $options) { + ->contain([$table => function ($q) use ($table, $options, $query) { if (!empty($options['primaryKey'])) { - $q->where(["$table.foreign_key IN" => $options['primaryKey']]); + $foreignKey = (array)$this->_config['foreignKey']; + $aliasedFK = []; + foreach ($foreignKey as $field) { + $aliasedFK[] = current($query->aliasField($field)) . ' IN'; + } + $conditions = array_combine($aliasedFK, (array)$options['primaryKey']); + $q->where($conditions); } if (!empty($options['versionId'])) { $q->where(["$table.version_id IN" => $options['versionId']]); } - $q->where(['field IN' => $this->_fields()]); + $q->where(["$table.field IN" => $this->_fields()]); return $q; }]) ->formatResults([$this, 'groupVersions'], $query::PREPEND); @@ -275,4 +279,19 @@ protected function _fields() return $fields; } + + /** + * Returns an array with foreignKey value. + * + * @param \Cake\Datasource\EntityInterface $entity Entity. + * @return array + */ + protected function _extractForeignKey($entity) + { + $foreignKey = (array)$this->_config['foreignKey']; + $primaryKey = (array)$this->_table->primaryKey(); + $pkValue = $entity->extract($primaryKey); + + return array_combine($foreignKey, $pkValue); + } } diff --git a/tests/Fixture/ArticlesTagsFixture.php b/tests/Fixture/ArticlesTagsFixture.php new file mode 100644 index 0000000..d7d3535 --- /dev/null +++ b/tests/Fixture/ArticlesTagsFixture.php @@ -0,0 +1,31 @@ + ['type' => 'integer'], + 'tag_id' => ['type' => 'integer'], + 'version_id' => ['type' => 'integer', 'null' => true], + 'sort_order' => ['type' => 'integer', 'default' => 1], + '_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['article_id', 'tag_id']]] + ]; + + /** + * records property + * + * @var array + */ + public $records = [ + ['article_id' => 1, 'tag_id' => 1, 'version_id' => 2, 'sort_order' => 1], + ]; +} diff --git a/tests/Fixture/ArticlesTagsVersionsFixture.php b/tests/Fixture/ArticlesTagsVersionsFixture.php new file mode 100644 index 0000000..563cf85 --- /dev/null +++ b/tests/Fixture/ArticlesTagsVersionsFixture.php @@ -0,0 +1,43 @@ + ['type' => 'integer'], + 'version_id' => ['type' => 'integer'], + 'model' => ['type' => 'string', 'null' => false], + 'article_id' => ['type' => 'integer', 'null' => false], + 'tag_id' => ['type' => 'integer', 'null' => false], + 'field' => ['type' => 'string', 'null' => false], + 'content' => ['type' => 'text'], + 'custom_field' => ['type' => 'text'], + '_constraints' => [ + 'primary' => ['type' => 'primary', 'columns' => ['id']], + ], + ]; + + /** + * records property + * + * @var array + */ + public $records = [ + ['version_id' => 1, 'model' => 'ArticlesTags', 'article_id' => 1, 'tag_id' => 1, 'field' => 'sort_order', 'content' => 1], + ['version_id' => 2, 'model' => 'ArticlesTags', 'article_id' => 1, 'tag_id' => 1, 'field' => 'sort_order', 'content' => 2], + ]; +} diff --git a/tests/TestCase/Model/Behavior/VersionBehaviorTest.php b/tests/TestCase/Model/Behavior/VersionBehaviorTest.php index e93b0da..327b4f0 100644 --- a/tests/TestCase/Model/Behavior/VersionBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/VersionBehaviorTest.php @@ -21,6 +21,8 @@ class VersionBehaviorTest extends TestCase public $fixtures = [ 'plugin.Josegonzalez\Version.versions', 'plugin.Josegonzalez\Version.articles', + 'plugin.Josegonzalez\Version.articles_tags_versions', + 'plugin.Josegonzalez\Version.articles_tags', ]; public function tearDown() @@ -207,4 +209,38 @@ function ($event) { ->toArray(); $this->assertNull($results[9]['custom_field']); } + + public function testFindWithCompositeKeys() + { + $table = TableRegistry::get('ArticlesTags', [ + 'entityClass' => 'Josegonzalez\Version\Test\TestCase\Model\Behavior\TestEntity' + ]); + $table->addBehavior('Josegonzalez/Version.Version', [ + 'fields' => 'sort_order', + 'versionTable' => 'articles_tags_versions', + 'foreignKey' => ['article_id', 'tag_id'] + ]); + + $entity = $table->find()->first(); + $this->assertEquals(['sort_order' => 1, 'version_id' => 1], $entity->version(1)->toArray()); + $this->assertEquals(['sort_order' => 2, 'version_id' => 2], $entity->version(2)->toArray()); + } + + public function testSaveWithCompositeKeys() + { + $table = TableRegistry::get('ArticlesTags', [ + 'entityClass' => 'Josegonzalez\Version\Test\TestCase\Model\Behavior\TestEntity' + ]); + $table->addBehavior('Josegonzalez/Version.Version', [ + 'fields' => 'sort_order', + 'versionTable' => 'articles_tags_versions', + 'foreignKey' => ['article_id', 'tag_id'] + ]); + + $entity = $table->find()->first(); + $entity->sort_order = 3; + $table->save($entity); + $this->assertEquals(3, $entity->version_id); + $this->assertEquals(['sort_order' => 3, 'version_id' => 3], $entity->version(3)->toArray()); + } }