From 8ec20f875b194d95aee0abeb4a3bf1b9e84c4ed1 Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Sun, 26 May 2013 16:59:44 +0200 Subject: [PATCH] Improving and testing the pivot method --- lib/Cake/ORM/Association/BelongsToMany.php | 51 +++++++++++++++--- .../Association/ExternalAssociationTrait.php | 7 +++ .../ORM/Association/BelongsToManyTest.php | 53 +++++++++++++++---- 3 files changed, 94 insertions(+), 17 deletions(-) diff --git a/lib/Cake/ORM/Association/BelongsToMany.php b/lib/Cake/ORM/Association/BelongsToMany.php index b9ecb2cc774..b92e5851638 100644 --- a/lib/Cake/ORM/Association/BelongsToMany.php +++ b/lib/Cake/ORM/Association/BelongsToMany.php @@ -60,6 +60,13 @@ class BelongsToMany extends Association { */ protected $_pivotTable; +/** + * The physical name of the pivot table + * + * @var string + */ + protected $_joinTable; + /** * Sets the table instance for the pivot relation. If no arguments * are passed, the current configured table instance is returned @@ -70,12 +77,15 @@ class BelongsToMany extends Association { public function pivot($table = null) { $target = $this->target(); $source = $this->source(); - $sourceAlias = $source->alias(); - $targetAlias = $target->alias(); + $sAlias = $source->alias(); + $tAlias = $target->alias(); if ($table === null) { if (empty($this->_pivotTable)) { - $table = Table::build($sourceAlias . $targetAlias); + $table = Table::instance($sAlias . $tAlias); + $table = $table ?: Table::build($sAlias . $tAlias, [ + 'table' => $this->_joinTableName() + ]); } else { return $this->_pivotTable; } @@ -85,16 +95,16 @@ public function pivot($table = null) { $table = Table::build($table); } - if (!$table->association($sourceAlias)) { - $table->belongsTo($sourceAlias)->source($this->source()); + if (!$table->association($sAlias)) { + $table->belongsTo($sAlias)->source($this->source()); } - if (!$table->association($targetAlias)) { - $table->belongsTo($targetAlias)->target($this->target()); + if (!$table->association($tAlias)) { + $table->belongsTo($tAlias)->target($this->target()); } if (!$target->association($table->alias())) { - $target->belongsToMany($sourceAlias); + $target->belongsToMany($sAlias); $target->hasMany($table->alias())->target($table); } @@ -197,6 +207,28 @@ protected function _buildQuery($options) { return $fetchQuery; } +/** + * Sets the name of the pivot table. + * If no arguments are passed the current configured name is returned. A default + * name based of the associated tables will be generated if none found. + * + * @param string $name + * @return string + */ + protected function _joinTableName($name = null) { + if ($name === null) { + if (empty($this->_joinTableName)) { + $aliases = array_map('\Cake\Utility\Inflector::tableize', [ + $sAlias = $this->source()->alias(), + $tAlias = $this->target()->alias() + ]); + sort($aliases); + $name = implode('_', $aliases); + } + } + return $this->_joinTable = $name; + } + /** * Parse extra options passed in the constructor. * @param array $opts original list of options passed in constructor @@ -207,6 +239,9 @@ protected function _options(array $opts) { if (!empty($opts['through'])) { $this->pivot($opts['through']); } + if (!empty($opts['joinTable'])) { + $this->_joinTableName($opts['joinTable']); + } $this->_externalOptions($opts); } diff --git a/lib/Cake/ORM/Association/ExternalAssociationTrait.php b/lib/Cake/ORM/Association/ExternalAssociationTrait.php index 30c459abe49..b7f326278ef 100644 --- a/lib/Cake/ORM/Association/ExternalAssociationTrait.php +++ b/lib/Cake/ORM/Association/ExternalAssociationTrait.php @@ -93,6 +93,13 @@ public function requiresKeys($options = []) { */ public abstract function eagerLoader(array $options); +/** + * Returns a single or multiple conditions to be appended to the generated join + * clause for getting the results on the target table. + * + * @param array $options list of options passed to attachTo method + * @return string|array + */ protected function _joinCondition(array $options) { return sprintf('%s.%s = %s.%s', $this->_sourceTable->alias(), diff --git a/lib/Cake/Test/TestCase/ORM/Association/BelongsToManyTest.php b/lib/Cake/Test/TestCase/ORM/Association/BelongsToManyTest.php index 416c29d60a6..782c7847038 100644 --- a/lib/Cake/Test/TestCase/ORM/Association/BelongsToManyTest.php +++ b/lib/Cake/Test/TestCase/ORM/Association/BelongsToManyTest.php @@ -32,19 +32,17 @@ class BelongsToManyTest extends \Cake\TestSuite\TestCase { * @return void */ public function setUp() { - $this->author = Table::build('Author', [ + $this->tag = Table::build('Tag', [ 'schema' => [ 'id' => ['type' => 'integer'], - 'username' => ['type' => 'string'], + 'name' => ['type' => 'string'], ] ]); - $this->article = $this->getMock( - 'Cake\ORM\Table', ['find'], [['alias' => 'Article']] - ); - $this->article->schema([ - 'id' => ['type' => 'integer'], - 'title' => ['type' => 'string'], - 'author_id' => ['type' => 'integer'], + $this->article = Table::build('Article', [ + 'schema' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'string'], + ] ]); } @@ -93,4 +91,41 @@ public function testRequiresKeys() { $this->assertFalse($assoc->requiresKeys()); } +/** + * Tests the pivot method + * + * @return void + */ + public function testPivot() { + $assoc = new BelongsToMany('Test', [ + 'sourceTable' => $this->article, + 'targetTable' => $this->tag + ]); + $pivot = $assoc->pivot(); + $this->assertInstanceOf('\Cake\ORM\Table', $pivot); + $this->assertEquals('ArticleTag', $pivot->alias()); + $this->assertEquals('articles_tags', $pivot->table()); + $this->assertSame($this->article, $pivot->association('Article')->source()); + $this->assertSame($this->tag, $pivot->association('Tag')->target()); + + $belongsTo = '\Cake\ORM\Association\BelongsTo'; + $this->assertInstanceOf($belongsTo, $pivot->association('Article')); + $this->assertInstanceOf($belongsTo, $pivot->association('Tag')); + + $this->assertSame($pivot, $this->tag->association('ArticleTag')->target()); + $this->assertSame($this->article, $this->tag->association('Article')->target()); + + $hasMany = '\Cake\ORM\Association\HasMany'; + $belongsToMany = '\Cake\ORM\Association\BelongsToMany'; + $this->assertInstanceOf($belongsToMany, $this->tag->association('Article')); + $this->assertInstanceOf($hasMany, $this->tag->association('ArticleTag')); + + $this->assertSame($pivot, $assoc->pivot()); + $pivot2 = Table::build('Foo'); + $assoc->pivot($pivot2); + $this->assertSame($pivot2, $assoc->pivot()); + + $assoc->pivot('ArticleTag'); + $this->assertSame($pivot, $assoc->pivot()); + } }