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
![]() |
|||||||
26 | return $this->fromSub($table, $as); |
||||||
0 ignored issues
–
show
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
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. ![]() |
|||||||
27 | } |
||||||
28 | |||||||
29 | assert(is_string($table)); |
||||||
30 | |||||||
31 | 395 | $this->registerTableAlias($table, $as); |
|||||
0 ignored issues
–
show
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
![]() |
|||||||
32 | |||||||
33 | 395 | $this->from = $table; |
|||||
0 ignored issues
–
show
|
|||||||
34 | |||||||
35 | 395 | return $this; |
|||||
0 ignored issues
–
show
|
|||||||
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
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
![]() |
|||||||
51 | } |
||||||
52 | |||||||
53 | 1 | $this->fromOptions = $boundOptions; |
|||||
0 ignored issues
–
show
|
|||||||
54 | |||||||
55 | 1 | return $this; |
|||||
0 ignored issues
–
show
|
|||||||
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
|
|||||||
68 | 97 | $this->bindings['select'] = []; |
|||||
0 ignored issues
–
show
|
|||||||
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
|
|||||||
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
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
![]() |
|||||||
97 | |||||||
98 | 1 | $this->set($as, new Expression($query), 'postIterationVariables'); |
|||||
0 ignored issues
–
show
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
![]() |
|||||||
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
|
|||||||
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
'(' . $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
![]() |
|||||||
164 | |||||||
165 | $this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order'); |
||||||
0 ignored issues
–
show
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
![]() |
|||||||
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
$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
![]() |
|||||||
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
|
|||||||
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
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
![]() |
|||||||
238 | } |
||||||
239 | |||||||
240 | 10 | if ($query instanceof IlluminateEloquentBuilder) { |
|||||
241 | $query = $query->getQuery(); |
||||||
242 | } |
||||||
243 | |||||||
244 | 10 | $this->importBindings($query); |
|||||
0 ignored issues
–
show
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
![]() |
|||||||
245 | 10 | $this->unions[] = compact('query', 'all'); |
|||||
0 ignored issues
–
show
|
|||||||
246 | |||||||
247 | 10 | return $this; |
|||||
248 | } |
||||||
249 | } |
||||||
250 |