1 | <?php |
||
2 | |||
3 | namespace Staudenmeir\EloquentHasManyDeep\Eloquent\Relations\ThirdParty\LaravelHasManyMerged; |
||
4 | |||
5 | use Illuminate\Database\Eloquent\Builder; |
||
6 | use Illuminate\Database\Eloquent\Collection; |
||
7 | use Illuminate\Database\Query\JoinClause; |
||
8 | use Korridor\LaravelHasManyMerged\HasManyMerged as Base; |
||
9 | use Staudenmeir\EloquentHasManyDeepContracts\Interfaces\ConcatenableRelation; |
||
10 | |||
11 | /** |
||
12 | * @copyright Based on package by Constantin Graf (korridor): https://github.com/korridor/laravel-has-many-merged |
||
13 | */ |
||
14 | class HasManyMerged extends Base implements ConcatenableRelation |
||
15 | { |
||
16 | /** |
||
17 | * Append the relation's through parents, foreign and local keys to a deep relationship. |
||
18 | * |
||
19 | * @param \Illuminate\Database\Eloquent\Model[] $through |
||
20 | * @param array $foreignKeys |
||
21 | * @param array $localKeys |
||
22 | * @param int $position |
||
23 | * @return array |
||
24 | */ |
||
25 | 30 | public function appendToDeepRelationship(array $through, array $foreignKeys, array $localKeys, int $position): array |
|
26 | { |
||
27 | 30 | if ($position === 0) { |
|
28 | 14 | $foreignKeys[] = function (Builder $query, Builder $parentQuery = null) { |
|
29 | 10 | if ($parentQuery) { |
|
30 | 2 | $this->getRelationExistenceQuery($this->query, $parentQuery); |
|
31 | } |
||
32 | |||
33 | 10 | $query->mergeConstraintsFrom($this->query); |
|
34 | 14 | }; |
|
35 | |||
36 | 14 | $localKeys[] = $this->localKey; |
|
37 | } else { |
||
38 | 16 | $foreignKeys[] = function (Builder $query, JoinClause $join) { |
|
39 | 16 | $join->on( |
|
40 | 16 | function (JoinClause $join) { |
|
41 | 16 | foreach ($this->foreignKeys as $foreignKey) { |
|
42 | 16 | $join->orOn($foreignKey, '=', $this->getQualifiedParentKeyName()); |
|
43 | } |
||
44 | 16 | } |
|
45 | 16 | ); |
|
46 | 16 | }; |
|
47 | |||
48 | 16 | $localKeys[] = null; |
|
49 | } |
||
50 | |||
51 | 30 | return [$through, $foreignKeys, $localKeys]; |
|
52 | } |
||
53 | |||
54 | /** |
||
55 | * Get the custom through key for an eager load of the relation. |
||
56 | * |
||
57 | * @param string $alias |
||
58 | * @return array |
||
59 | */ |
||
60 | 12 | public function getThroughKeyForDeepRelationships(string $alias): array |
|
61 | { |
||
62 | 12 | $columns = []; |
|
63 | |||
64 | 12 | foreach ($this->foreignKeys as $i => $foreignKey) { |
|
65 | 12 | $columns[] = "$foreignKey as $alias" . ($i > 0 ? "_$i" : ''); |
|
66 | } |
||
67 | |||
68 | 12 | return $columns; |
|
69 | } |
||
70 | |||
71 | /** |
||
72 | * Set the constraints for an eager load of the deep relation. |
||
73 | * |
||
74 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
75 | * @param array $models |
||
76 | * @return void |
||
77 | */ |
||
78 | 4 | public function addEagerConstraintsToDeepRelationship(Builder $query, array $models): void |
|
79 | { |
||
80 | 4 | $this->addEagerConstraints($models); |
|
81 | |||
82 | 4 | $query->mergeConstraintsFrom($this->query); |
|
83 | } |
||
84 | |||
85 | /** |
||
86 | * Match the eagerly loaded results for a deep relationship to their parents. |
||
87 | * |
||
88 | * @param array $models |
||
89 | * @param \Illuminate\Database\Eloquent\Collection $results |
||
90 | * @param string $relation |
||
91 | * @return array |
||
92 | */ |
||
93 | 4 | public function matchResultsForDeepRelationship(array $models, Collection $results, string $relation): array |
|
94 | { |
||
95 | 4 | $dictionary = $this->buildDictionaryForDeepRelationship($results); |
|
96 | |||
97 | 4 | foreach ($models as $model) { |
|
98 | 4 | if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) { |
|
99 | 4 | $model->setRelation( |
|
100 | 4 | $relation, |
|
101 | 4 | $this->getRelated()->newCollection($dictionary[$key])->unique($this->getRelated()->getKeyName()) |
|
102 | 4 | ); |
|
103 | } |
||
104 | } |
||
105 | |||
106 | 4 | return $models; |
|
107 | } |
||
108 | |||
109 | /** |
||
110 | * Build the model dictionary for a deep relation. |
||
111 | * |
||
112 | * @param \Illuminate\Database\Eloquent\Collection $results |
||
113 | * @return array |
||
114 | */ |
||
115 | 4 | protected function buildDictionaryForDeepRelationship(Collection $results): array |
|
116 | { |
||
117 | 4 | $dictionary = []; |
|
118 | |||
119 | 4 | $foreignKeyNames = array_map( |
|
120 | 4 | fn ($i) => 'laravel_through_key' . ($i > 0 ? "_$i" : ''), |
|
121 | 4 | range(0, count($this->foreignKeys) - 1) |
|
122 | 4 | ); |
|
123 | |||
124 | 4 | foreach ($results as $result) { |
|
125 | 4 | foreach ($foreignKeyNames as $foreignKeyName) { |
|
126 | 4 | $foreignKeyValue = $result->{$foreignKeyName}; |
|
127 | 4 | if (!isset($dictionary[$foreignKeyValue])) { |
|
128 | 4 | $dictionary[$foreignKeyValue] = []; |
|
129 | } |
||
130 | |||
131 | 4 | $dictionary[$foreignKeyValue][] = $result; |
|
132 | } |
||
133 | } |
||
134 | |||
135 | 4 | return $dictionary; |
|
136 | } |
||
137 | |||
138 | /** |
||
139 | * Create a new instance of the relation from a base relation instance. |
||
140 | * |
||
141 | * @param \Korridor\LaravelHasManyMerged\HasManyMerged $relation |
||
142 | * @return static |
||
143 | */ |
||
144 | 30 | public static function fromBaseRelation(Base $relation): static |
|
145 | { |
||
146 | 30 | return new static( |
|
147 | 30 | $relation->getQuery(), |
|
148 | 30 | $relation->getParent(), |
|
149 | 30 | $relation->getQualifiedForeignKeyNames(), |
|
150 | 30 | (fn () => $this->localKey)->call($relation) |
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
151 | 30 | ); |
|
152 | } |
||
153 | } |
||
154 |