]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Entity/SavedSearch.php
22ab866711d09c2d1ea91dfe829526714a48a74c
[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 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 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 Throwable;
40 use Galette\Core;
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 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
58 class SavedSearch
59 {
60 public const TABLE = 'searches';
61 public const PK = 'search_id';
62
63 private $zdb;
64 private $id;
65 private $name;
66 private $parameters = [];
67 private $author_id;
68 private $creation_date;
69 private $form;
70
71 private $login;
72 private $errors = [];
73
74 /**
75 * Main constructor
76 *
77 * @param Db $zdb Database instance
78 * @param Login $login Login instance
79 * @param mixed $args Arguments
80 */
81 public function __construct(Db $zdb, Login $login, $args = null)
82 {
83 $this->zdb = $zdb;
84 $this->login = $login;
85 $this->creation_date = date('Y-m-d H:i:s');
86
87 if (is_int($args)) {
88 $this->load($args);
89 } elseif ($args !== null && is_object($args)) {
90 $this->loadFromRs($args);
91 }
92 }
93
94 /**
95 * Load a saved search from its identifier
96 *
97 * @param integer $id Identifier
98 *
99 * @return void
100 */
101 private function load($id)
102 {
103 try {
104 $select = $this->zdb->select(self::TABLE);
105 $select->limit(1)->where(self::PK . ' = ' . $id);
106 if ($this->login->isSuperAdmin()) {
107 $select->where(Adherent::PK . ' IS NULL');
108 } else {
109 $select->where(Adherent::PK . ' = ' . (int)$this->login->id);
110 }
111
112 $results = $this->zdb->execute($select);
113 $res = $results->current();
114
115 $this->loadFromRs($res);
116 } catch (Throwable $e) {
117 Analog::log(
118 'An error occurred loading saved search #' . $id . "Message:\n" .
119 $e->getMessage(),
120 Analog::ERROR
121 );
122 }
123 }
124
125 /**
126 * Load a saved search from a db ResultSet
127 *
128 * @param ResultSet $rs ResultSet
129 *
130 * @return void
131 */
132 private function loadFromRs($rs)
133 {
134 $pk = self::PK;
135 $this->id = $rs->$pk;
136 $this->name = $rs->name;
137 $this->parameters = json_decode($rs->parameters, true);
138 $this->author_id = $rs->id_adh;
139 $this->creation_date = $rs->creation_date;
140 $this->form = $rs->form;
141 }
142
143 /**
144 * Check and set values
145 *
146 * @param array $values Values to set
147 *
148 * @return boolean
149 */
150 public function check($values)
151 {
152 $this->errors = [];
153 $mandatory = [
154 'form' => _T('Form is mandatory!')
155 ];
156
157 foreach ($values as $key => $value) {
158 if (in_array($key, ['nbshow', 'page'])) {
159 continue;
160 }
161 if (empty($value) && isset($mandatory[$key])) {
162 $this->errors[] = $mandatory[$key];
163 }
164 $this->$key = $value;
165 unset($mandatory[$key]);
166 }
167
168 if (count($mandatory)) {
169 $this->errors = array_merge($this->errors, $mandatory);
170 }
171
172 if ($this->id === null && !$this->login->isSuperAdmin()) {
173 //set author for new searches
174 $this->author_id = $this->login->id;
175 }
176
177 return (count($this->errors) === 0);
178 }
179
180 /**
181 * Store saved search in database
182 *
183 * @return boolean|null
184 */
185 public function store()
186 {
187 $parameters = json_encode($this->parameters);
188 $parameters_sum = sha1($parameters, true);
189 if ($this->zdb->isPostgres()) {
190 $parameters_sum = pg_escape_bytea($parameters_sum);
191 }
192 $data = array(
193 'name' => $this->name,
194 'parameters' => $parameters,
195 'parameters_sum' => $parameters_sum,
196 'id_adh' => $this->author_id,
197 'creation_date' => ($this->creation_date !== null ? $this->creation_date : date('Y-m-d H:i:s')),
198 'form' => $this->form
199 );
200
201 try {
202 $select = $this->zdb->select(self::TABLE);
203 $select
204 ->where([
205 'form' => $this->form,
206 'parameters_sum' => $parameters_sum,
207 'id_adh' => $this->author_id,
208 ])
209 ->limit(1);
210
211 $results = $this->zdb->execute($select);
212 if ($results->count() !== 0) {
213 $result = $results->current();
214 //search already exists
215 Analog::log(
216 str_replace('%name', $result->name, 'Already saved as "%name"!'),
217 Analog::INFO
218 );
219 return null;
220 } else {
221 $insert = $this->zdb->insert(self::TABLE);
222 $insert->values($data);
223 $add = $this->zdb->execute($insert);
224 if (!$add->count() > 0) {
225 Analog::log('Not stored!', Analog::ERROR);
226 return false;
227 }
228 }
229 return true;
230 } catch (Throwable $e) {
231 Analog::log(
232 'An error occurred storing saved search: ' . $e->getMessage() .
233 "\n" . print_r($data, true),
234 Analog::ERROR
235 );
236 return false;
237 }
238 }
239
240 /**
241 * Remove current saved search
242 *
243 * @return boolean
244 */
245 public function remove()
246 {
247 $id = (int)$this->id;
248 try {
249 $delete = $this->zdb->delete(self::TABLE);
250 $delete->where(
251 self::PK . ' = ' . $id
252 );
253 $this->zdb->execute($delete);
254 Analog::log(
255 'Saved search #' . $id . ' (' . $this->name
256 . ') deleted successfully.',
257 Analog::INFO
258 );
259 return true;
260 } catch (\RuntimeException $re) {
261 throw $re;
262 } catch (Throwable $e) {
263 Analog::log(
264 'Unable to delete saved search ' . $id . ' | ' . $e->getMessage(),
265 Analog::ERROR
266 );
267 throw $e;
268 }
269 }
270
271 /**
272 * Getter
273 *
274 * @param string $name Property name
275 *
276 * @return mixed
277 */
278 public function __get($name)
279 {
280 $forbidden = [];
281 $virtuals = ['sparameters'];
282 if (
283 in_array($name, $virtuals)
284 || !in_array($name, $forbidden)
285 && isset($this->$name)
286 ) {
287 switch ($name) {
288 case 'creation_date':
289 if ($this->$name != '') {
290 try {
291 $d = new \DateTime($this->$name);
292 return $d->format(__("Y-m-d"));
293 } catch (Throwable $e) {
294 //oops, we've got a bad date :/
295 Analog::log(
296 'Bad date (' . $this->$name . ') | ' .
297 $e->getMessage(),
298 Analog::INFO
299 );
300 return $this->$name;
301 }
302 }
303 break;
304 case 'sparameters':
305 include_once GALETTE_ROOT . 'includes/fields_defs/members_fields.php';
306 $parameters = [];
307 foreach ((array)$this->parameters as $key => $parameter) {
308 if (isset($members_fields[$key])) {
309 $key = $members_fields[$key]['label'];
310 }
311 if (is_array($parameter) || is_object($parameter)) {
312 $parameter = json_encode($parameter);
313 }
314 $parameters[$key] = $parameter;
315 }
316 return $parameters;
317 break;
318 default:
319 if (!property_exists($this, $name)) {
320 Analog::log(
321 "Unknown property '$name'",
322 Analog::WARNING
323 );
324 return null;
325 } else {
326 return $this->$name;
327 }
328 break;
329 }
330 }
331 }
332
333 /**
334 * Setter
335 *
336 * @param string $name Property name
337 * @param mixed $value Property value
338 *
339 * @return void
340 */
341 public function __set($name, $value)
342 {
343 switch ($name) {
344 case 'form':
345 if (!in_array($value, $this->getKnownForms())) {
346 $this->errors[] = str_replace('%form', $value, _T("Unknown form %form!"));
347 }
348 $this->form = $value;
349 break;
350 case 'parameters':
351 if (!is_array($value)) {
352 Analog::log(
353 'Search parameters must be an array!',
354 Analog::ERROR
355 );
356 }
357 $this->parameters = $value;
358 break;
359 case 'name':
360 if (trim($value) === '') {
361 $this->errors[] = _T("Name cannot be empty!");
362 }
363 $this->name = $value;
364 break;
365 case 'author_id':
366 $this->author_id = (int)$value;
367 break;
368 default:
369 Analog::log(
370 str_replace(
371 ['%class', '%property'],
372 [self::class, $name],
373 'Unable to set %class property %property'
374 ),
375 Analog::WARNING
376 );
377 break;
378 }
379 }
380
381 /**
382 * Get known forms
383 *
384 * @return array
385 */
386 public function getKnownForms()
387 {
388 return [
389 'Adherent'
390 ];
391 }
392
393 /**
394 * Get errors
395 *
396 * @return array
397 */
398 public function getErrors()
399 {
400 return $this->errors;
401 }
402 }