Failed Conditions
Push — refactor/improve-static-analys... ( b52513...13b8bc )
by Bas
06:07
created

BuildsUpdates::incrementEach()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 13
rs 10
cc 4
nc 4
nop 2
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\FluentAQL\Exceptions\BindException;
11
12
/**
13
 * @method applyBeforeQueryCallbacks()
14
 */
15
trait BuildsUpdates
16
{
17
    protected function prepareValuesForUpdate(array $values)
18
    {
19
        foreach($values as $key => $value) {
20
            if ($value instanceof Expression) {
21
                $values[$key] = $value->getValue($this->grammar);
22
            } elseif (is_array($value)) {
23
                $values[$key] = $this->prepareValuesForUpdate($value);
24
            } else {
25
                $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

25
                /** @scrutinizer ignore-call */ 
26
                $values[$key]  = $this->bindValue($value, 'update');
Loading history...
26
            }
27
        }
28
29
        return $values;
30
    }
31
32
    /**
33
     * Update records in the database.
34
     *
35
     * @param  array  $values
36
     * @return int
37
     */
38
    public function update(array $values)
39
    {
40
        $this->applyBeforeQueryCallbacks();
41
42
        $values = Arr::undot($this->grammar->convertJsonFields($values));
43
44
        $values = $this->prepareValuesForUpdate($values);
45
46
        $aql = $this->grammar->compileUpdate($this, $values);
47
48
        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

48
        return $this->connection->update($aql, $this->/** @scrutinizer ignore-call */ getBindings());
Loading history...
49
    }
50
51
    /**
52
     * Insert or update a record matching the attributes, and fill it with values.
53
     *
54
     * @param array $attributes
55
     * @param array $values
56
     * @return bool
57
     * @throws BindException
58
     */
59
    public function updateOrInsert(array $attributes, array $values = [])
60
    {
61
        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

61
        if (!$this->/** @scrutinizer ignore-call */ where($attributes)->exists()) {
Loading history...
62
            $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...
63
            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

63
            return $this->/** @scrutinizer ignore-call */ insert(array_merge($attributes, $values));
Loading history...
64
        }
65
66
        if (empty($values)) {
67
            return true;
68
        }
69
70
        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

70
        return (bool) $this->/** @scrutinizer ignore-call */ limit(1)->update($values);
Loading history...
71
    }
72
73
    /**
74
     * Increment the given column's values by the given amounts.
75
     *
76
     * @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...
77
     * @param  array<string, mixed>  $extra
78
     * @return int
79
     *
80
     * @throws \InvalidArgumentException
81
     */
82
    public function incrementEach(array $columns, array $extra = [])
83
    {
84
        foreach ($columns as $column => $amount) {
85
            if (!is_numeric($amount)) {
86
                throw new InvalidArgumentException("Non-numeric value passed as increment amount for column: '$column'.");
87
            } elseif (!is_string($column)) {
88
                throw new InvalidArgumentException('Non-associative array passed to incrementEach method.');
89
            }
90
91
            $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

91
            $columns[$column] = new Expression($this->/** @scrutinizer ignore-call */ getTableAlias($this->from) . '.' . $column . ' + ' . $amount);
Loading history...
92
        }
93
94
        return $this->update(array_merge($columns, $extra));
95
    }
96
97
    /**
98
     * Decrement the given column's values by the given amounts.
99
     *
100
     * @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...
101
     * @param  array<string, mixed>  $extra
102
     * @return int
103
     *
104
     * @throws \InvalidArgumentException
105
     */
106
    public function decrementEach(array $columns, array $extra = [])
107
    {
108
        foreach ($columns as $column => $amount) {
109
            if (!is_numeric($amount)) {
110
                throw new InvalidArgumentException("Non-numeric value passed as decrement amount for column: '$column'.");
111
            } elseif (!is_string($column)) {
112
                throw new InvalidArgumentException('Non-associative array passed to decrementEach method.');
113
            }
114
115
            $columns[$column] = new Expression($this->getTableAlias($this->from) . '.' . $column . ' - ' . $amount);
116
        }
117
118
        return $this->update(array_merge($columns, $extra));
119
    }
120
121
    /**
122
     * Insert new records or update the existing ones.
123
     *
124
     * @param array $values
125
     * @param array|string $uniqueBy
126
     * @param array|null $update
127
     * @return int
128
     * @throws BindException
129
     */
130
    public function upsert(array $values, $uniqueBy, $update = null)
131
    {
132
        if (empty($values)) {
133
            return 0;
134
        } elseif ($update === []) {
135
            return (int) $this->insert($values);
136
        }
137
138
        if (!is_array(reset($values))) {
139
            $values = [$values];
140
        }
141
142
        foreach($values as $key => $value) {
143
            $values[$key] = Arr::undot($this->grammar->convertJsonFields($value));
144
        }
145
146
        foreach($values as $key => $value) {
147
            $values[$key] = $this->convertIdToKey($value);
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

147
            /** @scrutinizer ignore-call */ 
148
            $values[$key] = $this->convertIdToKey($value);
Loading history...
148
        }
149
150
        foreach($values as $key => $value) {
151
            foreach ($value as $dataKey => $data) {
152
                $values[$key][$dataKey] = $this->bindValue($data, 'upsert');
153
            }
154
        }
155
156
        // unique id value should already be converted to _key
157
        foreach ($uniqueBy as $key => $value) {
158
            $uniqueBy[$key] = $this->convertIdToKey($value);
159
        }
160
        $uniqueBy = $this->grammar->convertJsonFields($uniqueBy);
161
162
        if (is_null($update)) {
163
            $update = array_keys(reset($values));
164
        }
165
        foreach ($update as $key => $value) {
166
            $update[$key] = $this->convertIdToKey($value);
167
        }
168
        $update = $this->grammar->convertJsonFields($update);
169
170
        $this->applyBeforeQueryCallbacks();
171
172
        $bindings = $this->bindings['upsert'];
173
174
        $aql = $this->grammar->compileUpsert($this, $values, (array) $uniqueBy, $update);
175
176
        return $this->connection->affectingStatement(
177
            $aql,
178
            $bindings
179
        );
180
    }
181
}
182