]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Entity/SavedSearch.php
Some phpstan lvl 4 checks
[galette.git] / galette / lib / Galette / Entity / SavedSearch.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Saved search
7 *
8 * PHP version 5
9 *
10 * Copyright © 2019-2023 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Entity
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2019-2023 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Available since 0.9.3dev - 2019-03-25
35 */
36
37 namespace Galette\Entity;
38
39 use ArrayObject;
40 use Throwable;
41 use Galette\Core\Db;
42 use Galette\Core\Login;
43 use Analog\Analog;
44
45 /**
46 * Saved search
47 *
48 * @category Entity
49 * @name SavedSearch
50 * @package Galette
51 * @author Johan Cwiklinski <johan@x-tnd.be>
52 * @copyright 2019-2023 The Galette Team
53 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
54 * @link http://galette.tuxfamily.org
55 * @since Available since 0.9.3dev - 2019-03-25
56 *
57 * @property integer $id
58 * @property string $name
59 * @property array $parameters
60 * @property integer $author_id
61 * @property string $creation_date
62 * @property string $form
63 */
64
65 class SavedSearch
66 {
67 public const TABLE = 'searches';
68 public const PK = 'search_id';
69
70 private $zdb;
71 private $id;
72 private $name;
73 private $parameters = [];
74 private $author_id;
75 private $creation_date;
76 private $form;
77
78 private $login;
79 private $errors = [];
80
81 /**
82 * Main constructor
83 *
84 * @param Db $zdb Database instance
85 * @param Login $login Login instance
86 * @param mixed $args Arguments
87 */
88 public function __construct(Db $zdb, Login $login, $args = null)
89 {
90 $this->zdb = $zdb;
91 $this->login = $login;
92 $this->creation_date = date('Y-m-d H:i:s');
93
94 if (is_int($args)) {
95 $this->load($args);
96 } elseif ($args !== null && is_object($args)) {
97 $this->loadFromRs($args);
98 }
99 }
100
101 /**
102 * Load a saved search from its identifier
103 *
104 * @param integer $id Identifier
105 *
106 * @return void
107 */
108 private function load($id)
109 {
110 try {
111 $select = $this->zdb->select(self::TABLE);
112 $select->limit(1)->where([self::PK => $id]);
113 if ($this->login->isSuperAdmin()) {
114 $select->where(Adherent::PK . ' IS NULL');
115 } else {
116 $select->where([Adherent::PK => $this->login->id]);
117 }
118
119 $results = $this->zdb->execute($select);
120 /** @var ArrayObject $res */
121 $res = $results->current();
122
123 $this->loadFromRs($res);
124 } catch (Throwable $e) {
125 Analog::log(
126 'An error occurred loading saved search #' . $id . "Message:\n" .
127 $e->getMessage(),
128 Analog::ERROR
129 );
130 throw $e;
131 }
132 }
133
134 /**
135 * Load a saved search from a db ResultSet
136 *
137 * @param ArrayObject $rs ResultSet
138 *
139 * @return void
140 */
141 private function loadFromRs(ArrayObject $rs)
142 {
143 $pk = self::PK;
144 $this->id = $rs->$pk;
145 $this->name = $rs->name;
146 $this->parameters = json_decode($rs->parameters, true);
147 $this->author_id = $rs->id_adh;
148 $this->creation_date = $rs->creation_date;
149 $this->form = $rs->form;
150 }
151
152 /**
153 * Check and set values
154 *
155 * @param array $values Values to set
156 *
157 * @return boolean
158 */
159 public function check($values)
160 {
161 $this->errors = [];
162 $mandatory = [
163 'form' => _T('Form is mandatory!')
164 ];
165
166 foreach ($values as $key => $value) {
167 if (in_array($key, ['nbshow', 'page'])) {
168 continue;
169 }
170 if (empty($value) && isset($mandatory[$key])) {
171 $this->errors[] = $mandatory[$key];
172 }
173 $this->$key = $value;
174 unset($mandatory[$key]);
175 }
176
177 if (count($mandatory)) {
178 $this->errors = array_merge($this->errors, $mandatory);
179 }
180
181 if ($this->id === null && !$this->login->isSuperAdmin()) {
182 //set author for new searches
183 $this->author_id = $this->login->id;
184 }
185
186 return (count($this->errors) === 0);
187 }
188
189 /**
190 * Store saved search in database
191 *
192 * @return boolean|null
193 */
194 public function store()
195 {
196 $parameters = json_encode($this->parameters);
197 $data = array(
198 'name' => $this->name,
199 'parameters' => $parameters,
200 'id_adh' => $this->author_id,
201 'creation_date' => ($this->creation_date !== null ? $this->creation_date : date('Y-m-d H:i:s')),
202 'form' => $this->form
203 );
204
205 try {
206 $insert = $this->zdb->insert(self::TABLE);
207 $insert->values($data);
208 $add = $this->zdb->execute($insert);
209 if (!$add->count() > 0) {
210 Analog::log('Not stored!', Analog::ERROR);
211 return false;
212 }
213 return true;
214 } catch (Throwable $e) {
215 Analog::log(
216 'An error occurred storing saved search: ' . $e->getMessage() .
217 "\n" . print_r($data, true),
218 Analog::ERROR
219 );
220 throw $e;
221 }
222 }
223
224 /**
225 * Remove current saved search
226 *
227 * @return boolean
228 */
229 public function remove()
230 {
231 $id = (int)$this->id;
232 try {
233 $delete = $this->zdb->delete(self::TABLE);
234 $delete->where([self::PK => $id]);
235 $this->zdb->execute($delete);
236 Analog::log(
237 'Saved search #' . $id . ' (' . $this->name
238 . ') deleted successfully.',
239 Analog::INFO
240 );
241 return true;
242 } catch (\RuntimeException $re) {
243 throw $re;
244 } catch (Throwable $e) {
245 Analog::log(
246 'Unable to delete saved search ' . $id . ' | ' . $e->getMessage(),
247 Analog::ERROR
248 );
249 throw $e;
250 }
251 }
252
253 /**
254 * Getter
255 *
256 * @param string $name Property name
257 *
258 * @return mixed
259 */
260 public function __get($name)
261 {
262 $forbidden = [];
263 $virtuals = ['sparameters'];
264 if (
265 in_array($name, $virtuals)
266 || !in_array($name, $forbidden)
267 && isset($this->$name)
268 ) {
269 switch ($name) {
270 case 'creation_date':
271 if ($this->$name != '') {
272 try {
273 $d = new \DateTime($this->$name);
274 return $d->format(__("Y-m-d"));
275 } catch (Throwable $e) {
276 //oops, we've got a bad date :/
277 Analog::log(
278 'Bad date (' . $this->$name . ') | ' .
279 $e->getMessage(),
280 Analog::INFO
281 );
282 return $this->$name;
283 }
284 }
285 break;
286 case 'sparameters':
287 include_once GALETTE_ROOT . 'includes/fields_defs/members_fields.php';
288 $parameters = [];
289 foreach ((array)$this->parameters as $key => $parameter) {
290 //@phpstan-ignore-next-line
291 if (isset($members_fields[$key])) {
292 //@phpstan-ignore-next-line
293 $key = $members_fields[$key]['label'];
294 }
295 if (is_array($parameter) || is_object($parameter)) {
296 $parameter = json_encode($parameter);
297 }
298 $parameters[$key] = $parameter;
299 }
300 return $parameters;
301 default:
302 if (!property_exists($this, $name)) {
303 Analog::log(
304 "Unknown property '$name'",
305 Analog::WARNING
306 );
307 return null;
308 } else {
309 return $this->$name;
310 }
311 }
312 }
313 }
314
315 /**
316 * Isset
317 * Required for twig to access properties via __get
318 *
319 * @param string $name Property name
320 *
321 * @return bool
322 */
323 public function __isset($name)
324 {
325 $forbidden = [];
326 $virtuals = ['sparameters'];
327 if (
328 in_array($name, $virtuals)
329 || !in_array($name, $forbidden)
330 && isset($this->$name)
331 ) {
332 switch ($name) {
333 case 'creation_date':
334 case 'sparameters':
335 return true;
336 default:
337 return property_exists($this, $name);
338 }
339 }
340 return false;
341 }
342
343 /**
344 * Setter
345 *
346 * @param string $name Property name
347 * @param mixed $value Property value
348 *
349 * @return void
350 */
351 public function __set($name, $value)
352 {
353 switch ($name) {
354 case 'form':
355 if (!in_array($value, $this->getKnownForms())) {
356 $this->errors[] = str_replace('%form', $value, _T("Unknown form %form!"));
357 }
358 $this->form = $value;
359 break;
360 case 'parameters':
361 if (!is_array($value)) {
362 Analog::log(
363 'Search parameters must be an array!',
364 Analog::ERROR
365 );
366 }
367 $this->parameters = $value;
368 break;
369 case 'name':
370 if (trim($value) === '') {
371 $this->errors[] = _T("Name cannot be empty!");
372 }
373 $this->name = $value;
374 break;
375 case 'author_id':
376 $this->author_id = (int)$value;
377 break;
378 default:
379 Analog::log(
380 str_replace(
381 ['%class', '%property'],
382 [self::class, $name],
383 'Unable to set %class property %property'
384 ),
385 Analog::WARNING
386 );
387 break;
388 }
389 }
390
391 /**
392 * Get known forms
393 *
394 * @return array
395 */
396 public function getKnownForms()
397 {
398 return [
399 'Adherent'
400 ];
401 }
402
403 /**
404 * Get errors
405 *
406 * @return array
407 */
408 public function getErrors()
409 {
410 return $this->errors;
411 }
412 }