These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Spatie\QueryBuilder\Concerns; |
||
4 | |||
5 | use Spatie\QueryBuilder\Sort; |
||
6 | use Illuminate\Support\Collection; |
||
7 | use Spatie\QueryBuilder\ColumnNameSanitizer; |
||
8 | use Spatie\QueryBuilder\Exceptions\InvalidSortQuery; |
||
9 | |||
10 | trait SortsQuery |
||
11 | { |
||
12 | /** @var \Illuminate\Support\Collection */ |
||
13 | protected $defaultSorts; |
||
14 | |||
15 | /** @var \Illuminate\Support\Collection */ |
||
16 | protected $allowedSorts; |
||
17 | |||
18 | /** @var bool */ |
||
19 | protected $sortsWereParsed = false; |
||
20 | |||
21 | /** |
||
22 | * Per default, sorting is allowed on all columns if not specified otherwise. |
||
23 | * We keep track of those default sorts to purge them if, at a later point in time, allowed sorts are specified. |
||
24 | * |
||
25 | * @var array |
||
26 | */ |
||
27 | protected $generatedDefaultSorts = []; |
||
28 | |||
29 | public function allowedSorts($sorts): self |
||
30 | { |
||
31 | $sorts = is_array($sorts) ? $sorts : func_get_args(); |
||
32 | |||
33 | if (! $this->request->sorts()) { |
||
0 ignored issues
–
show
|
|||
34 | return $this; |
||
35 | } |
||
36 | |||
37 | $this->allowedSorts = collect($sorts)->map(function ($sort) { |
||
38 | if ($sort instanceof Sort) { |
||
39 | return $sort; |
||
40 | } |
||
41 | |||
42 | return Sort::field(ltrim($sort, '-')); |
||
43 | }); |
||
44 | |||
45 | $this->guardAgainstUnknownSorts(); |
||
46 | |||
47 | return $this; |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * @param array|string|\Spatie\QueryBuilder\Sort $sorts |
||
52 | * |
||
53 | * @return \Spatie\QueryBuilder\QueryBuilder |
||
54 | */ |
||
55 | public function defaultSort($sorts): self |
||
56 | { |
||
57 | return $this->defaultSorts(func_get_args()); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * @param array|string|\Spatie\QueryBuilder\Sort $sorts |
||
62 | * |
||
63 | * @return \Spatie\QueryBuilder\QueryBuilder |
||
64 | */ |
||
65 | public function defaultSorts($sorts): self |
||
66 | { |
||
67 | $sorts = is_array($sorts) ? $sorts : func_get_args(); |
||
68 | |||
69 | $this->defaultSorts = collect($sorts)->map(function ($sort) { |
||
70 | if (is_string($sort)) { |
||
71 | return Sort::field($sort); |
||
72 | } |
||
73 | |||
74 | return $sort; |
||
75 | }); |
||
76 | |||
77 | return $this; |
||
78 | } |
||
79 | |||
80 | protected function parseSorts() |
||
81 | { |
||
82 | // Avoid repeated calls when used by e.g. 'paginate' |
||
83 | if ($this->sortsWereParsed) { |
||
84 | return; |
||
85 | } |
||
86 | |||
87 | $this->sortsWereParsed = true; |
||
88 | |||
89 | if (! $this->allowedSorts instanceof Collection) { |
||
90 | $this->addDefaultSorts(); |
||
91 | $this->allowRepeatedParse(); |
||
92 | } else { |
||
93 | $this->purgeGeneratedDefaultSorts(); |
||
94 | } |
||
95 | |||
96 | $sorts = $this->request->sorts(); |
||
97 | |||
98 | if ($sorts->isEmpty()) { |
||
99 | optional($this->defaultSorts)->each(function (Sort $sort) { |
||
100 | $sort->sort($this); |
||
101 | }); |
||
102 | } |
||
103 | |||
104 | $sorts |
||
105 | ->each(function (string $property) { |
||
106 | $descending = $property[0] === '-'; |
||
107 | |||
108 | $key = ltrim($property, '-'); |
||
109 | |||
110 | $sort = $this->findSort($key); |
||
111 | |||
112 | $sort->sort($this, $descending); |
||
113 | }); |
||
114 | } |
||
115 | |||
116 | protected function findSort(string $property): ?Sort |
||
117 | { |
||
118 | return $this->allowedSorts |
||
119 | ->merge($this->defaultSorts) |
||
120 | ->first(function (Sort $sort) use ($property) { |
||
121 | return $sort->isForProperty($property); |
||
122 | }); |
||
123 | } |
||
124 | |||
125 | protected function addDefaultSorts() |
||
126 | { |
||
127 | $sanitizedSortColumns = $this->request->sorts()->map(function ($sort) { |
||
128 | $sortColumn = ltrim($sort, '-'); |
||
129 | |||
130 | // This is the only place where query string parameters are passed as |
||
131 | // sort columns directly. We need to sanitize these column names. |
||
132 | return ColumnNameSanitizer::sanitize($sortColumn); |
||
133 | }); |
||
134 | |||
135 | $this->allowedSorts = $sanitizedSortColumns->map(function ($column) { |
||
136 | return Sort::field($column); |
||
137 | }); |
||
138 | |||
139 | $this->generatedDefaultSorts = $sanitizedSortColumns->toArray(); |
||
140 | } |
||
141 | |||
142 | protected function guardAgainstUnknownSorts() |
||
143 | { |
||
144 | $sortNames = $this->request->sorts()->map(function ($sort) { |
||
145 | return ltrim($sort, '-'); |
||
146 | }); |
||
147 | |||
148 | $allowedSortNames = $this->allowedSorts->map->getProperty(); |
||
149 | |||
150 | $diff = $sortNames->diff($allowedSortNames); |
||
151 | |||
152 | if ($diff->count()) { |
||
153 | throw InvalidSortQuery::sortsNotAllowed($diff, $allowedSortNames); |
||
154 | } |
||
155 | } |
||
156 | |||
157 | protected function allowRepeatedParse(): void |
||
158 | { |
||
159 | $this->sortsWereParsed = false; |
||
160 | } |
||
161 | |||
162 | protected function purgeGeneratedDefaultSorts(): void |
||
163 | { |
||
164 | $this->query->orders = collect($this->query->orders) |
||
0 ignored issues
–
show
The property
query does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
165 | ->reject(function ($order) { |
||
166 | if (! isset($order['column'])) { |
||
167 | return false; |
||
168 | } |
||
169 | |||
170 | return in_array($order['column'], $this->generatedDefaultSorts); |
||
171 | })->values()->all(); |
||
172 | } |
||
173 | } |
||
174 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: