2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
22 * @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 declare(strict_types=1);
28 namespace core_table\local\filter;
32 use InvalidArgumentException;
36 * Class representing a generic filter of any type.
39 * @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 class filter implements Countable, Iterator, JsonSerializable {
44 /** @var int The default filter type (ANY) */
45 const JOINTYPE_DEFAULT = 1;
47 /** @var int None of the following match */
48 const JOINTYPE_NONE = 0;
50 /** @var int Any of the following match */
51 const JOINTYPE_ANY = 1;
53 /** @var int All of the following match */
54 const JOINTYPE_ALL = 2;
56 /** @var string The name of this filter */
57 protected $name = null;
59 /** @var int The join type currently in use */
60 protected $jointype = self::JOINTYPE_DEFAULT;
62 /** @var array The list of active filter values */
63 protected $filtervalues = [];
65 /** @var int[] valid join types */
66 protected $jointypes = [
72 /** @var int The current iterator position */
73 protected $iteratorposition = null;
76 * Constructor for the generic filter class.
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.
83 public function __construct(string $name, ?int $jointype = null, ?array $values = null) {
86 if ($jointype !== null) {
87 $this->set_join_type($jointype);
90 if (!empty($values)) {
91 foreach ($values as $value) {
92 $this->add_filter_value($value);
98 * Reset the iterator position.
100 public function reset_iterator(): void {
101 $this->iteratorposition = null;
105 * Return the current filter value.
107 public function current() {
108 if ($this->iteratorposition === null) {
112 if ($this->iteratorposition === null) {
116 return $this->filtervalues[$this->iteratorposition];
120 * Returns the current position of the iterator.
124 public function key() {
125 if ($this->iteratorposition === null) {
129 return $this->iteratorposition;
133 * Rewind the Iterator position to the start.
135 public function rewind(): void {
136 if ($this->iteratorposition === null) {
137 $this->sort_filter_values();
140 if (count($this->filtervalues)) {
141 $this->iteratorposition = 0;
146 * Move to the next value in the list.
148 public function next(): void {
149 ++$this->iteratorposition;
153 * Check if the current position is valid.
157 public function valid(): bool {
158 return isset($this->filtervalues[$this->iteratorposition]);
162 * Return the number of contexts.
166 public function count(): int {
167 return count($this->filtervalues);
171 * Return the name of the filter.
175 public function get_name(): string {
180 * Specify the type of join to employ for the filter.
182 * @param int $jointype The join type to use using one of the supplied constants
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');
190 $this->jointype = $jointype;
196 * Return the currently specified join type.
200 public function get_join_type(): int {
201 return $this->jointype;
205 * Add a value to the filter.
207 * @param mixed $value
210 public function add_filter_value($value): self {
211 if ($value === null) {
212 // Null values are usually invalid.
217 // Empty strings are invalid.
221 if (array_search($value, $this->filtervalues) !== false) {
222 // Remove duplicates.
226 $this->filtervalues[] = $value;
228 // Reset the iterator position.
229 $this->reset_iterator();
235 * Sort the filter values to ensure reliable, and consistent output.
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);
243 $this->reset_iterator();
247 * Return the current filter values.
251 public function get_filter_values(): array {
252 $this->sort_filter_values();
253 return $this->filtervalues;
259 * @return mixed|object
261 public function jsonSerialize() {
263 'name' => $this->get_name(),
264 'jointype' => $this->get_join_type(),
265 'values' => $this->get_filter_values(),