Passed
Push — master ( 575ac1...7d6027 )
by Jonas
01:44
created

BelongsToJson::getResults()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
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 pivot attributes from a model.
17
     *
18
     * @param  \Illuminate\Database\Eloquent\Model  $model
19
     * @param  \Illuminate\Database\Eloquent\Model  $parent
20
     * @return array
21
     */
22
    protected function pivotAttributes(Model $model, Model $parent)
23
    {
24
        $record = collect($parent->{$this->path})
25
            ->where($this->key, $model->{$this->ownerKey})
26
            ->first();
27
28
        return ! is_null($record) ? Arr::except($record, $this->key) : [];
29
    }
30
31
    /**
32
     * Set the base constraints on the relation query.
33
     *
34
     * @return void
35
     */
36
    public function addConstraints()
37
    {
38
        if (static::$constraints) {
39
            $table = $this->related->getTable();
40
41
            $this->query->whereIn($table.'.'.$this->ownerKey, (array) $this->child->{$this->foreignKey});
42
        }
43
    }
44
45
    /**
46
     * Gather the keys from an array of related models.
47
     *
48
     * @param  array  $models
49
     * @return array
50
     */
51
    protected function getEagerModelKeys(array $models)
52
    {
53
        $keys = [];
54
55
        foreach ($models as $model) {
56
            $keys = array_merge($keys, (array) $model->{$this->foreignKey});
57
        }
58
59
        if (count($keys) === 0) {
60
            return [null];
61
        }
62
63
        sort($keys);
64
65
        return array_values(array_unique($keys));
66
    }
67
68
    /**
69
     * Match the eagerly loaded results to their parents.
70
     *
71
     * @param  array   $models
72
     * @param  \Illuminate\Database\Eloquent\Collection  $results
73
     * @param  string  $relation
74
     * @return array
75
     */
76
    public function match(array $models, Collection $results, $relation)
77
    {
78
        $dictionary = $this->buildDictionary($results);
79
80
        foreach ($models as $model) {
81
            $matches = [];
82
83
            foreach ((array) $model->{$this->foreignKey} as $id) {
84
                if (isset($dictionary[$id])) {
85
                    $matches[] = $dictionary[$id];
86
                }
87
            }
88
89
            $model->setRelation($relation, $collection = $this->related->newCollection($matches));
90
91
            if ($this->key) {
92
                $this->hydratePivotRelation($collection, $model);
93
            }
94
        }
95
96
        return $models;
97
    }
98
99
    /**
100
     * Build model dictionary keyed by the relation's foreign key.
101
     *
102
     * @param  \Illuminate\Database\Eloquent\Collection  $results
103
     * @return array
104
     */
105
    protected function buildDictionary(Collection $results)
106
    {
107
        $dictionary = [];
108
109
        foreach ($results as $result) {
110
            $dictionary[$result->{$this->ownerKey}] = $result;
111
        }
112
113
        return $dictionary;
114
    }
115
116
    /**
117
     * Add the constraints for a relationship query.
118
     *
119
     * @param  \Illuminate\Database\Eloquent\Builder  $query
120
     * @param  \Illuminate\Database\Eloquent\Builder  $parentQuery
121
     * @param  array|mixed  $columns
122
     * @return \Illuminate\Database\Eloquent\Builder
123
     */
124
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
125
    {
126
        if ($parentQuery->getQuery()->from == $query->getQuery()->from) {
127
            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
128
        }
129
130
        $ownerKey = $this->relationExistenceQueryOwnerKey($query, $this->ownerKey);
131
132
        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...
133
            $this->getQualifiedPath(),
134
            $query->getQuery()->connection->raw($ownerKey)
135
        );
136
    }
137
138
    /**
139
     * Add the constraints for a relationship query on the same table.
140
     *
141
     * @param  \Illuminate\Database\Eloquent\Builder  $query
142
     * @param  \Illuminate\Database\Eloquent\Builder  $parentQuery
143
     * @param  array|mixed  $columns
144
     * @return \Illuminate\Database\Eloquent\Builder
145
     */
146
    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
147
    {
148
        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
149
150
        $query->getModel()->setTable($hash);
151
152
        $ownerKey = $this->relationExistenceQueryOwnerKey($query, $hash.'.'.$this->ownerKey);
153
154
        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...
155
            $this->getQualifiedPath(),
156
            $query->getQuery()->connection->raw($ownerKey)
157
        );
158
    }
159
160
    /**
161
     * Get the owner key for the relationship query.
162
     *
163
     * @param  \Illuminate\Database\Eloquent\Builder  $query
164
     * @param  string  $ownerKey
165
     * @return string
166
     */
167
    protected function relationExistenceQueryOwnerKey(Builder $query, $ownerKey)
168
    {
169
        if (! $this->key) {
170
            return $this->getJsonGrammar($query)->compileJsonArray($query->qualifyColumn($ownerKey));
171
        }
172
173
        $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

173
        $this->/** @scrutinizer ignore-call */ 
174
               addBinding($this->key);
Loading history...
174
175
        return $this->getJsonGrammar($query)->compileJsonObject($query->qualifyColumn($ownerKey));
176
    }
177
}
178