Passed
Push — master ( 3263b5...c3fb84 )
by Jonas
15:03 queued 18s
created

IsJsonRelation::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 1
rs 10
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;
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\MariaDbGrammar;
13
use Staudenmeir\EloquentJsonRelations\Grammars\MySqlGrammar;
14
use Staudenmeir\EloquentJsonRelations\Grammars\PostgresGrammar;
15
use Staudenmeir\EloquentJsonRelations\Grammars\SQLiteGrammar;
16
use Staudenmeir\EloquentJsonRelations\Grammars\SqlServerGrammar;
17
18
trait IsJsonRelation
19
{
20
    /**
21
     * The base path of the foreign key.
22
     *
23
     * @var string
24
     */
25
    protected $path;
26
27
    /**
28
     * The optional object key of the foreign key.
29
     *
30
     * @var string
31
     */
32
    protected $key;
33
34
    /**
35
     * Hydrate the pivot relationship on the models.
36
     *
37 457
     * @param \Illuminate\Database\Eloquent\Collection $models
38
     * @param \Illuminate\Database\Eloquent\Model $parent
39 457
     * @param callable $callback
40
     * @return void
41 457
     */
42
    public function hydratePivotRelation(Collection $models, Model $parent, callable $callback)
43 457
    {
44 457
        foreach ($models as $i => $model) {
45
            $clone = clone $model;
46 457
47
            $models[$i] = $clone->setRelation(
48
                $this->getPivotAccessor(),
49
                $this->pivotRelation($clone, $parent, $callback)
50
            );
51
        }
52
    }
53
54
    /**
55
     * Get the pivot relationship from the query.
56
     *
57 99
     * @param \Illuminate\Database\Eloquent\Model $model
58
     * @param \Illuminate\Database\Eloquent\Model $parent
59 99
     * @param callable $callback
60 99
     * @return \Illuminate\Database\Eloquent\Model
61
     */
62 99
    protected function pivotRelation(Model $model, Model $parent, callable $callback)
63 99
    {
64 99
        $records = $callback($model, $parent);
65 99
66
        if ($records instanceof Arrayable) {
67
            $records = $records->toArray();
68
        }
69
70
        $attributes = $this->pivotAttributes($model, $parent, $records);
71
72
        return Pivot::fromAttributes($model, $attributes, null, true);
73
    }
74
75
    /**
76
     * Get the pivot attributes from a model.
77 99
     *
78
     * @param \Illuminate\Database\Eloquent\Model $model
79 99
     * @param \Illuminate\Database\Eloquent\Model $parent
80
     * @param array $records
81 99
     * @return array
82 12
     */
83
    abstract public function pivotAttributes(Model $model, Model $parent, array $records);
84
85 99
    /**
86
     * Execute the query and get the first related model.
87 99
     *
88
     * @param array $columns
89
     * @return mixed
90
     */
91
    public function first($columns = ['*'])
92
    {
93
        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

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