Passed
Push — refactor/improve-static-analys... ( bb4224...d678be )
by
unknown
07:03
created

BuildsUpdates::update()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 13
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent\Query\Concerns;
6
7
use Illuminate\Database\Query\Expression;
8
use Illuminate\Support\Arr;
9
use InvalidArgumentException;
10
use LaravelFreelancerNL\Aranguent\Query\Grammar;
11
use LaravelFreelancerNL\FluentAQL\Exceptions\BindException;
12
13
/**
14
 * @method applyBeforeQueryCallbacks()
15
 */
16
trait BuildsUpdates
17
{
18
    protected function prepareValuesForUpdate(array $values)
19
    {
20
        foreach($values as $key => $value) {
21
            if ($value instanceof Expression) {
22
                $values[$key] = $value->getValue($this->grammar);
23
24
                continue;
25
            }
26
27
            if (is_array($value)) {
28
                $values[$key] = $this->prepareValuesForUpdate($value);
29
                continue;
30
            }
31
32
            $values[$key]  = $this->bindValue($value, 'update');
0 ignored issues
show
Bug introduced by
It seems like bindValue() 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

32
            /** @scrutinizer ignore-call */ 
33
            $values[$key]  = $this->bindValue($value, 'update');
Loading history...
33
        }
34
35
        return $values;
36
    }
37
38
    /**
39
     * Update records in the database.
40
     *
41
     * @param  array  $values
42
     * @return int
43
     */
44
    public function update(array $values)
45
    {
46
        assert($this->grammar instanceof Grammar);
47
48
        $this->applyBeforeQueryCallbacks();
49
50
        $values = Arr::undot($this->grammar->convertJsonFields($values));
51
52
        $values = $this->prepareValuesForUpdate($values);
53
54
        $aql = $this->grammar->compileUpdate($this, $values);
0 ignored issues
show
Bug introduced by
$this of type LaravelFreelancerNL\Aran...\Concerns\BuildsUpdates is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of LaravelFreelancerNL\Aran...rammar::compileUpdate(). ( Ignorable by Annotation )

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

54
        $aql = $this->grammar->compileUpdate(/** @scrutinizer ignore-type */ $this, $values);
Loading history...
55
56
        return $this->connection->update($aql, $this->getBindings());
0 ignored issues
show
Bug introduced by
It seems like getBindings() 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

56
        return $this->connection->update($aql, $this->/** @scrutinizer ignore-call */ getBindings());
Loading history...
57
    }
58
59
    /**
60
     * Insert or update a record matching the attributes, and fill it with values.
61
     *
62
     * @param array $attributes
63
     * @param array $values
64
     * @return bool
65
     * @throws BindException
66
     */
67
    public function updateOrInsert(array $attributes, array $values = [])
68
    {
69
        if (!$this->where($attributes)->exists()) {
0 ignored issues
show
Bug introduced by
It seems like where() 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

69
        if (!$this->/** @scrutinizer ignore-call */ where($attributes)->exists()) {
Loading history...
70
            $this->bindings['where'] = [];
0 ignored issues
show
Bug Best Practice introduced by
The property bindings does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
71
            return $this->insert(array_merge($attributes, $values));
0 ignored issues
show
Bug introduced by
It seems like insert() 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

71
            return $this->/** @scrutinizer ignore-call */ insert(array_merge($attributes, $values));
Loading history...
72
        }
73
74
        if (empty($values)) {
75
            return true;
76
        }
77
78
        return (bool) $this->limit(1)->update($values);
0 ignored issues
show
Bug introduced by
It seems like limit() 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

78
        return (bool) $this->/** @scrutinizer ignore-call */ limit(1)->update($values);
Loading history...
79
    }
80
81
    /**
82
     * Increment the given column's values by the given amounts.
83
     *
84
     * @param  array<string, float|int|numeric-string>  $columns
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, float|int|numeric-string> at position 8 could not be parsed: Unknown type name 'numeric-string' at position 8 in array<string, float|int|numeric-string>.
Loading history...
85
     * @param  array<string, mixed>  $extra
86
     * @return int
87
     *
88
     * @throws \InvalidArgumentException
89
     */
90
    public function incrementEach(array $columns, array $extra = [])
91
    {
92
        foreach ($columns as $column => $amount) {
93
            if (!is_numeric($amount)) {
94
                throw new InvalidArgumentException("Non-numeric value passed as increment amount for column: '$column'.");
95
            } elseif (!is_string($column)) {
96
                throw new InvalidArgumentException('Non-associative array passed to incrementEach method.');
97
            }
98
99
            $columns[$column] = new Expression($this->getTableAlias($this->from) . '.' . $column . ' + ' . $amount);
0 ignored issues
show
Bug introduced by
It seems like getTableAlias() 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

99
            $columns[$column] = new Expression($this->/** @scrutinizer ignore-call */ getTableAlias($this->from) . '.' . $column . ' + ' . $amount);
Loading history...
100
        }
101
102
        return $this->update(array_merge($columns, $extra));
103
    }
104
105
    /**
106
     * Decrement the given column's values by the given amounts.
107
     *
108
     * @param  array<string, float|int|numeric-string>  $columns
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, float|int|numeric-string> at position 8 could not be parsed: Unknown type name 'numeric-string' at position 8 in array<string, float|int|numeric-string>.
Loading history...
109
     * @param  array<string, mixed>  $extra
110
     * @return int
111
     *
112
     * @throws \InvalidArgumentException
113
     */
114
    public function decrementEach(array $columns, array $extra = [])
115
    {
116
        foreach ($columns as $column => $amount) {
117
            if (!is_numeric($amount)) {
118
                throw new InvalidArgumentException("Non-numeric value passed as decrement amount for column: '$column'.");
119
            } elseif (!is_string($column)) {
120
                throw new InvalidArgumentException('Non-associative array passed to decrementEach method.');
121
            }
122
123
            $columns[$column] = new Expression($this->getTableAlias($this->from) . '.' . $column . ' - ' . $amount);
124
        }
125
126
        return $this->update(array_merge($columns, $extra));
127
    }
128
129
    /**
130
     * Insert new records or update the existing ones.
131
     *
132
     * @param array $values
133
     * @param array|string $uniqueBy
134
     * @param array|null $update
135
     * @return int
136
     * @throws BindException
137
     */
138
    public function upsert(array $values, $uniqueBy, $update = null)
139
    {
140
        assert($this->grammar instanceof Grammar);
141
142
        if (empty($values)) {
143
            return 0;
144
        } elseif ($update === []) {
145
            return (int) $this->insert($values);
146
        }
147
148
        if (!is_array(reset($values))) {
149
            $values = [$values];
150
        }
151
152
        foreach($values as $key => $value) {
153
            $values[$key] = $this->grammar->convertJsonFields($value);
154
            $values[$key] = $this->convertIdToKey($values[$key]);
0 ignored issues
show
Bug introduced by
It seems like convertIdToKey() 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

154
            /** @scrutinizer ignore-call */ 
155
            $values[$key] = $this->convertIdToKey($values[$key]);
Loading history...
155
            $values[$key] = Arr::undot($values[$key]);
156
        }
157
158
        foreach($values as $key => $value) {
159
            foreach ($value as $dataKey => $data) {
160
                $values[$key][$dataKey] = $this->bindValue($data, 'upsert');
161
            }
162
        }
163
164
        $uniqueBy = $this->grammar->convertJsonFields($uniqueBy);
165
166
        if (is_null($update)) {
167
            $update = array_keys(reset($values));
168
        }
169
170
        foreach ($update as $key => $value) {
171
            $update[$key] = $this->convertIdToKey($value);
172
        }
173
174
        $update = $this->grammar->convertJsonFields($update);
175
176
        $this->applyBeforeQueryCallbacks();
177
178
        $bindings = $this->bindings['upsert'];
179
180
        $aql = $this->grammar->compileUpsert($this, $values, (array) $uniqueBy, $update);
0 ignored issues
show
Bug introduced by
$this of type LaravelFreelancerNL\Aran...\Concerns\BuildsUpdates is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of LaravelFreelancerNL\Aran...rammar::compileUpsert(). ( Ignorable by Annotation )

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

180
        $aql = $this->grammar->compileUpsert(/** @scrutinizer ignore-type */ $this, $values, (array) $uniqueBy, $update);
Loading history...
181
182
        return $this->connection->affectingStatement(
183
            $aql,
184
            $bindings
185
        );
186
    }
187
}
188