Failed Conditions
Push — refactor/improve-static-analys... ( c6edde...45b897 )
by Bas
07:40
created

BuildsUpdates   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 63
c 1
b 0
f 0
dl 0
loc 168
rs 10
wmc 27

6 Methods

Rating   Name   Duplication   Size   Complexity  
A decrementEach() 0 13 4
A incrementEach() 0 13 4
A updateOrInsert() 0 12 3
C upsert() 0 51 11
A prepareValuesForUpdate() 0 13 4
A update() 0 13 1
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
            } elseif (is_array($value)) {
24
                $values[$key] = $this->prepareValuesForUpdate($value);
25
            } else {
26
                $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

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

49
        $aql = $this->grammar->compileUpdate(/** @scrutinizer ignore-type */ $this, $values);
Loading history...
50
51
        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

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

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

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

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

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

152
            /** @scrutinizer ignore-call */ 
153
            $values[$key] = $this->convertIdToKey($value);
Loading history...
153
        }
154
155
        foreach($values as $key => $value) {
156
            foreach ($value as $dataKey => $data) {
157
                $values[$key][$dataKey] = $this->bindValue($data, 'upsert');
158
            }
159
        }
160
161
        // unique id value should already be converted to _key
162
        foreach ($uniqueBy as $key => $value) {
163
            $uniqueBy[$key] = $this->convertIdToKey($value);
164
        }
165
        $uniqueBy = $this->grammar->convertJsonFields($uniqueBy);
166
167
        if (is_null($update)) {
168
            $update = array_keys(reset($values));
169
        }
170
        foreach ($update as $key => $value) {
171
            $update[$key] = $this->convertIdToKey($value);
172
        }
173
        $update = $this->grammar->convertJsonFields($update);
174
175
        $this->applyBeforeQueryCallbacks();
176
177
        $bindings = $this->bindings['upsert'];
178
179
        $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

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