Commit | Line | Data |
---|---|---|
44effcb4 AN |
1 | <?php |
2 | // This file is part of Moodle - http://moodle.org/ | |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | /** | |
18 | * Table filterset. | |
19 | * | |
20 | * @package core | |
21 | * @category table | |
22 | * @copyright 2020 Andrew Nicols <andrew@nicols.co.uk> | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
26 | declare(strict_types=1); | |
27 | ||
28 | namespace core_table\local\filter; | |
29 | ||
30 | use Countable; | |
1592c3c4 | 31 | use JsonSerializable; |
44effcb4 AN |
32 | use InvalidArgumentException; |
33 | use Iterator; | |
34 | ||
35 | /** | |
36 | * Class representing a generic filter of any type. | |
37 | * | |
38 | * @package core | |
39 | * @copyright 2020 Andrew Nicols <andrew@nicols.co.uk> | |
40 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
41 | */ | |
1592c3c4 | 42 | class filter implements Countable, Iterator, JsonSerializable { |
44effcb4 | 43 | |
a489f20f | 44 | /** @var int The default filter type (ANY) */ |
9e791ff7 | 45 | const JOINTYPE_DEFAULT = 1; |
44effcb4 AN |
46 | |
47 | /** @var int None of the following match */ | |
48 | const JOINTYPE_NONE = 0; | |
49 | ||
50 | /** @var int Any of the following match */ | |
51 | const JOINTYPE_ANY = 1; | |
52 | ||
53 | /** @var int All of the following match */ | |
54 | const JOINTYPE_ALL = 2; | |
55 | ||
56 | /** @var string The name of this filter */ | |
57 | protected $name = null; | |
58 | ||
59 | /** @var int The join type currently in use */ | |
60 | protected $jointype = self::JOINTYPE_DEFAULT; | |
61 | ||
62 | /** @var array The list of active filter values */ | |
63 | protected $filtervalues = []; | |
64 | ||
65 | /** @var int[] valid join types */ | |
66 | protected $jointypes = [ | |
67 | self::JOINTYPE_NONE, | |
68 | self::JOINTYPE_ANY, | |
69 | self::JOINTYPE_ALL, | |
70 | ]; | |
71 | ||
72 | /** @var int The current iterator position */ | |
73 | protected $iteratorposition = null; | |
74 | ||
75 | /** | |
76 | * Constructor for the generic filter class. | |
77 | * | |
78 | * @param string $name The name of the current filter. | |
79 | * @param int $jointype The join to use when combining the filters. | |
80 | * See the JOINTYPE_ constants for further information on the field. | |
81 | * @param mixed[] $values An array of filter objects to be applied. | |
82 | */ | |
83 | public function __construct(string $name, ?int $jointype = null, ?array $values = null) { | |
84 | $this->name = $name; | |
85 | ||
86 | if ($jointype !== null) { | |
87 | $this->set_join_type($jointype); | |
88 | } | |
89 | ||
90 | if (!empty($values)) { | |
91 | foreach ($values as $value) { | |
92 | $this->add_filter_value($value); | |
93 | } | |
94 | } | |
95 | } | |
96 | ||
97 | /** | |
98 | * Reset the iterator position. | |
99 | */ | |
100 | public function reset_iterator(): void { | |
101 | $this->iteratorposition = null; | |
102 | } | |
103 | ||
104 | /** | |
105 | * Return the current filter value. | |
106 | */ | |
107 | public function current() { | |
108 | if ($this->iteratorposition === null) { | |
109 | $this->rewind(); | |
110 | } | |
111 | ||
112 | if ($this->iteratorposition === null) { | |
113 | return null; | |
114 | } | |
115 | ||
116 | return $this->filtervalues[$this->iteratorposition]; | |
117 | } | |
118 | ||
119 | /** | |
120 | * Returns the current position of the iterator. | |
121 | * | |
122 | * @return int | |
123 | */ | |
124 | public function key() { | |
125 | if ($this->iteratorposition === null) { | |
126 | $this->rewind(); | |
127 | } | |
128 | ||
129 | return $this->iteratorposition; | |
130 | } | |
131 | ||
132 | /** | |
133 | * Rewind the Iterator position to the start. | |
134 | */ | |
135 | public function rewind(): void { | |
136 | if ($this->iteratorposition === null) { | |
137 | $this->sort_filter_values(); | |
138 | } | |
139 | ||
140 | if (count($this->filtervalues)) { | |
141 | $this->iteratorposition = 0; | |
142 | } | |
143 | } | |
144 | ||
145 | /** | |
146 | * Move to the next value in the list. | |
147 | */ | |
148 | public function next(): void { | |
149 | ++$this->iteratorposition; | |
150 | } | |
151 | ||
152 | /** | |
153 | * Check if the current position is valid. | |
154 | * | |
155 | * @return bool | |
156 | */ | |
157 | public function valid(): bool { | |
158 | return isset($this->filtervalues[$this->iteratorposition]); | |
159 | } | |
160 | ||
161 | /** | |
162 | * Return the number of contexts. | |
163 | * | |
164 | * @return int | |
165 | */ | |
166 | public function count(): int { | |
167 | return count($this->filtervalues); | |
168 | } | |
169 | ||
170 | /** | |
171 | * Return the name of the filter. | |
172 | * | |
173 | * @return string | |
174 | */ | |
175 | public function get_name(): string { | |
176 | return $this->name; | |
177 | } | |
178 | ||
179 | /** | |
180 | * Specify the type of join to employ for the filter. | |
181 | * | |
182 | * @param int $jointype The join type to use using one of the supplied constants | |
183 | * @return self | |
184 | */ | |
185 | public function set_join_type(int $jointype): self { | |
186 | if (array_search($jointype, $this->jointypes) === false) { | |
187 | throw new InvalidArgumentException('Invalid join type specified'); | |
188 | } | |
189 | ||
190 | $this->jointype = $jointype; | |
191 | ||
192 | return $this; | |
193 | } | |
194 | ||
195 | /** | |
196 | * Return the currently specified join type. | |
197 | * | |
198 | * @return int | |
199 | */ | |
200 | public function get_join_type(): int { | |
201 | return $this->jointype; | |
202 | } | |
203 | ||
204 | /** | |
205 | * Add a value to the filter. | |
206 | * | |
207 | * @param mixed $value | |
208 | * @return self | |
209 | */ | |
210 | public function add_filter_value($value): self { | |
211 | if ($value === null) { | |
212 | // Null values are usually invalid. | |
213 | return $this; | |
214 | } | |
215 | ||
216 | if ($value === '') { | |
217 | // Empty strings are invalid. | |
218 | return $this; | |
219 | } | |
220 | ||
221 | if (array_search($value, $this->filtervalues) !== false) { | |
222 | // Remove duplicates. | |
223 | return $this; | |
224 | } | |
225 | ||
226 | $this->filtervalues[] = $value; | |
227 | ||
228 | // Reset the iterator position. | |
229 | $this->reset_iterator(); | |
230 | ||
231 | return $this; | |
232 | } | |
233 | ||
234 | /** | |
235 | * Sort the filter values to ensure reliable, and consistent output. | |
236 | */ | |
237 | protected function sort_filter_values(): void { | |
238 | // Sort the filter values to ensure consistent output. | |
239 | // Note: This is not a locale-aware sort, but we don't need this. | |
240 | // It's primarily for consistency, not for actual sorting. | |
241 | sort($this->filtervalues); | |
242 | ||
243 | $this->reset_iterator(); | |
244 | } | |
245 | ||
246 | /** | |
247 | * Return the current filter values. | |
248 | * | |
249 | * @return mixed[] | |
250 | */ | |
251 | public function get_filter_values(): array { | |
252 | $this->sort_filter_values(); | |
253 | return $this->filtervalues; | |
254 | } | |
1592c3c4 SL |
255 | |
256 | /** | |
257 | * Serialize filter. | |
258 | * | |
259 | * @return mixed|object | |
260 | */ | |
261 | public function jsonSerialize() { | |
262 | return (object) [ | |
263 | 'name' => $this->get_name(), | |
264 | 'jointype' => $this->get_join_type(), | |
265 | 'values' => $this->get_filter_values(), | |
266 | ]; | |
267 | } | |
44effcb4 | 268 | } |