Passed
Pull Request — master (#57)
by
unknown
10:11
created

BelongsToJson::getArrayableItems()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 9
c 0
b 0
f 0
nc 5
nop 1
dl 0
loc 13
ccs 0
cts 0
cp 0
crap 30
rs 9.6111
1
<?php
2
3
namespace Staudenmeir\EloquentJsonRelations\Relations;
4
5
use Illuminate\Contracts\Support\Arrayable;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Collection;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Database\Eloquent\Relations\BelongsTo;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Enumerable;
12
13
class BelongsToJson extends BelongsTo
14
{
15
    use InteractsWithPivotRecords, IsJsonRelation;
16
17
    /**
18
     * Get the results of the relationship.
19
     *
20 24
     * @return mixed
21
     */
22 24
    public function getResults()
23 21
    {
24 24
        return !empty($this->getForeignKeys())
25
            ? $this->get()
26
            : $this->related->newCollection();
27
    }
28
29
    /**
30
     * Set the base constraints on the relation query.
31
     *
32 70
     * @return void
33
     */
34 70
    public function addConstraints()
35 48
    {
36
        if (static::$constraints) {
37 48
            $table = $this->related->getTable();
38
39 70
            $this->query->whereIn($table.'.'.$this->ownerKey, $this->getForeignKeys());
40
        }
41
    }
42
43
    /**
44
     * Gather the keys from an array of related models.
45
     *
46
     * @param array $models
47 15
     * @return array
48
     */
49 15
    protected function getEagerModelKeys(array $models)
50
    {
51 15
        $keys = [];
52 15
53
        foreach ($models as $model) {
54
            $keys = array_merge($keys, $this->getForeignKeys($model));
55 15
        }
56
57 15
        sort($keys);
58
59
        return array_values(array_unique($keys));
60
    }
61
62
    /**
63
     * Match the eagerly loaded results to their parents.
64
     *
65
     * @param array  $models
66
     * @param \Illuminate\Database\Eloquent\Collection $results
67
     * @param string $relation
68 15
     * @return array
69
     */
70 15
    public function match(array $models, Collection $results, $relation)
71
    {
72 15
        $dictionary = $this->buildDictionary($results);
73 15
74
        foreach ($models as $model) {
75 15
            $matches = [];
76 15
77 15
            foreach ($this->getForeignKeys($model) as $id) {
78
                if (isset($dictionary[$id])) {
79
                    $matches[] = $dictionary[$id];
80
                }
81 15
            }
82
83 15
            $model->setRelation($relation, $collection = $this->related->newCollection($matches));
84 9
85
            if ($this->key) {
86
                $this->hydratePivotRelation($collection, $model);
87
            }
88 15
        }
89
90
        return $models;
91
    }
92
93
    /**
94
     * Build model dictionary keyed by the relation's foreign key.
95
     *
96
     * @param \Illuminate\Database\Eloquent\Collection $results
97 15
     * @return array
98
     */
99 15
    protected function buildDictionary(Collection $results)
100
    {
101 15
        $dictionary = [];
102 15
103
        foreach ($results as $result) {
104
            $dictionary[$result->{$this->ownerKey}] = $result;
105 15
        }
106
107
        return $dictionary;
108
    }
109
110
    /**
111
     * Add the constraints for a relationship query.
112
     *
113
     * @param \Illuminate\Database\Eloquent\Builder $query
114
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
115
     * @param array|mixed $columns
116 10
     * @return \Illuminate\Database\Eloquent\Builder
117
     */
118 10
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
119 5
    {
120
        if ($parentQuery->getQuery()->from == $query->getQuery()->from) {
121
            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
122 5
        }
123
124 5
        $ownerKey = $this->relationExistenceQueryOwnerKey($query, $this->ownerKey);
125 5
126 5
        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...
127
            $this->getQualifiedPath(),
128
            $query->getQuery()->connection->raw($ownerKey)
129
        );
130
    }
131
132
    /**
133
     * Add the constraints for a relationship query on the same table.
134
     *
135
     * @param \Illuminate\Database\Eloquent\Builder $query
136
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
137
     * @param array|mixed $columns
138 5
     * @return \Illuminate\Database\Eloquent\Builder
139
     */
140 5
    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
141
    {
142 5
        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
143
144 5
        $query->getModel()->setTable($hash);
145
146 5
        $ownerKey = $this->relationExistenceQueryOwnerKey($query, $hash.'.'.$this->ownerKey);
147 5
148 5
        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...
149
            $this->getQualifiedPath(),
150
            $query->getQuery()->connection->raw($ownerKey)
151
        );
152
    }
153
154
    /**
155
     * Get the owner key for the relationship query.
156
     *
157
     * @param \Illuminate\Database\Eloquent\Builder $query
158
     * @param string $ownerKey
159 10
     * @return string
160
     */
161 10
    protected function relationExistenceQueryOwnerKey(Builder $query, $ownerKey)
162
    {
163 10
        $ownerKey = $query->qualifyColumn($ownerKey);
164 6
165
        if (!$this->key) {
166
            return $this->getJsonGrammar($query)->compileJsonArray($ownerKey);
167 4
        }
168
169 4
        $query->addBinding($keys = explode('->', $this->key));
170
171
        return $this->getJsonGrammar($query)->compileJsonObject($ownerKey, count($keys));
172
    }
173
174
    /**
175
     * Get the pivot attributes from a model.
176
     *
177
     * @param \Illuminate\Database\Eloquent\Model $model
178
     * @param \Illuminate\Database\Eloquent\Model $parent
179 27
     * @return array
180
     */
181 27
    protected function pivotAttributes(Model $model, Model $parent)
182
    {
183 27
        $key = str_replace('->', '.', $this->key);
184 27
185 27
        $record = collect($parent->{$this->path})
186 27
            ->filter(function ($value) use ($key, $model) {
187
                return Arr::get($value, $key) == $model->{$this->ownerKey};
188 27
            })->first();
189
190
        return Arr::except($record, $key);
191
    }
192
193
    /**
194
     * Get the foreign key values.
195
     *
196
     * @param \Illuminate\Database\Eloquent\Model|null $model
197 60
     * @return array
198
     */
199 60
    public function getForeignKeys(Model $model = null)
200
    {
201 60
        $model = $model ?: $this->child;
202
203 60
        $keys = $this->getArrayableItems($model->{$this->foreignKey});
204 57
205 60
        return array_filter($keys, function ($key) {
206
            return $key !== null;
207
        });
208
    }
209
210
    /**
211
     * Results array of items from Collection or Arrayable.
212
     *
213
     * @param  mixed  $items
214
     * @return array
215
     */
216
    protected function getArrayableItems($items)
217
    {
218
        if (is_array($items)) {
219
            return $items;
220
        } elseif ($items instanceof Enumerable) {
221
            return $items->all();
222
        } elseif ($items instanceof Arrayable) {
223
            return $items->toArray();
224
        } elseif ($items instanceof Traversable) {
0 ignored issues
show
Bug introduced by
The type Staudenmeir\EloquentJson...s\Relations\Traversable was not found. Did you mean Traversable? If so, make sure to prefix the type with \.
Loading history...
225
            return iterator_to_array($items);
226
        }
227
228
        return (array) $items;
229
    }
230
}
231