Skip to content

Commit

Permalink
Merge pull request #14 from robertpustulka/composite-keys
Browse files Browse the repository at this point in the history
Added support for custom and composite foreign keys.
  • Loading branch information
josegonzalez authored Sep 19, 2016
2 parents 6935921 + 17eafd6 commit 47f796e
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 19 deletions.
15 changes: 10 additions & 5 deletions src/Model/Behavior/Version/VersionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 [];
Expand Down
47 changes: 33 additions & 14 deletions src/Model/Behavior/VersionBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class VersionBehavior extends Behavior
'implementedFinders' => ['versions' => 'findVersions'],
'versionTable' => 'version',
'versionField' => 'version_id',
'fields' => null
'fields' => null,
'foreignKey' => 'foreign_key'
];

/**
Expand Down Expand Up @@ -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,
Expand All @@ -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',
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}
31 changes: 31 additions & 0 deletions tests/Fixture/ArticlesTagsFixture.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
namespace Josegonzalez\Version\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

class ArticlesTagsFixture extends TestFixture
{
public $table = 'articles_tags';

/**
* fields property
*
* @var array
*/
public $fields = [
'article_id' => ['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],
];
}
43 changes: 43 additions & 0 deletions tests/Fixture/ArticlesTagsVersionsFixture.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
namespace Josegonzalez\Version\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

class ArticlesTagsVersionsFixture extends TestFixture
{
/**
* table property
*
* @var string
*/
public $table = 'articles_tags_versions';

/**
* fields property
*
* @var array
*/
public $fields = [
'id' => ['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],
];
}
36 changes: 36 additions & 0 deletions tests/TestCase/Model/Behavior/VersionBehaviorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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());
}
}

0 comments on commit 47f796e

Please sign in to comment.