![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/ts.corals.io/corals-api/Corals/core/Foundation/Models/Relations/ |
<?php namespace Corals\Foundation\Models\Relations; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\SoftDeletes; class HasManyDeep extends HasManyThrough { /** * The "through" parent model instances. * * @var \Illuminate\Database\Eloquent\Model[] */ protected $throughParents; /** * The foreign keys on the relationship. * * @var array */ protected $foreignKeys; /** * The local keys on the relationship. * * @var array */ protected $localKeys; /** * The intermediate tables to retrieve. * * @var array */ protected $intermediateTables = []; /** * Create a new has many deep relationship instance. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Model $farParent * @param \Illuminate\Database\Eloquent\Model[] $throughParents * @param array $foreignKeys * @param array $localKeys * @return void */ public function __construct(Builder $query, Model $farParent, array $throughParents, array $foreignKeys, array $localKeys) { $this->throughParents = $throughParents; $this->foreignKeys = $foreignKeys; $this->localKeys = $localKeys; $firstKey = is_array($foreignKeys[0]) ? $foreignKeys[0][1] : $foreignKeys[0]; parent::__construct($query, $farParent, $throughParents[0], $firstKey, $foreignKeys[1], $localKeys[0], $localKeys[1]); } /** * Set the base constraints on the relation query. * * @return void */ public function addConstraints() { parent::addConstraints(); if (static::$constraints) { if (is_array($this->foreignKeys[0])) { $column = $this->throughParent->qualifyColumn($this->foreignKeys[0][0]); $this->query->where($column, '=', $this->farParent->getMorphClass()); } } } /** * Set the join clause on the query. * * @param \Illuminate\Database\Eloquent\Builder|null $query * @return void */ protected function performJoin(Builder $query = null) { $query = $query ?: $this->query; $throughParents = array_reverse($this->throughParents); $foreignKeys = array_reverse($this->foreignKeys); $localKeys = array_reverse($this->localKeys); $segments = explode(' as ', $query->getQuery()->from); $alias = count($segments) > 1 ? $segments[1] : null; foreach ($throughParents as $i => $throughParent) { $predecessor = $i > 0 ? $throughParents[$i - 1] : $this->related; $localKey = $localKeys[$i]; if (is_array($localKey)) { $query->where($throughParent->qualifyColumn($localKey[0]), '=', $predecessor->getMorphClass()); $localKey = $localKey[1]; } $first = $throughParent->qualifyColumn($localKey); $foreignKey = $foreignKeys[$i]; if (is_array($foreignKey)) { $query->where($predecessor->qualifyColumn($foreignKey[0]), '=', $throughParent->getMorphClass()); $foreignKey = $foreignKey[1]; } $foreignKey = ($i === 0 && $alias ? $alias . '.' : '') . $foreignKey; $second = $predecessor->qualifyColumn($foreignKey); $query->join($throughParent->getTable(), $first, '=', $second); if ($this->throughParentInstanceSoftDeletes($throughParent)) { $query->whereNull($throughParent->getQualifiedDeletedAtColumn()); } } } /** * Determine whether a "through" parent instance of the relation uses Soft Deletes. * * @param \Illuminate\Database\Eloquent\Model $instance * @return bool */ public function throughParentInstanceSoftDeletes(Model $instance) { return in_array(SoftDeletes::class, class_uses_recursive($instance)); } /** * Set the constraints for an eager load of the relation. * * @param array $models * @return void */ public function addEagerConstraints(array $models) { parent::addEagerConstraints($models); if (is_array($this->foreignKeys[0])) { $column = $this->throughParent->qualifyColumn($this->foreignKeys[0][0]); $this->query->where($column, '=', $this->farParent->getMorphClass()); } } /** * Execute the query as a "select" statement. * * @param array $columns * @return \Illuminate\Database\Eloquent\Collection */ public function get($columns = ['*']) { $models = parent::get($columns); $this->hydrateIntermediateRelations($models->all()); return $models; } /** * Get a paginator for the "select" statement. * * @param int $perPage * @param array $columns * @param string $pageName * @param int $page * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator */ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $columns = $this->shouldSelect($columns); unset($columns[array_search($this->getQualifiedFirstKeyName(), $columns)]); $this->query->addSelect($columns); return tap($this->query->paginate($perPage, $columns, $pageName, $page), function ($paginator) { $this->hydrateIntermediateRelations($paginator->items()); }); } /** * Paginate the given query into a simple paginator. * * @param int $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return \Illuminate\Contracts\Pagination\Paginator */ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $columns = $this->shouldSelect($columns); unset($columns[array_search($this->getQualifiedFirstKeyName(), $columns)]); $this->query->addSelect($columns); return tap($this->query->simplePaginate($perPage, $columns, $pageName, $page), function ($paginator) { $this->hydrateIntermediateRelations($paginator->items()); }); } /** * Set the select clause for the relation query. * * @param array $columns * @return array */ protected function shouldSelect(array $columns = ['*']) { return array_merge(parent::shouldSelect($columns), $this->intermediateColumns()); } /** * Chunk the results of the query. * * @param int $count * @param callable $callback * @return bool */ public function chunk($count, callable $callback) { return $this->prepareQueryBuilder()->chunk($count, function ($results) use ($callback) { $this->hydrateIntermediateRelations($results->all()); return $callback($results); }); } /** * Hydrate the intermediate table relationship on the models. * * @param array $models * @return void */ protected function hydrateIntermediateRelations(array $models) { $intermediateTables = $this->intermediateTables; ksort($intermediateTables); foreach ($intermediateTables as $accessor => $intermediateTable) { $prefix = $this->prefix($accessor); if (Str::contains($accessor, '.')) { list($path, $key) = preg_split('/\.(?=[^.]*$)/', $accessor); } else { list($path, $key) = [null, $accessor]; } foreach ($models as $model) { $relation = $this->intermediateRelation($model, $intermediateTable, $prefix); data_get($model, $path)->setRelation($key, $relation); } } } /** * Get the intermediate relationship from the query. * * @param \Illuminate\Database\Eloquent\Model $model * @param array $intermediateTable * @param string $prefix * @return \Illuminate\Database\Eloquent\Model */ protected function intermediateRelation(Model $model, array $intermediateTable, $prefix) { $attributes = $this->intermediateAttributes($model, $prefix); $class = $intermediateTable['class']; if ($class === Pivot::class) { return $class::fromAttributes($model, $attributes, $intermediateTable['table'], true); } if (is_subclass_of($class, Pivot::class)) { return $class::fromRawAttributes($model, $attributes, $intermediateTable['table'], true); } return (new $class)->newFromBuilder($attributes); } /** * Get the intermediate attributes from a model. * * @param \Illuminate\Database\Eloquent\Model $model * @param string $prefix * @return array */ protected function intermediateAttributes(Model $model, $prefix) { $attributes = []; foreach ($model->getAttributes() as $key => $value) { if (strpos($key, $prefix) === 0) { $attributes[substr($key, strlen($prefix))] = $value; unset($model->$key); } } return $attributes; } /** * Add the constraints for a relationship 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 = ['*']) { $query = parent::getRelationExistenceQuery($query, $parentQuery, $columns); if (is_array($this->foreignKeys[0])) { $column = $this->throughParent->qualifyColumn($this->foreignKeys[0][0]); $query->where($column, '=', $this->farParent->getMorphClass()); } return $query; } /** * Add the constraints for a relationship query on the same table. * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) { $query->from($query->getModel()->getTable() . ' as ' . $hash = $this->getRelationCountHash()); $this->performJoin($query); $query->getModel()->setTable($hash); return $query->select($columns)->whereColumn( $parentQuery->getQuery()->from . '.' . $query->getModel()->getKeyName(), '=', $this->getQualifiedFirstKeyName() ); } /** * Set the columns on an intermediate table to retrieve. * * @param string $class * @param array $columns * @param string|null $accessor * @return $this */ public function withIntermediate($class, array $columns = ['*'], $accessor = null) { $table = (new $class)->getTable(); $accessor = $accessor ?: \Str::snake(class_basename($class)); return $this->withPivot($table, $columns, $class, $accessor); } /** * Set the columns on a pivot table to retrieve. * * @param string $table * @param array $columns * @param string $class * @param string|null $accessor * @return $this */ public function withPivot($table, array $columns = ['*'], $class = Pivot::class, $accessor = null) { if ($columns === ['*']) { $columns = $this->query->getConnection()->getSchemaBuilder()->getColumnListing($table); } $accessor = $accessor ?: $table; if (isset($this->intermediateTables[$accessor])) { $columns = array_merge($columns, $this->intermediateTables[$accessor]['columns']); } $this->intermediateTables[$accessor] = compact('table', 'columns', 'class'); return $this; } /** * Get the intermediate columns for the relation. * * @return array */ protected function intermediateColumns() { $columns = []; foreach ($this->intermediateTables as $accessor => $intermediateTable) { $prefix = $this->prefix($accessor); foreach ($intermediateTable['columns'] as $column) { $columns[] = $intermediateTable['table'] . '.' . $column . ' as ' . $prefix . $column; } } return array_unique($columns); } /** * Get the intermediate column alias prefix. * * @param string $accessor * @return string */ protected function prefix($accessor) { return '__' . $accessor . '__'; } }