Skip to content
Permalink
Browse files

rename pivot to junction

junction is a more familiar alternate name to "join table". The name
join cannot/shouldn't be used as it could easily be confused with a
function to join a table into a query, rather than a method for
getting/setting the table name/instance for the join table.

closes #2391
  • Loading branch information...
AD7six committed Dec 3, 2013
1 parent 1439118 commit a46e1c6a5df8ded092824e9dc267f779c671f693
@@ -24,7 +24,7 @@
use Cake\Utility\Inflector;
/**
* Represents an M - N relationship where there exists a pivot - or join - table
* Represents an M - N relationship where there exists a junction - or join - table
* that contains the association fields between the source and the target table.
*
* An example of a BelongsToMany association would be Article belongs to many Tags.
@@ -57,56 +57,56 @@ class BelongsToMany extends Association {
protected $_strategy = parent::STRATEGY_SELECT;
/**
* Pivot table instance
* Junction table instance
*
* @var Cake\ORM\Table
*/
protected $_pivotTable;
protected $_junctionTable;
/**
* The physical name of the pivot table
* Junction table name
*
* @var string
*/
protected $_joinTable;
protected $_junctionTableName;
/**
* The name of the hasMany association from the target table
* to the pivot table
* to the junction table
*
* @var string
*/
protected $_pivotAssociationName;
protected $_junctionAssociationName;
/**
* Sets the table instance for the pivot relation. If no arguments
* Sets the table instance for the junction relation. If no arguments
* are passed, the current configured table instance is returned
*
* @param string|Cake\ORM\Table $table Name or instance for the join table
* @return Cake\ORM\Table
*/
public function pivot($table = null) {
public function junction($table = null) {
$target = $this->target();
$source = $this->source();
$sAlias = $source->alias();
$tAlias = $target->alias();
if ($table === null) {
if (empty($this->_pivotTable)) {
$tableName = $this->_joinTableName();
if (empty($this->_junctionTable)) {
$tableName = $this->_junctionTableName();
$tableAlias = Inflector::camelize($tableName);
$table = TableRegistry::get($tableAlias, [
'table' => $tableName
]);
} else {
return $this->_pivotTable;
return $this->_junctionTable;
}
}
if (is_string($table)) {
$table = TableRegistry::get($table);
}
$pivotAlias = $table->alias();
$junctionAlias = $table->alias();
if (!$table->association($sAlias)) {
$table->belongsTo($sAlias)->target($source);
@@ -116,16 +116,16 @@ public function pivot($table = null) {
$table->belongsTo($tAlias)->target($target);
}
if (!$target->association($pivotAlias)) {
if (!$target->association($junctionAlias)) {
$target->belongsToMany($sAlias);
$target->hasMany($pivotAlias)->target($table);
$target->hasMany($junctionAlias)->target($table);
}
if (!$source->association($table->alias())) {
$source->hasMany($pivotAlias)->target($table);
$source->hasMany($junctionAlias)->target($table);
}
return $this->_pivotTable = $table;
return $this->_junctionTable = $table;
}
/**
@@ -147,8 +147,8 @@ public function pivot($table = null) {
*/
public function attachTo(Query $query, array $options = []) {
parent::attachTo($query, $options);
$pivot = $this->pivot();
$belongsTo = $pivot->association($this->source()->alias());
$junction = $this->junction();
$belongsTo = $junction->association($this->source()->alias());
$cond = $belongsTo->_joinCondition(['foreignKey' => $belongsTo->foreignKey()]);
if (isset($options['includeFields'])) {
@@ -157,12 +157,12 @@ public function attachTo(Query $query, array $options = []) {
$options = ['conditions' => [$cond]] + compact('includeFields');
$this->target()
->association($pivot->alias())
->association($junction->alias())
->attachTo($query, $options);
}
/**
* Return false as join conditions are defined in the pivot table
* Return false as join conditions are defined in the junction table
*
* @param array $options list of options passed to attachTo method
* @return boolean false
@@ -210,7 +210,7 @@ public function eagerLoader(array $options) {
$fetchQuery = $this->_buildQuery($options);
$resultMap = [];
$key = $options['foreignKey'];
$property = $this->target()->association($this->pivot()->alias())->property();
$property = $this->target()->association($this->junction()->alias())->property();
foreach ($fetchQuery->execute() as $result) {
$resultMap[$result[$property][$key]][] = $result;
@@ -220,7 +220,7 @@ public function eagerLoader(array $options) {
}
/**
* Clear out the data in the join/pivot table for a given entity.
* Clear out the data in the junction table for a given entity.
*
* @param Cake\ORM\Entity $entity The entity that started the cascading delete.
* @param array $options The options for the original delete.
@@ -235,7 +235,7 @@ public function cascadeDelete(Entity $entity, $options = []) {
// TODO fix multi-column primary keys.
$conditions = array_merge($conditions, $this->conditions());
$table = $this->pivot();
$table = $this->junction();
if ($this->_cascadeCallbacks) {
foreach ($table->find('all')->where($conditions) as $related) {
$table->delete($related, $options);
@@ -256,7 +256,7 @@ public function cascadeDelete(Entity $entity, $options = []) {
*/
protected function _addFilteringCondition($query, $key, $filter) {
return $query->contain([
$this->_pivotAssociationName() => [
$this->_junctionAssociationName() => [
'conditions' => [$key . ' in' => $filter],
'matching' => true
]
@@ -271,46 +271,46 @@ protected function _addFilteringCondition($query, $key, $filter) {
* @return string
*/
protected function _linkField($options) {
return sprintf('%s.%s', $this->_pivotAssociationName(), $options['foreignKey']);
return sprintf('%s.%s', $this->_junctionAssociationName(), $options['foreignKey']);
}
/**
* Returns the name of the association from the target table to the pivot table,
* Returns the name of the association from the target table to the junction table,
* this name is used to generate alias in the query and to later on retrieve the
* results.
*
* @return string
*/
protected function _pivotAssociationName() {
if (!$this->_pivotAssociationName) {
$this->_pivotAssociationName = $this->target()
->association($this->pivot()->alias())
protected function _junctionAssociationName() {
if (!$this->_junctionAssociationName) {
$this->_junctionAssociationName = $this->target()
->association($this->junction()->alias())
->name();
}
return $this->_pivotAssociationName;
return $this->_junctionAssociationName;
}
/**
* Sets the name of the pivot table.
* Sets the name of the junction 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) {
protected function _junctionTableName($name = null) {
if ($name === null) {
if (empty($this->_joinTable)) {
if (empty($this->_junctionTableName)) {
$aliases = array_map('\Cake\Utility\Inflector::underscore', [
$sAlias = $this->source()->alias(),
$tAlias = $this->target()->alias()
]);
sort($aliases);
$this->_joinTable = implode('_', $aliases);
$this->_junctionTableName = implode('_', $aliases);
}
return $this->_joinTable;
return $this->_junctionTableName;
}
return $this->_joinTable = $name;
return $this->_junctionTableName = $name;
}
/**
@@ -321,10 +321,10 @@ protected function _joinTableName($name = null) {
*/
protected function _options(array $opts) {
if (!empty($opts['through'])) {
$this->pivot($opts['through']);
$this->junction($opts['through']);
}
if (!empty($opts['joinTable'])) {
$this->_joinTableName($opts['joinTable']);
$this->_junctionTableName($opts['joinTable']);
}
$this->_externalOptions($opts);
}
@@ -595,7 +595,7 @@ public function hasMany($associated, array $options = []) {
* and target tables in this association.
* - cascadeCallbacks: Set to true if you want CakePHP to fire callbacks on
* cascaded deletes. If false the ORM will use deleteAll() to remove data.
* When true pivot table records will be loaded and then deleted.
* When true join/junction table records will be loaded and then deleted.
* - conditions: array with a list of conditions to filter the join with
* - sort: The order in which results for this association should be returned
* - strategy: The strategy to be used for selecting results Either 'select'
@@ -101,57 +101,57 @@ public function testRequiresKeys() {
}
/**
* Tests the pivot method
* Tests the junction method
*
* @return void
*/
public function testPivot() {
public function testJunction() {
$assoc = new BelongsToMany('Test', [
'sourceTable' => $this->article,
'targetTable' => $this->tag
]);
$pivot = $assoc->pivot();
$this->assertInstanceOf('\Cake\ORM\Table', $pivot);
$this->assertEquals('ArticlesTags', $pivot->alias());
$this->assertEquals('articles_tags', $pivot->table());
$this->assertSame($this->article, $pivot->association('Articles')->target());
$this->assertSame($this->tag, $pivot->association('Tags')->target());
$junction = $assoc->junction();
$this->assertInstanceOf('\Cake\ORM\Table', $junction);
$this->assertEquals('ArticlesTags', $junction->alias());
$this->assertEquals('articles_tags', $junction->table());
$this->assertSame($this->article, $junction->association('Articles')->target());
$this->assertSame($this->tag, $junction->association('Tags')->target());
$belongsTo = '\Cake\ORM\Association\BelongsTo';
$this->assertInstanceOf($belongsTo, $pivot->association('Articles'));
$this->assertInstanceOf($belongsTo, $pivot->association('Tags'));
$this->assertInstanceOf($belongsTo, $junction->association('Articles'));
$this->assertInstanceOf($belongsTo, $junction->association('Tags'));
$this->assertSame($pivot, $this->tag->association('ArticlesTags')->target());
$this->assertSame($junction, $this->tag->association('ArticlesTags')->target());
$this->assertSame($this->article, $this->tag->association('Articles')->target());
$hasMany = '\Cake\ORM\Association\HasMany';
$belongsToMany = '\Cake\ORM\Association\BelongsToMany';
$this->assertInstanceOf($belongsToMany, $this->tag->association('Articles'));
$this->assertInstanceOf($hasMany, $this->tag->association('ArticlesTags'));
$this->assertSame($pivot, $assoc->pivot());
$pivot2 = TableRegistry::get('Foos');
$assoc->pivot($pivot2);
$this->assertSame($pivot2, $assoc->pivot());
$this->assertSame($junction, $assoc->junction());
$junction2 = TableRegistry::get('Foos');
$assoc->junction($junction2);
$this->assertSame($junction2, $assoc->junction());
$assoc->pivot('ArticlesTags');
$this->assertSame($pivot, $assoc->pivot());
$assoc->junction('ArticlesTags');
$this->assertSame($junction, $assoc->junction());
}
/**
* Tests it is possible to set the table name for the join table
*
* @return void
*/
public function testPivotWithDefaultTableName() {
public function testJunctionWithDefaultTableName() {
$assoc = new BelongsToMany('Test', [
'sourceTable' => $this->article,
'targetTable' => $this->tag,
'joinTable' => 'tags_articles'
]);
$pivot = $assoc->pivot();
$this->assertEquals('TagsArticles', $pivot->alias());
$this->assertEquals('tags_articles', $pivot->table());
$junction = $assoc->junction();
$this->assertEquals('TagsArticles', $junction->alias());
$this->assertEquals('tags_articles', $junction->table());
}
/**
@@ -566,7 +566,7 @@ public function testCascadeDelete() {
'sort' => ['id' => 'ASC'],
];
$association = new BelongsToMany('Tags', $config);
$association->pivot($articleTag);
$association->junction($articleTag);
$articleTag->expects($this->once())
->method('deleteAll')
@@ -593,7 +593,7 @@ public function testCascadeDeleteWithCallbacks() {
'cascadeCallbacks' => true,
];
$association = new BelongsToMany('Tag', $config);
$association->pivot($articleTag);
$association->junction($articleTag);
$articleTagOne = new Entity(['article_id' => 1, 'tag_id' => 2]);
$articleTagTwo = new Entity(['article_id' => 1, 'tag_id' => 4]);
@@ -447,7 +447,7 @@ public function testBelongsToMany() {
$this->assertEquals(['b' => 'c'], $belongsToMany->conditions());
$this->assertEquals(['foo' => 'asc'], $belongsToMany->sort());
$this->assertSame($table, $belongsToMany->source());
$this->assertSame('things_tags', $belongsToMany->pivot()->table());
$this->assertSame('things_tags', $belongsToMany->junction()->table());
}
/**
@@ -887,7 +887,7 @@ public function testReciprocalHasManyLoading() {
}
/**
* Tests that the correct table and entity are loaded for the pivot association in
* Tests that the correct table and entity are loaded for the join association in
* a belongsToMany setup
*
* @return void
@@ -1681,8 +1681,8 @@ public function testDeleteBelongsToMany() {
$entity = $query->first();
$table->delete($entity);
$pivot = $table->association('tags')->pivot();
$query = $pivot->find('all')->where(['article_id' => 1]);
$junction = $table->association('tags')->junction();
$query = $junction->find('all')->where(['article_id' => 1]);
$this->assertNull($query->execute()->one(), 'Should not find any rows.');
}

0 comments on commit a46e1c6

Please sign in to comment.
You can’t perform that action at this time.