Passed
Push — master ( 09af0a...9826c5 )
by Jonas
06:00
created

HasManyJson::getResults()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Staudenmeir\EloquentJsonRelations\Relations;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\HasMany;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Collection as BaseCollection;
11
12
class HasManyJson extends HasMany
13
{
14
    use IsJsonRelation;
15
16
    /**
17
     * Get the results of the relationship.
18
     *
19
     * @return mixed
20
     */
21 8
    public function getResults()
22
    {
23 8
        return !is_null($this->getParentKey())
24 5
            ? $this->get()
25 8
            : $this->related->newCollection();
26
    }
27
28
    /**
29
     * Execute the query as a "select" statement.
30
     *
31
     * @param array $columns
32
     * @return \Illuminate\Database\Eloquent\Collection
33
     */
34 17
    public function get($columns = ['*'])
35
    {
36 17
        $models = parent::get($columns);
37
38 17
        if ($this->key && !is_null($this->parent->{$this->localKey})) {
39 4
            $this->hydratePivotRelation($models, $this->parent);
40
        }
41
42 17
        return $models;
43
    }
44
45
    /**
46
     * Set the base constraints on the relation query.
47
     *
48
     * @return void
49
     */
50 36
    public function addConstraints()
51
    {
52 36
        if (static::$constraints) {
53 16
            $parentKey = $this->getParentKey();
54
55 16
            if ($this->key) {
56 7
                $parentKey = $this->parentKeyToArray($parentKey);
57
            }
58
59 16
            $this->query->whereJsonContains($this->path, $parentKey);
60
        }
61
    }
62
63
    /**
64
     * Set the constraints for an eager load of the relation.
65
     *
66
     * @param array $models
67
     * @return void
68
     */
69 10
    public function addEagerConstraints(array $models)
70
    {
71 10
        $parentKeys = $this->getKeys($models, $this->localKey);
72
73 10
        $this->query->where(function (Builder $query) use ($parentKeys) {
74 10
            foreach ($parentKeys as $parentKey) {
75 10
                if ($this->key) {
76 4
                    $parentKey = $this->parentKeyToArray($parentKey);
77
                }
78
79 10
                $query->orWhereJsonContains($this->path, $parentKey);
80
            }
81
        });
82
    }
83
84
    /**
85
     * Embed a parent key in a nested array.
86
     *
87
     * @param mixed $parentKey
88
     * @return array
89
     */
90 11
    protected function parentKeyToArray($parentKey)
91
    {
92 11
        $keys = explode('->', $this->key);
93
94 11
        foreach (array_reverse($keys) as $key) {
95 11
            $parentKey = [$key => $parentKey];
96
        }
97
98 11
        return [$parentKey];
99
    }
100
101
    /**
102
     * Match the eagerly loaded results to their many parents.
103
     *
104
     * @param array  $models
105
     * @param \Illuminate\Database\Eloquent\Collection $results
106
     * @param string $relation
107
     * @param string $type
108
     * @return array
109
     */
110 10
    protected function matchOneOrMany(array $models, Collection $results, $relation, $type)
111
    {
112 10
        $models = parent::matchOneOrMany(...func_get_args());
113
114 10
        if ($this->key) {
115 4
            foreach ($models as $model) {
116 4
                $this->hydratePivotRelation($model->$relation, $model);
117
            }
118
        }
119
120 10
        return $models;
121
    }
122
123
    /**
124
     * Build model dictionary keyed by the relation's foreign key.
125
     *
126
     * @param \Illuminate\Database\Eloquent\Collection $results
127
     * @return array
128
     */
129 10
    protected function buildDictionary(Collection $results)
130
    {
131 10
        $foreign = $this->getForeignKeyName();
132
133 10
        $dictionary = [];
134
135 10
        foreach ($results as $result) {
136 10
            foreach ($result->{$foreign} as $value) {
137 10
                $dictionary[$value][] = $result;
138
            }
139
        }
140
141 10
        return $dictionary;
142
    }
143
144
    /**
145
     * Set the foreign ID for creating a related model.
146
     *
147
     * @param \Illuminate\Database\Eloquent\Model $model
148
     * @return void
149
     */
150 6
    protected function setForeignAttributesForCreate(Model $model)
151
    {
152 6
        $foreignKey = explode('.', $this->foreignKey)[1];
153
154
        /** @var \Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson $relation */
155 6
        $relation = $model->belongsToJson(get_class($this->parent), $foreignKey, $this->localKey);
156
157 6
        $relation->attach($this->getParentKey());
158
    }
159
160
    /**
161
     * Add the constraints for a relationship query.
162
     *
163
     * @param \Illuminate\Database\Eloquent\Builder $query
164
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
165
     * @param array|mixed $columns
166
     * @return \Illuminate\Database\Eloquent\Builder
167
     */
168 10
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
169
    {
170 10
        if ($query->getQuery()->from == $parentQuery->getQuery()->from) {
171 5
            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
172
        }
173
174 5
        $parentKey = $this->relationExistenceQueryParentKey($query);
175
176 5
        return $query->select($columns)->whereJsonContains(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->select($c...ction->raw($parentKey)) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
177 5
            $this->getQualifiedPath(),
178 5
            $query->getQuery()->connection->raw($parentKey)
179
        );
180
    }
181
182
    /**
183
     * Add the constraints for a relationship query on the same table.
184
     *
185
     * @param \Illuminate\Database\Eloquent\Builder $query
186
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
187
     * @param array|mixed $columns
188
     * @return \Illuminate\Database\Eloquent\Builder
189
     */
190 5
    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
191
    {
192 5
        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
193
194 5
        $query->getModel()->setTable($hash);
195
196 5
        $parentKey = $this->relationExistenceQueryParentKey($query);
197
198 5
        return $query->select($columns)->whereJsonContains(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->select($c...ction->raw($parentKey)) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
199 5
            $hash.'.'.$this->getPathName(),
200 5
            $query->getQuery()->connection->raw($parentKey)
201
        );
202
    }
203
204
    /**
205
     * Get the parent key for the relationship query.
206
     *
207
     * @param \Illuminate\Database\Eloquent\Builder $query
208
     * @return string
209
     */
210 10
    protected function relationExistenceQueryParentKey(Builder $query)
211
    {
212 10
        $parentKey = $this->getQualifiedParentKeyName();
213
214 10
        if (!$this->key) {
215 6
            return $this->getJsonGrammar($query)->compileJsonArray($parentKey);
216
        }
217
218 4
        $query->addBinding($keys = explode('->', $this->key));
219
220 4
        return $this->getJsonGrammar($query)->compileJsonObject($parentKey, count($keys));
221
    }
222
223
    /**
224
     * Get the pivot attributes from a model.
225
     *
226
     * @param \Illuminate\Database\Eloquent\Model $model
227
     * @param \Illuminate\Database\Eloquent\Model $parent
228
     * @return array
229
     */
230 8
    protected function pivotAttributes(Model $model, Model $parent)
231
    {
232 8
        $key = str_replace('->', '.', $this->key);
233
234 8
        $record = (new BaseCollection($model->{$this->getPathName()}))
235 8
            ->filter(function ($value) use ($key, $parent) {
236 8
                return Arr::get($value, $key) == $parent->{$this->localKey};
237 8
            })->first();
238
239 8
        return Arr::except($record, $key);
240
    }
241
242
    /**
243
     * Get the plain path name.
244
     *
245
     * @return string
246
     */
247 13
    public function getPathName()
248
    {
249 13
        return last(explode('.', $this->path));
250
    }
251
}
252