Passed
Branch master (39a2d7)
by Jonas
01:38
created

HasManyJson   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 52
dl 0
loc 201
ccs 64
cts 64
cp 1
rs 10
c 0
b 0
f 0
wmc 22

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getPathName() 0 3 1
A addEagerConstraints() 0 11 3
A getRelationExistenceQueryForSelfRelation() 0 11 1
A setForeignAttributesForCreate() 0 8 1
A buildDictionary() 0 13 3
A relationExistenceQueryParentKey() 0 11 2
A matchOneOrMany() 0 11 3
A getRelationExistenceQuery() 0 11 2
A addConstraints() 0 10 3
A getResults() 0 5 2
A pivotAttributes() 0 7 1
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
11
class HasManyJson extends HasMany
12
{
13
    use IsJsonRelation;
14
15
    /**
16
     * Get the results of the relationship.
17
     *
18
     * @return mixed
19
     */
20 6
    public function getResults()
21
    {
22 6
        return ! is_null($this->getParentKey())
23 4
            ? $this->get()
24 6
            : $this->related->newCollection();
25
    }
26
27
    /**
28
     * Set the base constraints on the relation query.
29
     *
30
     * @return void
31
     */
32 26
    public function addConstraints()
33
    {
34 26
        if (static::$constraints) {
35 10
            $parentKey = $this->getParentKey();
36
37 10
            if ($this->key) {
38 4
                $parentKey = [[$this->key => $parentKey]];
39
            }
40
41 10
            $this->query->whereJsonContains($this->path, $parentKey);
42
        }
43 26
    }
44
45
    /**
46
     * Set the constraints for an eager load of the relation.
47
     *
48
     * @param  array  $models
49
     * @return void
50
     */
51 8
    public function addEagerConstraints(array $models)
52
    {
53 8
        $keys = $this->getKeys($models, $this->localKey);
54
55
        $this->query->where(function (Builder $query) use ($keys) {
56 8
            foreach ($keys as $key) {
57 8
                if ($this->key) {
58 4
                    $key = [[$this->key => $key]];
59
                }
60
61 8
                $query->orWhereJsonContains($this->path, $key);
62
            }
63 8
        });
64 8
    }
65
66
    /**
67
     * Match the eagerly loaded results to their many parents.
68
     *
69
     * @param  array   $models
70
     * @param  \Illuminate\Database\Eloquent\Collection  $results
71
     * @param  string  $relation
72
     * @param  string  $type
73
     * @return array
74
     */
75 8
    protected function matchOneOrMany(array $models, Collection $results, $relation, $type)
76
    {
77 8
        $models = parent::matchOneOrMany(...func_get_args());
78
79 8
        if ($this->key) {
80 4
            foreach ($models as $model) {
81 4
                $this->hydratePivotRelation($model->$relation, $model);
82
            }
83
        }
84
85 8
        return $models;
86
    }
87
88
    /**
89
     * Build model dictionary keyed by the relation's foreign key.
90
     *
91
     * @param  \Illuminate\Database\Eloquent\Collection  $results
92
     * @return array
93
     */
94 8
    protected function buildDictionary(Collection $results)
95
    {
96 8
        $foreign = $this->getForeignKeyName();
97
98 8
        $dictionary = [];
99
100 8
        foreach ($results as $result) {
101 8
            foreach ($result->{$foreign} as $value) {
102 8
                $dictionary[$value][] = $result;
103
            }
104
        }
105
106 8
        return $dictionary;
107
    }
108
109
    /**
110
     * Set the foreign ID for creating a related model.
111
     *
112
     * @param  \Illuminate\Database\Eloquent\Model  $model
113
     * @return void
114
     */
115 4
    protected function setForeignAttributesForCreate(Model $model)
116
    {
117 4
        $foreignKey = explode('.', $this->foreignKey)[1];
118
119
        /** @var \Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson $relation */
120 4
        $relation = $model->belongsToJson(get_class($this->parent), $foreignKey, $this->localKey);
121
122 4
        $relation->attach($this->getParentKey());
123 4
    }
124
125
    /**
126
     * Add the constraints for a relationship query.
127
     *
128
     * @param  \Illuminate\Database\Eloquent\Builder  $query
129
     * @param  \Illuminate\Database\Eloquent\Builder  $parentQuery
130
     * @param  array|mixed  $columns
131
     * @return \Illuminate\Database\Eloquent\Builder
132
     */
133 8
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
134
    {
135 8
        if ($query->getQuery()->from == $parentQuery->getQuery()->from) {
136 4
            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
137
        }
138
139 4
        $parentKey = $this->relationExistenceQueryParentKey($query);
140
141 4
        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...
142 4
            $this->getQualifiedPath(),
143 4
            $query->getQuery()->connection->raw($parentKey)
144
        );
145
    }
146
147
    /**
148
     * Add the constraints for a relationship query on the same table.
149
     *
150
     * @param  \Illuminate\Database\Eloquent\Builder  $query
151
     * @param  \Illuminate\Database\Eloquent\Builder  $parentQuery
152
     * @param  array|mixed  $columns
153
     * @return \Illuminate\Database\Eloquent\Builder
154
     */
155 4
    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
156
    {
157 4
        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
158
159 4
        $query->getModel()->setTable($hash);
160
161 4
        $parentKey = $this->relationExistenceQueryParentKey($query);
162
163 4
        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...
164 4
            $hash.'.'.$this->getPathName(),
165 4
            $query->getQuery()->connection->raw($parentKey)
166
        );
167
    }
168
169
    /**
170
     * Get the parent key for the relationship query.
171
     *
172
     * @param  \Illuminate\Database\Eloquent\Builder  $query
173
     * @return string
174
     */
175 8
    protected function relationExistenceQueryParentKey(Builder $query)
176
    {
177 8
        $parentKey = $this->getQualifiedParentKeyName();
178
179 8
        if (! $this->key) {
180 4
            return $this->getJsonGrammar($query)->compileJsonArray($query->qualifyColumn($parentKey));
181
        }
182
183 4
        $this->query->addBinding($this->key);
184
185 4
        return $this->getJsonGrammar($query)->compileJsonObject($query->qualifyColumn($parentKey));
186
    }
187
188
    /**
189
     * Get the pivot attributes from a model.
190
     *
191
     * @param  \Illuminate\Database\Eloquent\Model  $model
192
     * @param  \Illuminate\Database\Eloquent\Model  $parent
193
     * @return array
194
     */
195 6
    protected function pivotAttributes(Model $model, Model $parent)
196
    {
197 6
        $record = collect($model->{$this->getPathName()})
198 6
            ->where($this->key, $parent->{$this->localKey})
199 6
            ->first();
200
201 6
        return Arr::except($record, $this->key);
202
    }
203
204
    /**
205
     * Get the plain path name.
206
     *
207
     * @return string
208
     */
209 10
    public function getPathName()
210
    {
211 10
        return last(explode('.', $this->path));
212
    }
213
}
214