PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php

https://gitlab.com/madwanz64/laravel
PHP | 403 lines | 158 code | 46 blank | 199 comment | 8 complexity | 751859b5fbd0b30b887c8945d160d4e6 MD5 | raw file
  1. <?php
  2. namespace Illuminate\Database\Eloquent\Relations;
  3. use Closure;
  4. use Illuminate\Database\Eloquent\Builder;
  5. use Illuminate\Database\Eloquent\Collection;
  6. use Illuminate\Database\Eloquent\Model;
  7. use Illuminate\Database\Query\Expression;
  8. use Illuminate\Support\Arr;
  9. use Illuminate\Support\Traits\ForwardsCalls;
  10. use Illuminate\Support\Traits\Macroable;
  11. /**
  12. * @mixin \Illuminate\Database\Eloquent\Builder
  13. */
  14. abstract class Relation
  15. {
  16. use ForwardsCalls, Macroable {
  17. __call as macroCall;
  18. }
  19. /**
  20. * The Eloquent query builder instance.
  21. *
  22. * @var \Illuminate\Database\Eloquent\Builder
  23. */
  24. protected $query;
  25. /**
  26. * The parent model instance.
  27. *
  28. * @var \Illuminate\Database\Eloquent\Model
  29. */
  30. protected $parent;
  31. /**
  32. * The related model instance.
  33. *
  34. * @var \Illuminate\Database\Eloquent\Model
  35. */
  36. protected $related;
  37. /**
  38. * Indicates if the relation is adding constraints.
  39. *
  40. * @var bool
  41. */
  42. protected static $constraints = true;
  43. /**
  44. * An array to map class names to their morph names in database.
  45. *
  46. * @var array
  47. */
  48. public static $morphMap = [];
  49. /**
  50. * Create a new relation instance.
  51. *
  52. * @param \Illuminate\Database\Eloquent\Builder $query
  53. * @param \Illuminate\Database\Eloquent\Model $parent
  54. * @return void
  55. */
  56. public function __construct(Builder $query, Model $parent)
  57. {
  58. $this->query = $query;
  59. $this->parent = $parent;
  60. $this->related = $query->getModel();
  61. $this->addConstraints();
  62. }
  63. /**
  64. * Run a callback with constraints disabled on the relation.
  65. *
  66. * @param \Closure $callback
  67. * @return mixed
  68. */
  69. public static function noConstraints(Closure $callback)
  70. {
  71. $previous = static::$constraints;
  72. static::$constraints = false;
  73. // When resetting the relation where clause, we want to shift the first element
  74. // off of the bindings, leaving only the constraints that the developers put
  75. // as "extra" on the relationships, and not original relation constraints.
  76. try {
  77. return $callback();
  78. } finally {
  79. static::$constraints = $previous;
  80. }
  81. }
  82. /**
  83. * Set the base constraints on the relation query.
  84. *
  85. * @return void
  86. */
  87. abstract public function addConstraints();
  88. /**
  89. * Set the constraints for an eager load of the relation.
  90. *
  91. * @param array $models
  92. * @return void
  93. */
  94. abstract public function addEagerConstraints(array $models);
  95. /**
  96. * Initialize the relation on a set of models.
  97. *
  98. * @param array $models
  99. * @param string $relation
  100. * @return array
  101. */
  102. abstract public function initRelation(array $models, $relation);
  103. /**
  104. * Match the eagerly loaded results to their parents.
  105. *
  106. * @param array $models
  107. * @param \Illuminate\Database\Eloquent\Collection $results
  108. * @param string $relation
  109. * @return array
  110. */
  111. abstract public function match(array $models, Collection $results, $relation);
  112. /**
  113. * Get the results of the relationship.
  114. *
  115. * @return mixed
  116. */
  117. abstract public function getResults();
  118. /**
  119. * Get the relationship for eager loading.
  120. *
  121. * @return \Illuminate\Database\Eloquent\Collection
  122. */
  123. public function getEager()
  124. {
  125. return $this->get();
  126. }
  127. /**
  128. * Execute the query as a "select" statement.
  129. *
  130. * @param array $columns
  131. * @return \Illuminate\Database\Eloquent\Collection
  132. */
  133. public function get($columns = ['*'])
  134. {
  135. return $this->query->get($columns);
  136. }
  137. /**
  138. * Touch all of the related models for the relationship.
  139. *
  140. * @return void
  141. */
  142. public function touch()
  143. {
  144. $model = $this->getRelated();
  145. if (! $model::isIgnoringTouch()) {
  146. $this->rawUpdate([
  147. $model->getUpdatedAtColumn() => $model->freshTimestampString(),
  148. ]);
  149. }
  150. }
  151. /**
  152. * Run a raw update against the base query.
  153. *
  154. * @param array $attributes
  155. * @return int
  156. */
  157. public function rawUpdate(array $attributes = [])
  158. {
  159. return $this->query->withoutGlobalScopes()->update($attributes);
  160. }
  161. /**
  162. * Add the constraints for a relationship count query.
  163. *
  164. * @param \Illuminate\Database\Eloquent\Builder $query
  165. * @param \Illuminate\Database\Eloquent\Builder $parentQuery
  166. * @return \Illuminate\Database\Eloquent\Builder
  167. */
  168. public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery)
  169. {
  170. return $this->getRelationExistenceQuery(
  171. $query, $parentQuery, new Expression('count(*)')
  172. )->setBindings([], 'select');
  173. }
  174. /**
  175. * Add the constraints for an internal relationship existence query.
  176. *
  177. * Essentially, these queries compare on column names like whereColumn.
  178. *
  179. * @param \Illuminate\Database\Eloquent\Builder $query
  180. * @param \Illuminate\Database\Eloquent\Builder $parentQuery
  181. * @param array|mixed $columns
  182. * @return \Illuminate\Database\Eloquent\Builder
  183. */
  184. public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
  185. {
  186. return $query->select($columns)->whereColumn(
  187. $this->getQualifiedParentKeyName(), '=', $this->getExistenceCompareKey()
  188. );
  189. }
  190. /**
  191. * Get all of the primary keys for an array of models.
  192. *
  193. * @param array $models
  194. * @param string $key
  195. * @return array
  196. */
  197. protected function getKeys(array $models, $key = null)
  198. {
  199. return collect($models)->map(function ($value) use ($key) {
  200. return $key ? $value->getAttribute($key) : $value->getKey();
  201. })->values()->unique(null, true)->sort()->all();
  202. }
  203. /**
  204. * Get the underlying query for the relation.
  205. *
  206. * @return \Illuminate\Database\Eloquent\Builder
  207. */
  208. public function getQuery()
  209. {
  210. return $this->query;
  211. }
  212. /**
  213. * Get the base query builder driving the Eloquent builder.
  214. *
  215. * @return \Illuminate\Database\Query\Builder
  216. */
  217. public function getBaseQuery()
  218. {
  219. return $this->query->getQuery();
  220. }
  221. /**
  222. * Get the parent model of the relation.
  223. *
  224. * @return \Illuminate\Database\Eloquent\Model
  225. */
  226. public function getParent()
  227. {
  228. return $this->parent;
  229. }
  230. /**
  231. * Get the fully qualified parent key name.
  232. *
  233. * @return string
  234. */
  235. public function getQualifiedParentKeyName()
  236. {
  237. return $this->parent->getQualifiedKeyName();
  238. }
  239. /**
  240. * Get the related model of the relation.
  241. *
  242. * @return \Illuminate\Database\Eloquent\Model
  243. */
  244. public function getRelated()
  245. {
  246. return $this->related;
  247. }
  248. /**
  249. * Get the name of the "created at" column.
  250. *
  251. * @return string
  252. */
  253. public function createdAt()
  254. {
  255. return $this->parent->getCreatedAtColumn();
  256. }
  257. /**
  258. * Get the name of the "updated at" column.
  259. *
  260. * @return string
  261. */
  262. public function updatedAt()
  263. {
  264. return $this->parent->getUpdatedAtColumn();
  265. }
  266. /**
  267. * Get the name of the related model's "updated at" column.
  268. *
  269. * @return string
  270. */
  271. public function relatedUpdatedAt()
  272. {
  273. return $this->related->getUpdatedAtColumn();
  274. }
  275. /**
  276. * Get the name of the "where in" method for eager loading.
  277. *
  278. * @param \Illuminate\Database\Eloquent\Model $model
  279. * @param string $key
  280. * @return string
  281. */
  282. protected function whereInMethod(Model $model, $key)
  283. {
  284. return $model->getKeyName() === last(explode('.', $key))
  285. && in_array($model->getKeyType(), ['int', 'integer'])
  286. ? 'whereIntegerInRaw'
  287. : 'whereIn';
  288. }
  289. /**
  290. * Set or get the morph map for polymorphic relations.
  291. *
  292. * @param array|null $map
  293. * @param bool $merge
  294. * @return array
  295. */
  296. public static function morphMap(array $map = null, $merge = true)
  297. {
  298. $map = static::buildMorphMapFromModels($map);
  299. if (is_array($map)) {
  300. static::$morphMap = $merge && static::$morphMap
  301. ? $map + static::$morphMap : $map;
  302. }
  303. return static::$morphMap;
  304. }
  305. /**
  306. * Builds a table-keyed array from model class names.
  307. *
  308. * @param string[]|null $models
  309. * @return array|null
  310. */
  311. protected static function buildMorphMapFromModels(array $models = null)
  312. {
  313. if (is_null($models) || Arr::isAssoc($models)) {
  314. return $models;
  315. }
  316. return array_combine(array_map(function ($model) {
  317. return (new $model)->getTable();
  318. }, $models), $models);
  319. }
  320. /**
  321. * Get the model associated with a custom polymorphic type.
  322. *
  323. * @param string $alias
  324. * @return string|null
  325. */
  326. public static function getMorphedModel($alias)
  327. {
  328. return static::$morphMap[$alias] ?? null;
  329. }
  330. /**
  331. * Handle dynamic method calls to the relationship.
  332. *
  333. * @param string $method
  334. * @param array $parameters
  335. * @return mixed
  336. */
  337. public function __call($method, $parameters)
  338. {
  339. if (static::hasMacro($method)) {
  340. return $this->macroCall($method, $parameters);
  341. }
  342. $result = $this->forwardCallTo($this->query, $method, $parameters);
  343. if ($result === $this->query) {
  344. return $this;
  345. }
  346. return $result;
  347. }
  348. /**
  349. * Force a clone of the underlying query builder when cloning.
  350. *
  351. * @return void
  352. */
  353. public function __clone()
  354. {
  355. $this->query = clone $this->query;
  356. }
  357. }