MorphToMany.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. namespace Illuminate\Database\Eloquent\Relations;
  3. use Illuminate\Database\Eloquent\Builder;
  4. use Illuminate\Database\Eloquent\Model;
  5. use Illuminate\Support\Arr;
  6. class MorphToMany extends BelongsToMany
  7. {
  8. /**
  9. * The type of the polymorphic relation.
  10. *
  11. * @var string
  12. */
  13. protected $morphType;
  14. /**
  15. * The class name of the morph type constraint.
  16. *
  17. * @var string
  18. */
  19. protected $morphClass;
  20. /**
  21. * Indicates if we are connecting the inverse of the relation.
  22. *
  23. * This primarily affects the morphClass constraint.
  24. *
  25. * @var bool
  26. */
  27. protected $inverse;
  28. /**
  29. * Create a new morph to many relationship instance.
  30. *
  31. * @param \Illuminate\Database\Eloquent\Builder $query
  32. * @param \Illuminate\Database\Eloquent\Model $parent
  33. * @param string $name
  34. * @param string $table
  35. * @param string $foreignPivotKey
  36. * @param string $relatedPivotKey
  37. * @param string $parentKey
  38. * @param string $relatedKey
  39. * @param string|null $relationName
  40. * @param bool $inverse
  41. * @return void
  42. */
  43. public function __construct(Builder $query, Model $parent, $name, $table, $foreignPivotKey,
  44. $relatedPivotKey, $parentKey, $relatedKey, $relationName = null, $inverse = false)
  45. {
  46. $this->inverse = $inverse;
  47. $this->morphType = $name.'_type';
  48. $this->morphClass = $inverse ? $query->getModel()->getMorphClass() : $parent->getMorphClass();
  49. parent::__construct(
  50. $query, $parent, $table, $foreignPivotKey,
  51. $relatedPivotKey, $parentKey, $relatedKey, $relationName
  52. );
  53. }
  54. /**
  55. * Set the where clause for the relation query.
  56. *
  57. * @return $this
  58. */
  59. protected function addWhereConstraints()
  60. {
  61. parent::addWhereConstraints();
  62. $this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);
  63. return $this;
  64. }
  65. /**
  66. * Set the constraints for an eager load of the relation.
  67. *
  68. * @param array $models
  69. * @return void
  70. */
  71. public function addEagerConstraints(array $models)
  72. {
  73. parent::addEagerConstraints($models);
  74. $this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);
  75. }
  76. /**
  77. * Create a new pivot attachment record.
  78. *
  79. * @param int $id
  80. * @param bool $timed
  81. * @return array
  82. */
  83. protected function baseAttachRecord($id, $timed)
  84. {
  85. return Arr::add(
  86. parent::baseAttachRecord($id, $timed), $this->morphType, $this->morphClass
  87. );
  88. }
  89. /**
  90. * Add the constraints for a relationship count query.
  91. *
  92. * @param \Illuminate\Database\Eloquent\Builder $query
  93. * @param \Illuminate\Database\Eloquent\Builder $parentQuery
  94. * @param array|mixed $columns
  95. * @return \Illuminate\Database\Eloquent\Builder
  96. */
  97. public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
  98. {
  99. return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where(
  100. $this->qualifyPivotColumn($this->morphType), $this->morphClass
  101. );
  102. }
  103. /**
  104. * Get the pivot models that are currently attached.
  105. *
  106. * @return \Illuminate\Support\Collection
  107. */
  108. protected function getCurrentlyAttachedPivots()
  109. {
  110. return parent::getCurrentlyAttachedPivots()->map(function ($record) {
  111. return $record instanceof MorphPivot
  112. ? $record->setMorphType($this->morphType)
  113. ->setMorphClass($this->morphClass)
  114. : $record;
  115. });
  116. }
  117. /**
  118. * Create a new query builder for the pivot table.
  119. *
  120. * @return \Illuminate\Database\Query\Builder
  121. */
  122. public function newPivotQuery()
  123. {
  124. return parent::newPivotQuery()->where($this->morphType, $this->morphClass);
  125. }
  126. /**
  127. * Create a new pivot model instance.
  128. *
  129. * @param array $attributes
  130. * @param bool $exists
  131. * @return \Illuminate\Database\Eloquent\Relations\Pivot
  132. */
  133. public function newPivot(array $attributes = [], $exists = false)
  134. {
  135. $using = $this->using;
  136. $attributes = array_merge([$this->morphType => $this->morphClass], $attributes);
  137. $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists)
  138. : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists);
  139. $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey)
  140. ->setMorphType($this->morphType)
  141. ->setMorphClass($this->morphClass);
  142. return $pivot;
  143. }
  144. /**
  145. * Get the pivot columns for the relation.
  146. *
  147. * "pivot_" is prefixed at each column for easy removal later.
  148. *
  149. * @return array
  150. */
  151. protected function aliasedPivotColumns()
  152. {
  153. $defaults = [$this->foreignPivotKey, $this->relatedPivotKey, $this->morphType];
  154. return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) {
  155. return $this->qualifyPivotColumn($column).' as pivot_'.$column;
  156. })->unique()->all();
  157. }
  158. /**
  159. * Get the foreign key "type" name.
  160. *
  161. * @return string
  162. */
  163. public function getMorphType()
  164. {
  165. return $this->morphType;
  166. }
  167. /**
  168. * Get the fully qualified morph type for the relation.
  169. *
  170. * @return string
  171. */
  172. public function getQualifiedMorphTypeName()
  173. {
  174. return $this->qualifyPivotColumn($this->morphType);
  175. }
  176. /**
  177. * Get the class name of the parent model.
  178. *
  179. * @return string
  180. */
  181. public function getMorphClass()
  182. {
  183. return $this->morphClass;
  184. }
  185. /**
  186. * Get the indicator for a reverse relationship.
  187. *
  188. * @return bool
  189. */
  190. public function getInverse()
  191. {
  192. return $this->inverse;
  193. }
  194. }