Passed
Push — master ( a4b3c7...383d4c )
by Jonas
03:04
created

IsJsonRelation::whereJsonContainsOrMemberOf()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 5
nop 5
dl 0
loc 20
ccs 11
cts 11
cp 1
crap 4
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace Staudenmeir\EloquentJsonRelations\Relations\Traits;
4
5
use Illuminate\Contracts\Database\Query\Builder;
6
use Illuminate\Contracts\Support\Arrayable;
7
use Illuminate\Database\Eloquent\Collection;
0 ignored issues
show
Bug introduced by
The type Illuminate\Database\Eloquent\Collection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Database\Eloquent\Relations\Pivot;
10
use RuntimeException;
11
use Staudenmeir\EloquentJsonRelations\Grammars\JsonGrammar;
12
use Staudenmeir\EloquentJsonRelations\Grammars\MySqlGrammar;
13
use Staudenmeir\EloquentJsonRelations\Grammars\PostgresGrammar;
14
use Staudenmeir\EloquentJsonRelations\Grammars\SqlServerGrammar;
15
16
trait IsJsonRelation
17
{
18
    /**
19
     * The base path of the foreign key.
20
     *
21
     * @var string
22
     */
23
    protected $path;
24
25
    /**
26
     * The optional object key of the foreign key.
27
     *
28
     * @var string
29
     */
30
    protected $key;
31
32
    /**
33
     * Create a new JSON relationship instance.
34
     *
35
     * @return void
36
     */
37 436
    public function __construct()
38
    {
39 436
        $args = func_get_args();
40
41 436
        $foreignKey = explode('[]->', $args[2]);
42
43 436
        $this->path = $foreignKey[0];
44 436
        $this->key = $foreignKey[1] ?? null;
45
46 436
        parent::__construct(...$args);
47
    }
48
49
    /**
50
     * Hydrate the pivot relationship on the models.
51
     *
52
     * @param \Illuminate\Database\Eloquent\Collection $models
53
     * @param \Illuminate\Database\Eloquent\Model $parent
54
     * @param callable $callback
55
     * @return void
56
     */
57 99
    public function hydratePivotRelation(Collection $models, Model $parent, callable $callback)
58
    {
59 99
        foreach ($models as $i => $model) {
60 99
            $clone = clone $model;
61
62 99
            $models[$i] = $clone->setRelation(
63 99
                $this->getPivotAccessor(),
64 99
                $this->pivotRelation($clone, $parent, $callback)
65 99
            );
66
        }
67
    }
68
69
    /**
70
     * Get the pivot relationship from the query.
71
     *
72
     * @param \Illuminate\Database\Eloquent\Model $model
73
     * @param \Illuminate\Database\Eloquent\Model $parent
74
     * @param callable $callback
75
     * @return \Illuminate\Database\Eloquent\Model
76
     */
77 99
    protected function pivotRelation(Model $model, Model $parent, callable $callback)
78
    {
79 99
        $records = $callback($model, $parent);
80
81 99
        if ($records instanceof Arrayable) {
82 12
            $records = $records->toArray();
83
        }
84
85 99
        $attributes = $this->pivotAttributes($model, $parent, $records);
86
87 99
        return Pivot::fromAttributes($model, $attributes, null, true);
88
    }
89
90
    /**
91
     * Get the pivot attributes from a model.
92
     *
93
     * @param \Illuminate\Database\Eloquent\Model $model
94
     * @param \Illuminate\Database\Eloquent\Model $parent
95
     * @param array $records
96
     * @return array
97
     */
98
    abstract public function pivotAttributes(Model $model, Model $parent, array $records);
99
100
    /**
101
     * Execute the query and get the first related model.
102
     *
103
     * @param array $columns
104
     * @return mixed
105
     */
106 7
    public function first($columns = ['*'])
107
    {
108 7
        return $this->take(1)->get($columns)->first();
0 ignored issues
show
Bug introduced by
It seems like take() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

108
        return $this->/** @scrutinizer ignore-call */ take(1)->get($columns)->first();
Loading history...
109
    }
110
111
    /**
112
     * Get the fully qualified path of the relationship.
113
     *
114
     * @return string
115
     */
116 165
    public function getQualifiedPath()
117
    {
118 165
        return $this->parent->qualifyColumn($this->path);
119
    }
120
121
    /**
122
     * Add a “where JSON contains” or "member of" clause to the query.
123
     *
124
     * @param \Illuminate\Contracts\Database\Query\Builder $query
125
     * @param string $column
126
     * @param mixed $value
127
     * @param callable|null $objectValueCallback
128
     * @param string $boolean
129
     * @return void
130
     */
131 268
    protected function whereJsonContainsOrMemberOf(
132
        Builder $query,
133
        string $column,
134
        mixed $value,
135
        callable $objectValueCallback = null,
136
        string $boolean = 'and'
137
    ): void {
138 268
        $grammar = $this->getJsonGrammar($query);
139 268
        $connection = $query->getConnection();
140
141 268
        if ($grammar->supportsMemberOf($connection)) {
142 76
            $query->whereRaw(
143 76
                $grammar->compileMemberOf($column, $this->key, $value),
144 76
                $grammar->prepareBindingsForMemberOf($value),
145 76
                $boolean
146 76
            );
147
        } else {
148 192
            $value = $this->key && $objectValueCallback ? $objectValueCallback($value) : $value;
149
150 192
            $query->whereJsonContains($column, $value, $boolean);
151
        }
152
    }
153
154
    /**
155
     * Get the JSON grammar.
156
     *
157
     * @param \Illuminate\Contracts\Database\Query\Builder $query
158
     * @return \Staudenmeir\EloquentJsonRelations\Grammars\JsonGrammar
159
     */
160 268
    protected function getJsonGrammar(Builder $query): JsonGrammar
161
    {
162 268
        $driver = $query->getConnection()->getDriverName();
163
164
        switch ($driver) {
165 268
            case 'mysql':
166 152
                return $query->getConnection()->withTablePrefix(new MySqlGrammar());
167 116
            case 'pgsql':
168 76
                return $query->getConnection()->withTablePrefix(new PostgresGrammar());
169 40
            case 'sqlsrv':
170 40
                return $query->getConnection()->withTablePrefix(new SqlServerGrammar());
171
        }
172
173
        throw new RuntimeException('This database is not supported.'); // @codeCoverageIgnore
174
    }
175
176
    /**
177
     * Get the name of the pivot accessor for this relationship.
178
     *
179
     * @return string
180
     */
181 99
    public function getPivotAccessor(): string
182
    {
183 99
        return 'pivot';
184
    }
185
186
    /**
187
     * Get the base path of the foreign key.
188
     *
189
     * @return string
190
     */
191 9
    public function getForeignKeyPath(): string
192
    {
193 9
        return $this->path;
194
    }
195
}
196