Skip to content

Commit

Permalink
Improving and testing the pivot method
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed May 26, 2013
1 parent 326ad60 commit 8ec20f8
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 17 deletions.
51 changes: 43 additions & 8 deletions lib/Cake/ORM/Association/BelongsToMany.php
Expand Up @@ -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
Expand All @@ -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;
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -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
Expand All @@ -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);
}

Expand Down
7 changes: 7 additions & 0 deletions lib/Cake/ORM/Association/ExternalAssociationTrait.php
Expand Up @@ -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(),
Expand Down
53 changes: 44 additions & 9 deletions lib/Cake/Test/TestCase/ORM/Association/BelongsToManyTest.php
Expand Up @@ -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'],
]
]);
}

Expand Down Expand Up @@ -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());
}
}

0 comments on commit 8ec20f8

Please sign in to comment.