MorphToMany.php
TLDR
This file defines the MorphToMany
class, which is a subclass of BelongsToMany
. It handles the many-to-many relationship between models that use polymorphic morphing. It includes methods to set constraints, attach records, create pivot models, and get pivot columns. It also includes methods to get the morph type, the class name of the parent model, and the indicator for a reverse relationship.
Methods
__construct
Creates a new MorphToMany
instance. It takes various parameters to initialize the relationship.
addWhereConstraints
Sets the where clause for the relation query.
addEagerConstraints
Sets the constraints for an eager load of the relation.
baseAttachRecord
Creates a new pivot attachment record.
getRelationExistenceQuery
Adds the constraints for a relationship count query.
getCurrentlyAttachedPivots
Gets the pivot models that are currently attached.
newPivotQuery
Creates a new query builder for the pivot table.
newPivot
Creates a new pivot model instance.
aliasedPivotColumns
Gets the pivot columns for the relation.
getMorphType
Gets the foreign key "type" name.
getMorphClass
Gets the class name of the parent model.
getInverse
Gets the indicator for a reverse relationship.
END
<?php
namespace Illuminate\Database\Eloquent\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
class MorphToMany extends BelongsToMany
{
/**
* The type of the polymorphic relation.
*
* @var string
*/
protected $morphType;
/**
* The class name of the morph type constraint.
*
* @var string
*/
protected $morphClass;
/**
* Indicates if we are connecting the inverse of the relation.
*
* This primarily affects the morphClass constraint.
*
* @var bool
*/
protected $inverse;
/**
* Create a new morph to many relationship instance.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Model $parent
* @param string $name
* @param string $table
* @param string $foreignPivotKey
* @param string $relatedPivotKey
* @param string $parentKey
* @param string $relatedKey
* @param string|null $relationName
* @param bool $inverse
* @return void
*/
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, $foreignPivotKey,
$relatedPivotKey, $parentKey, $relatedKey, $relationName
);
}
/**
* Set the where clause for the relation query.
*
* @return $this
*/
protected function addWhereConstraints()
{
parent::addWhereConstraints();
$this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);
return $this;
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
parent::addEagerConstraints($models);
$this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);
}
/**
* Create a new pivot attachment record.
*
* @param int $id
* @param bool $timed
* @return array
*/
protected function baseAttachRecord($id, $timed)
{
return Arr::add(
parent::baseAttachRecord($id, $timed), $this->morphType, $this->morphClass
);
}
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parentQuery
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
{
return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where(
$this->qualifyPivotColumn($this->morphType), $this->morphClass
);
}
/**
* Get the pivot models that are currently attached.
*
* @return \Illuminate\Support\Collection
*/
protected function getCurrentlyAttachedPivots()
{
return parent::getCurrentlyAttachedPivots()->map(function ($record) {
return $record instanceof MorphPivot
? $record->setMorphType($this->morphType)
->setMorphClass($this->morphClass)
: $record;
});
}
/**
* Create a new query builder for the pivot table.
*
* @return \Illuminate\Database\Query\Builder
*/
public function newPivotQuery()
{
return parent::newPivotQuery()->where($this->morphType, $this->morphClass);
}
/**
* Create a new pivot model instance.
*
* @param array $attributes
* @param bool $exists
* @return \Illuminate\Database\Eloquent\Relations\Pivot
*/
public function newPivot(array $attributes = [], $exists = false)
{
$using = $this->using;
$attributes = array_merge([$this->morphType => $this->morphClass], $attributes);
$pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists)
: MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists);
$pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey)
->setMorphType($this->morphType)
->setMorphClass($this->morphClass);
return $pivot;
}
/**
* Get the pivot columns for the relation.
*
* "pivot_" is prefixed at each column for easy removal later.
*
* @return array
*/
protected function aliasedPivotColumns()
{
$defaults = [$this->foreignPivotKey, $this->relatedPivotKey, $this->morphType];
return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) {
return $this->qualifyPivotColumn($column).' as pivot_'.$column;
})->unique()->all();
}
/**
* Get the foreign key "type" name.
*
* @return string
*/
public function getMorphType()
{
return $this->morphType;
}
/**
* Get the class name of the parent model.
*
* @return string
*/
public function getMorphClass()
{
return $this->morphClass;
}
/**
* Get the indicator for a reverse relationship.
*
* @return bool
*/
public function getInverse()
{
return $this->inverse;
}
}