Passed
Push — master ( 39a2d7...bcd993 )
by Jonas
02:36
created

BelongsToJson::getForeignKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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\BelongsTo;
9
use Illuminate\Support\Arr;
10
11
class BelongsToJson extends BelongsTo
12
{
13
    use InteractsWithPivotRecords, IsJsonRelation;
14
15
    /**
16
     * Get the results of the relationship.
17
     *
18
     * @return mixed
19
     */
20 16
    public function getResults()
21
    {
22 16
        return ! empty($this->getForeignKeys())
23 14
            ? $this->get()
24 16
            : $this->related->newCollection();
25
    }
26
27
    /**
28
     * Set the base constraints on the relation query.
29
     *
30
     * @return void
31
     */
32 44
    public function addConstraints()
33
    {
34 44
        if (static::$constraints) {
35 28
            $table = $this->related->getTable();
36
37 28
            $this->query->whereIn($table.'.'.$this->ownerKey, $this->getForeignKeys());
38
        }
39 44
    }
40
41
    /**
42
     * Gather the keys from an array of related models.
43
     *
44
     * @param  array  $models
45
     * @return array
46
     */
47 10
    protected function getEagerModelKeys(array $models)
48
    {
49 10
        $keys = [];
50
51 10
        foreach ($models as $model) {
52 10
            $keys = array_merge($keys, (array) $model->{$this->foreignKey});
53
        }
54
55 10
        sort($keys);
56
57 10
        return array_values(array_unique($keys));
58
    }
59
60
    /**
61
     * Match the eagerly loaded results to their parents.
62
     *
63
     * @param  array   $models
64
     * @param  \Illuminate\Database\Eloquent\Collection  $results
65
     * @param  string  $relation
66
     * @return array
67
     */
68 10
    public function match(array $models, Collection $results, $relation)
69
    {
70 10
        $dictionary = $this->buildDictionary($results);
71
72 10
        foreach ($models as $model) {
73 10
            $matches = [];
74
75 10
            foreach ((array) $model->{$this->foreignKey} as $id) {
76 10
                if (isset($dictionary[$id])) {
77 10
                    $matches[] = $dictionary[$id];
78
                }
79
            }
80
81 10
            $model->setRelation($relation, $collection = $this->related->newCollection($matches));
82
83 10
            if ($this->key) {
84 6
                $this->hydratePivotRelation($collection, $model);
85
            }
86
        }
87
88 10
        return $models;
89
    }
90
91
    /**
92
     * Build model dictionary keyed by the relation's foreign key.
93
     *
94
     * @param  \Illuminate\Database\Eloquent\Collection  $results
95
     * @return array
96
     */
97 10
    protected function buildDictionary(Collection $results)
98
    {
99 10
        $dictionary = [];
100
101 10
        foreach ($results as $result) {
102 10
            $dictionary[$result->{$this->ownerKey}] = $result;
103
        }
104
105 10
        return $dictionary;
106
    }
107
108
    /**
109
     * Add the constraints for a relationship query.
110
     *
111
     * @param  \Illuminate\Database\Eloquent\Builder  $query
112
     * @param  \Illuminate\Database\Eloquent\Builder  $parentQuery
113
     * @param  array|mixed  $columns
114
     * @return \Illuminate\Database\Eloquent\Builder
115
     */
116 8
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
117
    {
118 8
        if ($parentQuery->getQuery()->from == $query->getQuery()->from) {
119 4
            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
120
        }
121
122 4
        $ownerKey = $this->relationExistenceQueryOwnerKey($query, $this->ownerKey);
123
124 4
        return $query->select($columns)->whereJsonContains(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->select($c...ection->raw($ownerKey)) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
125 4
            $this->getQualifiedPath(),
126 4
            $query->getQuery()->connection->raw($ownerKey)
127
        );
128
    }
129
130
    /**
131
     * Add the constraints for a relationship query on the same table.
132
     *
133
     * @param  \Illuminate\Database\Eloquent\Builder  $query
134
     * @param  \Illuminate\Database\Eloquent\Builder  $parentQuery
135
     * @param  array|mixed  $columns
136
     * @return \Illuminate\Database\Eloquent\Builder
137
     */
138 4
    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
139
    {
140 4
        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
141
142 4
        $query->getModel()->setTable($hash);
143
144 4
        $ownerKey = $this->relationExistenceQueryOwnerKey($query, $hash.'.'.$this->ownerKey);
145
146 4
        return $query->select($columns)->whereJsonContains(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->select($c...ection->raw($ownerKey)) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
147 4
            $this->getQualifiedPath(),
148 4
            $query->getQuery()->connection->raw($ownerKey)
149
        );
150
    }
151
152
    /**
153
     * Get the owner key for the relationship query.
154
     *
155
     * @param  \Illuminate\Database\Eloquent\Builder  $query
156
     * @param  string  $ownerKey
157
     * @return string
158
     */
159 8
    protected function relationExistenceQueryOwnerKey(Builder $query, $ownerKey)
160
    {
161 8
        if (! $this->key) {
162 4
            return $this->getJsonGrammar($query)->compileJsonArray($query->qualifyColumn($ownerKey));
163
        }
164
165 4
        $this->addBinding($this->key);
0 ignored issues
show
Bug introduced by
The method addBinding() does not exist on Staudenmeir\EloquentJson...Relations\BelongsToJson. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

165
        $this->/** @scrutinizer ignore-call */ 
166
               addBinding($this->key);
Loading history...
166
167 4
        return $this->getJsonGrammar($query)->compileJsonObject($query->qualifyColumn($ownerKey));
168
    }
169
170
    /**
171
     * Get the pivot attributes from a model.
172
     *
173
     * @param  \Illuminate\Database\Eloquent\Model  $model
174
     * @param  \Illuminate\Database\Eloquent\Model  $parent
175
     * @return array
176
     */
177 16
    protected function pivotAttributes(Model $model, Model $parent)
178
    {
179 16
        $record = collect($parent->{$this->path})
180 16
            ->where($this->key, $model->{$this->ownerKey})
181 16
            ->first();
182
183 16
        return Arr::except($record, $this->key);
184
    }
185
186
    /**
187
     * Get the foreign key values.
188
     *
189
     * @return array
190
     */
191 28
    public function getForeignKeys()
192
    {
193 28
        return (array) $this->child->{$this->foreignKey};
194
    }
195
}
196