8000 [5.5] Fix various problems with belongs to many by taylorotwell · Pull Request #18380 · laravel/framework · GitHub
[go: up one dir, main page]

Skip to content

[5.5] Fix various problems with belongs to many #18380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix various problems with belongs to many
  • Loading branch information
taylorotwell committed Mar 16, 2017
commit 110b282d280704fe0c62fe7b1482c3c414dec41f
51 changes: 31 additions & 20 deletions src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,15 @@ public function morphMany($related, $name, $type = null, $id = null, $localKey =
*
* @param string $related
* @param string $table
* @param string $foreignKey
* @param string $relatedKey
* @param string $foreignPivotKey
* @param string $relatedPivotKey
* @param string $parentKey
* @param string $localKey
* @param string $relatedKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $table = null, $foreignKey = null, $relatedKey = null,
$parentKey = null, $localKey = null, $relation = null)
public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null,
$parentKey = null, $relatedKey = null, $relation = null)
{
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
Expand All @@ -306,9 +306,9 @@ public function belongsToMany($related, $table = null, $foreignKey = null, $rela
// instances as well as the relationship instances we need for this.
$instance = $this->newRelatedInstance($related);

$foreignKey = $foreignKey ?: $this->getForeignKey();
$foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();

$relatedKey = $relatedKey ?: $instance->getForeignKey();
$relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();

// If no table name was provided, we can guess it by concatenating the two
// models using underscores in alphabetical order. The two model names
Expand All @@ -318,9 +318,9 @@ public function belongsToMany($related, $table = null, $foreignKey = null, $rela
}

return new BelongsToMany(
$instance->newQuery(), $this, $table, $foreignKey,
$relatedKey, $parentKey ?: $this->getKeyName(),
$localKey ?: $instance->getKeyName(), $relation
$instance->newQuery(), $this, $table, $foreignPivotKey,
$relatedPivotKey, $parentKey ?: $this->getKeyName(),
$relatedKey ?: $instance->getKeyName(), $relation
);
}

Expand All @@ -330,12 +330,16 @@ public function belongsToMany($related, $table = null, $foreignKey = null, $rela
* @param string $related
* @param string $name
* @param string $table
* @param string $foreignKey
* @param string $foreignPivotKey
* @param string $relatedPivotKey
* @param string $parentKey
* @param string $relatedKey
* @param bool $inverse
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function morphToMany($related, $name, $table = null, $foreignKey = null, $relatedKey = null, $inverse = false)
public function morphToMany($related, $name, $table = null, $foreignPivotKey = null,
$relatedPivotKey = null, $parentKey = null,
$relatedKey = null, $inverse = false)
{
$caller = $this->guessBelongsToManyRelation();

Expand All @@ -344,9 +348,9 @@ public function morphToMany($related, $name, $table = null, $foreignKey = null,
// instances, as well as the relationship instances we need for these.
$instance = $this->newRelatedInstance($related);

$foreignKey = $foreignKey ?: $name.'_id';
$foreignPivotKey = $foreignPivotKey ?: $name.'_id';

$relatedKey = $relatedKey ?: $instance->getForeignKey();
$relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();

// Now we're ready to create a new query builder for this related model and
// the relationship instances for this relation. This relations will set
Expand All @@ -355,7 +359,8 @@ public function morphToMany($related, $name, $table = null, $foreignKey = null,

return new MorphToMany(
$instance->newQuery(), $this, $name, $table,
$foreignKey, $relatedKey, $caller, $inverse
$foreignPivotKey, $relatedPivotKey, $parentKey ?: $this->getKeyName(),
$relatedKey ?: $instance->getKeyName(), $caller, $inverse
);
}

Expand All @@ -365,20 +370,26 @@ public function morphToMany($related, $name, $table = null, $foreignKey = null,
* @param string $related
* @param string $name
* @param string $table
* @param string $foreignKey
* @param string $foreignPivotKey
* @param string $relatedPivotKey
* @param string $parentKey
* @param string $relatedKey
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function morphedByMany($related, $name, $table = null, $foreignKey = null, $relatedKey = null)
public function morphedByMany($related, $name, $table = null, $foreignPivotKey = null,
$relatedPivotKey = null, $parentKey = null, $relatedKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();

// For the inverse of the polymorphic many-to-many relations, we will change
// the way we determine the foreign and other keys, as it is the opposite
// of the morph-to-many method since we're figuring out these inverses.
$relatedKey = $relatedKey ?: $name.'_id';
$relatedPivotKey = $relatedPivotKey ?: $name.'_id';

return $this->morphToMany($related, $name, $table, $foreignKey, $relatedKey, true);
return $this->morphToMany(
$related, $name, $table, $foreignPivotKey,
$relatedPivotKey, $parentKey, $relatedKey, true
);
}

/**
Expand Down
36 changes: 18 additions & 18 deletions src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ class BelongsToMany extends Relation
*
* @var string
*/
protected $foreignKey;
protected $foreignPivotKey;

/**
* The associated key of the relation.
*
* @var string
*/
protected $relatedKey;
protected $relatedPivotKey;

/**
* The key name of the parent model.
Expand All @@ -46,7 +46,7 @@ class BelongsToMany extends Relation
*
* @var string
*/
protected $localKey;
protected $relatedKey;

/**
* The "name" of the relationship.
Expand Down Expand Up @@ -117,15 +117,15 @@ class BelongsToMany extends Relation
* @param string $relationName
* @return void
*/
public function __construct(Builder $query, Model $parent, $table, $foreignKey,
$relatedKey, $parentKey, $localKey, $relationName = null)
public function __construct(Builder $query, Model $parent, $table, $foreignPivotKey,
$relatedPivotKey, $parentKey, $relatedKey, $relationName = null)
{
$this->table = $table;
$this->localKey = $localKey;
$this->parentKey = $parentKey;
$this->relatedKey = $relatedKey;
$this->foreignKey = $foreignKey;
$this->relationName = $relationName;
$this->relatedPivotKey = $relatedPivotKey;
$this->foreignPivotKey = $foreignPivotKey;

parent::__construct($query, $parent);
}
Expand Down Expand Up @@ -159,9 +159,9 @@ protected function performJoin($query = null)
// model instance. Then we can set the "where" for the parent models.
$baseTable = $this->related->getTable();

$key = $baseTable.'.'.$this->localKey;
$key = $baseTable.'.'.$this->relatedKey;

$query->join($this->table, $key, '=', $this->getQualifiedRelatedKeyName());
$query->join($this->table, $key, '=', $this->getQualifiedRelatedPivotKeyName());

return $this;
}
Expand All @@ -174,7 +174,7 @@ protected function performJoin($query = null)
protected function addWhereConstraints()
{
$this->query->where(
$this->getQualifiedForeignKeyName(), '=', $this->parent->{$this->parentKey}
$this->getQualifiedForeignPivotKeyName(), '=', $this->parent->{$this->parentKey}
);

return $this;
Expand All @@ -188,7 +188,7 @@ protected function addWhereConstraints()
*/
public function addEagerConstraints(array $models)
{
$this->query->whereIn($this->getQualifiedForeignKeyName(), $this->getKeys($models));
$this->query->whereIn($this->getQualifiedForeignPivotKeyName(), $this->getKeys($models));
}

/**
Expand Down Expand Up @@ -247,7 +247,7 @@ protected function buildDictionary(Collection $results)
$dictionary = [];

foreach ($results as $result) {
$dictionary[$result->pivot->{$this->foreignKey}][] = $result;
$dictionary[$result->pivot->{$this->foreignPivotKey}][] = $result;
}

return $dictionary;
Expand Down Expand Up @@ -540,7 +540,7 @@ protected function shouldSelect(array $columns = ['*'])
*/
protected function aliasedPivotColumns()
{
$defaults = [$this->foreignKey, $this->relatedKey];
$defaults = [$this->foreignPivotKey, $this->relatedPivotKey];

return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) {
return $this->table.'.'.$column.' as pivot_'.$column;
Expand Down Expand Up @@ -840,7 +840,7 @@ public function getRelationExistenceQueryForSelfJoin(Builder $query, Builder $pa
*/
public function getExistenceCompareKey()
{
return $this->getQualifiedForeignKeyName();
return $this->getQualifiedForeignPivotKeyName();
}

/**
Expand Down Expand Up @@ -893,19 +893,19 @@ public function updatedAt()
*
* @return string
*/
public function getQualifiedForeignKeyName()
public function getQualifiedForeignPivotKeyName()
{
return $this->table.'.'.$this->foreignKey;
return $this->table.'.'.$this->foreignPivotKey;
}

/**
* Get the fully qualified "related key" for the relation.
*
* @return string
*/
public function getQualifiedRelatedKeyName()
public function getQualifiedRelatedPivotKeyName()
{
return $this->table.'.'.$this->relatedKey;
return $this->table.'.'.$this->relatedPivotKey;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function toggle($ids, $touch = true)
// checking which of the given ID/records is in the list of current records
// and removing all of those rows from this "intermediate" joining table.
$detach = array_values(array_intersect(
$this->newPivotQuery()->pluck($this->relatedKey)->all(),
$this->newPivotQuery()->pluck($this->relatedPivotKey)->all(),
array_keys($records)
));

Expand Down Expand Up @@ -89,7 +89,7 @@ public function sync($ids, $detaching = true)
// in this joining table. We'll spin through the given IDs, checking to see
// if they exist in the array of current ones, and if not we will insert.
$current = $this->newPivotQuery()->pluck(
$this->relatedKey
$this->relatedPivotKey
)->all();

$detach = array_diff($current, array_keys(
Expand Down Expand Up @@ -287,9 +287,9 @@ protected function extractAttachIdAndAttributes($key, $value, array $attributes)
*/
protected function baseAttachRecord($id, $timed)
{
$record[$this->relatedKey] = $id;
$record[$this->relatedPivotKey] = $id;

$record[$this->foreignKey] = $this->parent->getKey();
$record[$this->foreignPivotKey] = $this->parent->getKey();

// If the record needs to have creation and update timestamps, we will make
// them by calling the parent model's "freshTimestamp" method which will
Expand Down Expand Up @@ -353,7 +353,7 @@ public function detach($ids = null, $touch = true)
return 0;
}

$query->whereIn($this->relatedKey, (array) $ids);
$query->whereIn($this->relatedPivotKey, (array) $ids);
}

// Once we have all of the conditions set on the statement, we are ready
Expand Down Expand Up @@ -381,7 +381,7 @@ public function newPivot(array $attributes = [], $exists = false)
$this->parent, $attributes, $this->table, $exists, $this->using
);

return $pivot->setPivotKeys($this->foreignKey, $this->relatedKey);
return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey);
}

/**
Expand Down Expand Up @@ -413,7 +413,7 @@ public function newPivotStatement()
*/
public function newPivotStatementForId($id)
{
return $this->newPivotQuery()->where($this->relatedKey, $id);
return $this->newPivotQuery()->where($this->relatedPivotKey, $id);
}

/**
Expand All @@ -433,7 +433,7 @@ protected function newPivotQuery()
call_user_func_array([$query, 'whereIn'], $arguments);
}

return $query->where($this->foreignKey, $this->parent->getKey());
return $query->where($this->foreignPivotKey, $this->parent->getKey());
}

/**
Expand Down
17 changes: 10 additions & 7 deletions src/Illuminate/Database/Eloquent/Relations/MorphToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,25 @@ class MorphToMany extends BelongsToMany
* @param \Illuminate\Database\Eloquent\Model $parent
* @param string $name
* @param string $table
* @param string $foreignKey
* @param string $relatedKey
* @param string $foreignPivotKey
* @param string $relatedPivotKey
* @param string $parentKey
* @param string $localKey
* @param string $relatedKey
* @param string $relationName
* @param bool $inverse
* @return void
*/
public function __construct(Builder $query, Model $parent, $name, $table, $foreignKey,
$relatedKey, $parentKey, $localKey, $relationName = null, $inverse = false)
public function __construct(Builder $query, Model $parent, $name, $table, $foreignPivotKey,
$relatedPivotKey, $parentKey, $relatedKey, $relationName = null, $inverse = false)
{
$this->inverse = $inverse;
$this->morphType = $name.'_type';
$this->morphClass = $inverse ? $query->getModel()->getMorphClass() : $parent->getMorphClass();

parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $parentKey, $localKey, $relationName);
parent::__construct(
$query, $parent, $table, $foreignPivotKey,
$relatedPivotKey, $parentKey, $relatedKey, $relationName
);
}

/**
Expand Down Expand Up @@ -136,7 +139,7 @@ public function newPivot(array $attributes = [], $exists = false)
$pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists)
: new MorphPivot($this->parent, $attributes, $this->table, $exists);

$pivot->setPivotKeys($this->foreignKey, $this->relatedKey)
$pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey)
->setMorphType($this->morphType)
->setMorphClass($this->morphClass);

Expand Down
8 changes: 4 additions & 4 deletions tests/Database/DatabaseEloquentModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1015,17 +1015,17 @@ public function testBelongsToManyCreatesProperRelation()
$this->addMockConnection($model);

$relation = $model->belongsToMany('Illuminate\Tests\Database\EloquentModelSaveStub');
$this->assertEquals('eloquent_model_save_stub_eloquent_model_stub.eloquent_model_stub_id', $relation->getQualifiedForeignKeyName());
$this->assertEquals('eloquent_model_save_stub_eloquent_model_stub.eloquent_model_save_stub_id', $relation->getQualifiedRelatedKeyName());
$this->assertEquals('eloquent_model_save_stub_eloquent_model_stub.eloquent_model_stub_id', $relation->getQualifiedForeignPivotKeyName());
$this->assertEquals('eloquent_model_save_stub_eloquent_model_stub.eloquent_model_save_stub_id', $relation->getQualifiedRelatedPivotKeyName());
$this->assertSame($model, $relation->getParent());
$this->assertInstanceOf('Illuminate\Tests\Database\EloquentModelSaveStub', $relation->getQuery()->getModel());
$this->assertEquals(__FUNCTION__, $relation->getRelationName());

$model = new EloquentModelStub;
$this->addMockConnection($model);
$relation = $model->belongsToMany('Illuminate\Tests\Database\EloquentModelSaveStub', 'table', 'foreign', 'other');
$this->assertEquals('table.foreign', $relation->getQualifiedForeignKeyName());
$this->assertEquals('table.other', $relation->getQualifiedRelatedKeyName());
$this->assertEquals('table.foreign', $relation->getQualifiedForeignPivotKeyName());
$this->assertEquals('table.other', $relation->getQualifiedRelatedPivotKeyName());
$this->assertSame($model, $relation->getParent());
$this->assertInstanceOf('Illuminate\Tests\Database\EloquentModelSaveStub', $relation->getQuery()->getModel());
}
Expand Down
0