BuildsSelects::addSelect()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent\Query\Concerns;
6
7
use Exception;
8
use Illuminate\Database\Eloquent\Builder as IlluminateEloquentBuilder;
9
use Illuminate\Database\Query\Builder as IlluminateQueryBuilder;
10
use Illuminate\Database\Query\Expression;
11
use InvalidArgumentException;
12
use LaravelFreelancerNL\Aranguent\Query\Grammar;
13
14
trait BuildsSelects
15
{
16
    /**
17
     * Set the table which the query is targeting.
18
     *
19
     * @param \Closure|IlluminateQueryBuilder|string $table
20
     * @param string|null $as
21
     * @return IlluminateQueryBuilder
22
     */
23 395
    public function from($table, $as = null)
24
    {
25 395
        if ($this->isQueryable($table) && $as !== null) {
0 ignored issues
show
Bug introduced by
It seems like isQueryable() 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
        if ($this->/** @scrutinizer ignore-call */ isQueryable($table) && $as !== null) {
Loading history...
26
            return $this->fromSub($table, $as);
0 ignored issues
show
Bug introduced by
The method fromSub() does not exist on LaravelFreelancerNL\Aran...\Concerns\BuildsSelects. Did you maybe mean from()? ( Ignorable by Annotation )

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

26
            return $this->/** @scrutinizer ignore-call */ fromSub($table, $as);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
27
        }
28
29
        assert(is_string($table));
30
31 395
        $this->registerTableAlias($table, $as);
0 ignored issues
show
Bug introduced by
It seems like registerTableAlias() 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

31
        $this->/** @scrutinizer ignore-call */ 
32
               registerTableAlias($table, $as);
Loading history...
32
33 395
        $this->from = $table;
0 ignored issues
show
Bug Best Practice introduced by
The property from does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
34
35 395
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type LaravelFreelancerNL\Aran...\Concerns\BuildsSelects which is incompatible with the documented return type Illuminate\Database\Query\Builder.
Loading history...
36
    }
37
38
    /**
39
     * Set the table which the query is targeting.
40
     *
41
     * @param array<mixed> $options
42
     *
43
     * @return IlluminateQueryBuilder
44
     */
45 1
    public function fromOptions($options)
46
    {
47
48 1
        $boundOptions = [];
49 1
        foreach ($options as $key => $option) {
50 1
            $boundOptions[$key]  = $this->bindValue($option, 'fromOptions');
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

50
            /** @scrutinizer ignore-call */ 
51
            $boundOptions[$key]  = $this->bindValue($option, 'fromOptions');
Loading history...
51
        }
52
53 1
        $this->fromOptions = $boundOptions;
0 ignored issues
show
Bug Best Practice introduced by
The property fromOptions does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
54
55 1
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type LaravelFreelancerNL\Aran...\Concerns\BuildsSelects which is incompatible with the documented return type Illuminate\Database\Query\Builder.
Loading history...
56
    }
57
58
    /**
59
     * Set the columns to be selected.
60
     *
61
     * @param array<mixed>|mixed $columns
62
     * @return IlluminateQueryBuilder
63
     * @throws Exception
64
     */
65 97
    public function select($columns = ['*']): IlluminateQueryBuilder
66
    {
67 97
        $this->columns = [];
0 ignored issues
show
Bug Best Practice introduced by
The property columns does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
68 97
        $this->bindings['select'] = [];
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...
69
70 97
        $columns = is_array($columns) ? $columns : func_get_args();
71
72 97
        foreach ($columns as $as => $column) {
73 97
            if (is_string($as) && $this->isQueryable($column)) {
74 1
                $this->selectSub($column, $as);
75 1
                continue;
76
            }
77
78 97
            $this->addColumns([$as => $column]);
79
        }
80
81 97
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type LaravelFreelancerNL\Aran...\Concerns\BuildsSelects which is incompatible with the type-hinted return Illuminate\Database\Query\Builder.
Loading history...
82
    }
83
84
    /**
85
     * Add a subselect expression to the query.
86
     *
87
     * @param \Closure|IlluminateQueryBuilder|IlluminateEloquentBuilder|string $query
88
     * @param string $as
89
     * @return $this
90
     *
91
     * @throws \InvalidArgumentException
92
     * @throws Exception
93
     */
94 1
    public function selectSub($query, $as)
95
    {
96 1
        [$query] = $this->createSub($query, true);
0 ignored issues
show
Bug introduced by
It seems like createSub() 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

96
        /** @scrutinizer ignore-call */ 
97
        [$query] = $this->createSub($query, true);
Loading history...
97
98 1
        $this->set($as, new Expression($query), 'postIterationVariables');
0 ignored issues
show
Bug introduced by
It seems like set() 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

98
        $this->/** @scrutinizer ignore-call */ 
99
               set($as, new Expression($query), 'postIterationVariables');
Loading history...
99
100 1
        $this->addColumns([$as]);
101
102 1
        return $this;
103
    }
104
105
    /**
106
     * Add a new select column to the query.
107
     *
108
     * @param array|mixed $column
109
     * @return $this
110
     */
111 21
    public function addSelect($column)
112
    {
113 21
        $columns = is_array($column) ? $column : func_get_args();
114
115 21
        $this->addColumns($columns);
116
117 21
        return $this;
118
    }
119
120
    /**
121
     * @param array<mixed> $columns
122
     */
123 113
    protected function addColumns(array $columns): void
124
    {
125 113
        $table = (string) $this->grammar->getValue($this->from);
126
127 113
        foreach ($columns as $as => $column) {
128 113
            if (is_string($as) && $this->isQueryable($column)) {
129
                if (empty($this->columns)) {
130
                    $this->select($table . '.*');
131
                }
132
133
                $this->selectSub($column, $as);
134
135
                continue;
136
            }
137
138 113
            if (is_string($as)) {
139 2
                $this->columns[$as] = $column;
0 ignored issues
show
Bug Best Practice introduced by
The property columns does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
140
141 2
                continue;
142
            }
143
144 113
            $this->columns[] = $column;
145
        }
146
    }
147
148
    /**
149
     * Add an "order by" clause to the query.
150
     *
151
     * @param \Closure|IlluminateQueryBuilder|IlluminateEloquentBuilder|Expression|string $column
152
     * @param string $direction
153
     * @return $this
154
     *
155
     * @throws \InvalidArgumentException
156
     */
157 94
    public function orderBy($column, $direction = 'asc')
158
    {
159 94
        if ($this->isQueryable($column)) {
160
            assert(!$column instanceof Expression);
161
            [$query, $bindings] = $this->createSub($column);
162
163
            $column = new Expression('(' . $query . ')');
0 ignored issues
show
Bug introduced by
'(' . $query . ')' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct(). ( Ignorable by Annotation )

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

163
            $column = new Expression(/** @scrutinizer ignore-type */ '(' . $query . ')');
Loading history...
164
165
            $this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order');
0 ignored issues
show
Bug introduced by
It seems like addBinding() 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

165
            $this->/** @scrutinizer ignore-call */ 
166
                   addBinding($bindings, $this->unions ? 'unionOrder' : 'order');
Loading history...
166
        }
167
168 94
        $direction = strtoupper($direction);
169
170 94
        if (!in_array($direction, ['ASC', 'DESC'], true)) {
171
            throw new InvalidArgumentException('Order direction must be "asc" or "desc".');
172
        }
173
174 94
        $this->{$this->unions ? 'unionOrders' : 'orders'}[] = [
175 94
            'column' => $column,
176 94
            'direction' => $direction,
177 94
        ];
178
179 94
        return $this;
180
    }
181
182
    /**
183
     * @param string $aql
184
     * @param array<mixed> $bindings
185
     * @return $this
186
     */
187 3
    public function orderByRaw($aql, $bindings = [])
188
    {
189 3
        $type = 'Raw';
190
191 3
        $sql = new Expression($aql);
0 ignored issues
show
Bug introduced by
$aql of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct(). ( Ignorable by Annotation )

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

191
        $sql = new Expression(/** @scrutinizer ignore-type */ $aql);
Loading history...
192
193 3
        $this->{$this->unions ? 'unionOrders' : 'orders'}[] = compact('type', 'sql');
194
195 3
        if (!isset($this->bindings[$this->unions ? 'unionOrders' : 'orders'])) {
196 3
            $this->bindings[$this->unions ? 'unionOrders' : 'orders'] = $bindings;
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...
197
198 3
            return $this;
199
        }
200
201
        $this->bindings[$this->unions ? 'unionOrders' : 'orders'] = array_merge(
202
            $this->bindings[$this->unions ? 'unionOrders' : 'orders'],
203
            $bindings,
204
        );
205
206
        return $this;
207
    }
208
209
    /**
210
     * Put the query's results in random order.
211
     *
212
     * @param string $seed
213
     * @return $this
214
     */
215 1
    public function inRandomOrder($seed = '')
216
    {
217
        assert($this->grammar instanceof Grammar);
218
219
        // ArangoDB's random function doesn't accept a seed.
220 1
        unset($seed);
221
222 1
        return $this->orderByRaw($this->grammar->compileRandom());
223
    }
224
225
    /**
226
     * Add a union statement to the query.
227
     *
228
     * @param  \Closure|IlluminateQueryBuilder|IlluminateEloquentBuilder $query
229
     * @param  bool  $all
230
     * @return $this
231
     *
232
     * @SuppressWarnings("PHPMD.BooleanArgumentFlag")
233
     */
234 10
    public function union($query, $all = false)
235
    {
236 10
        if ($query instanceof \Closure) {
237
            $query($query = $this->newQuery());
0 ignored issues
show
Bug introduced by
It seems like newQuery() 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

237
            $query($query = $this->/** @scrutinizer ignore-call */ newQuery());
Loading history...
238
        }
239
240 10
        if ($query instanceof IlluminateEloquentBuilder) {
241
            $query = $query->getQuery();
242
        }
243
244 10
        $this->importBindings($query);
0 ignored issues
show
Bug introduced by
It seems like importBindings() 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

244
        $this->/** @scrutinizer ignore-call */ 
245
               importBindings($query);
Loading history...
245 10
        $this->unions[] = compact('query', 'all');
0 ignored issues
show
Bug Best Practice introduced by
The property unions does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
246
247 10
        return $this;
248
    }
249
}
250