3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
10 * Copyright © 2007-2021 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
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.
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.
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/>.
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2007-2021 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.7dev - 2007-10-27
37 namespace Galette\Entity
;
41 use Laminas\Db\Sql\Expression
;
43 use Galette\Features\I18n
;
46 * Entitled handling. Manage:
49 * - extra (that may differ from one entity to another)
54 * @author Johan Cwiklinski <johan@x-tnd.be>
55 * @copyright 2007-2021 The Galette Team
56 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
57 * @link http://galette.tuxfamily.org
58 * @since Available since 0.7dev - 2007-10-27
60 * @property integer $id
61 * @property string $label
62 * @property string $libelle
63 * @property mixed $third
64 * @property mixed $extension
67 abstract class Entitled
71 public const ID_NOT_EXITS
= -1;
80 public static $fields;
81 protected static $defaults;
83 /** @var string|false */
84 protected $order_field = false;
90 private $errors = array();
95 * @param Db $zdb Database
96 * @param string $table Table name
97 * @param string $fpk Primary key field name
98 * @param string $flabel Label fields name
99 * @param string $fthird The third field name
100 * @param string $used Table name for isUsed function
101 * @param mixed $args Either an int or a resultset to load
103 public function __construct(Db
$zdb, $table, $fpk, $flabel, $fthird, $used, $args = null)
106 $this->table
= $table;
108 $this->flabel
= $flabel;
109 $this->fthird
= $fthird;
113 } elseif (is_object($args)) {
114 $this->loadFromRS($args);
119 * Loads an entry from its id
121 * @param int $id Entry ID
123 * @return boolean true if query succeed, false otherwise
125 public function load($id)
128 $select = $this->zdb
->select($this->table
);
129 $select->where($this->fpk
. ' = ' . $id);
131 $results = $this->zdb
->execute($select);
132 if ($results->count() > 0) {
133 $result = $results->current();
134 $this->loadFromRS($result);
144 } catch (Throwable
$e) {
146 'Cannot load ' . $this->getType() . ' from id `' . $id . '` | ' .
155 * Populate object from a resultset row
157 * @param ResultSet $r the resultset row
161 private function loadFromRS($r)
165 $flabel = $this->flabel
;
166 $this->label
= $r->$flabel;
167 $fthird = $this->fthird
;
168 $this->third
= $r->$fthird;
172 * Set defaults at install time
177 public function installInit()
179 $class = get_class($this);
182 //first, we drop all values
183 $delete = $this->zdb
->delete($this->table
);
184 $this->zdb
->execute($delete);
187 foreach ($class::$fields as $key => $f) {
188 $values[$f] = ':' . $key;
191 $insert = $this->zdb
->insert($this->table
);
192 $insert->values($values);
193 $stmt = $this->zdb
->sql
->prepareStatementForSqlObject($insert);
195 $this->zdb
->handleSequence(
197 count(static::$defaults)
200 $fnames = array_values($values);
201 foreach ($class::$defaults as $d) {
203 if (isset($d['priority'])) {
204 $val = $d['priority'];
206 $val = $d['extension'];
211 $fnames[0] => $d['id'],
212 $fnames[1] => $d['libelle'],
219 'Defaults (' . $this->getType() .
220 ') were successfully stored into database.',
224 } catch (Throwable
$e) {
226 'Unable to initialize defaults (' . $this->getType() . ').' .
235 * Get list in an array built as:
236 * $array[id] = "translated label"
238 * @param boolean|null $extent Filter on (non) cotisations types
240 * @return array|false
242 public function getList(bool $extent = null)
247 $select = $this->zdb
->select($this->table
);
248 $fields = array($this->fpk
, $this->flabel
);
250 $this->order_field
!== false
251 && $this->order_field
!== $this->fpk
252 && $this->order_field
!== $this->flabel
254 $fields[] = $this->order_field
;
256 $select->quantifier('DISTINCT');
257 $select->columns($fields);
259 if ($this->order_field
!== false) {
260 $select->order($this->order_field
, $this->fpk
);
262 if ($extent !== null) {
263 if ($extent === true) {
264 $select->where(array($this->fthird
=> new Expression('true')));
265 } elseif ($extent === false) {
266 $select->where(array($this->fthird
=> new Expression('false')));
270 $results = $this->zdb
->execute($select);
272 foreach ($results as $r) {
274 $flabel = $this->flabel
;
275 $list[$r->$fpk] = _T($r->$flabel);
278 } catch (Throwable
$e) {
280 __METHOD__
. ' | ' . $e->getMessage(),
290 * @return array of all objects if succeeded, false otherwise
292 public function getCompleteList()
297 $select = $this->zdb
->select($this->table
);
298 if ($this->order_field
!== false) {
299 $select->order(array($this->order_field
, $this->fpk
));
302 $results = $this->zdb
->execute($select);
304 if ($results->count() == 0) {
306 'No entries (' . $this->getType() . ') defined in database.',
311 $flabel = $this->flabel
;
312 $fprio = $this->fthird
;
314 foreach ($results as $r) {
315 $list[$r->$pk] = array(
316 'name' => _T($r->$flabel),
317 'extra' => $r->$fprio
322 } catch (Throwable
$e) {
324 'Cannot list entries (' . $this->getType() .
325 ') | ' . $e->getMessage(),
335 * @param integer $id Entry ID
337 * @return mixed|false Row if succeed ; false: no such id
339 public function get($id)
341 if (!is_numeric($id)) {
342 $this->errors
[] = _T("ID must be an integer!");
347 $select = $this->zdb
->select($this->table
);
348 $select->where($this->fpk
. '=' . $id);
350 $results = $this->zdb
->execute($select);
351 $result = $results->current();
354 $this->errors
[] = _T("Label does not exist");
359 } catch (Throwable
$e) {
361 __METHOD__
. ' | ' . $e->getMessage(),
371 * @param integer $id Id
372 * @param boolean $translated Do we want translated or original label?
377 public function getLabel($id, $translated = true)
379 $res = $this->get($id);
380 if ($res === false) {
381 //get() already logged
382 return self
::ID_NOT_EXITS
;
384 $field = $this->flabel
;
385 return ($translated) ?
_T($res->$field) : $res->$field;
389 * Get an ID from a label
391 * @param string $label The label
393 * @return int|false Return id if it exists false otherwise
395 public function getIdByLabel($label)
399 $select = $this->zdb
->select($this->table
);
400 $select->columns(array($pk))
401 ->where(array($this->flabel
=> $label));
403 $results = $this->zdb
->execute($select);
404 $result = $results->current();
410 } catch (Throwable
$e) {
412 'Unable to retrieve ' . $this->getType() . ' from label `' .
413 $label . '` | ' . $e->getMessage(),
423 * @param string $label The label
424 * @param integer $extra Extra values (priority for statuses,
425 * extension for contributions types, ...)
427 * @return integer id if success ; -1 : DB error ; -2 : label already exists
429 public function add($label, $extra)
432 $ret = $this->getIdByLabel($label);
434 if ($ret !== false) {
436 $this->getType() . ' with label `' . $label . '` already exists',
443 $this->zdb
->connection
->beginTransaction();
445 $this->flabel
=> $label,
446 $this->fthird
=> $extra
449 $insert = $this->zdb
->insert($this->table
);
450 $insert->values($values);
452 $ret = $this->zdb
->execute($insert);
454 if ($ret->count() > 0) {
456 'New ' . $this->getType() . ' `' . $label .
457 '` added successfully.',
461 $this->id
= $this->zdb
->getLastGeneratedValue($this);
463 $this->addTranslation($label);
465 throw new \
Exception('New ' . $this->getType() . ' not added.');
467 $this->zdb
->connection
->commit();
469 } catch (Throwable
$e) {
470 $this->zdb
->connection
->rollBack();
472 'Unable to add new entry `' . $label . '` | ' .
481 * Update in database.
483 * @param integer $id Entry ID
484 * @param string $label The label
485 * @param integer $extra Extra values (priority for statuses,
486 * extension for contributions types, ...)
488 * @return ID_NOT_EXITS|boolean
490 public function update($id, $label, $extra)
492 $ret = $this->get($id);
494 /* get() already logged and set $this->error. */
495 return self
::ID_NOT_EXITS
;
498 $class = get_class($this);
501 $oldlabel = $ret->{$this->flabel
};
502 $this->zdb
->connection
->beginTransaction();
504 $this->flabel
=> $label,
505 $this->fthird
=> $extra
508 $update = $this->zdb
->update($this->table
);
509 $update->set($values);
510 $update->where($this->fpk
. ' = ' . $id);
512 $ret = $this->zdb
->execute($update);
514 if ($oldlabel != $label) {
515 $this->deleteTranslation($oldlabel);
516 $this->addTranslation($label);
520 $this->getType() . ' #' . $id . ' updated successfully.',
523 $this->zdb
->connection
->commit();
525 } catch (Throwable
$e) {
526 $this->zdb
->connection
->rollBack();
528 'Unable to update ' . $this->getType() . ' #' . $id . ' | ' .
539 * @param integer $id Entry ID
541 * @return ID_NOT_EXITS|boolean
543 public function delete($id)
545 $ret = $this->get($id);
547 /* get() already logged */
548 return self
::ID_NOT_EXITS
;
551 if ($this->isUsed($id)) {
552 $this->errors
[] = _T("Cannot delete this label: it's still used");
557 $this->zdb
->connection
->beginTransaction();
558 $delete = $this->zdb
->delete($this->table
);
559 $delete->where($this->fpk
. ' = ' . $id);
561 $this->zdb
->execute($delete);
562 $this->deleteTranslation($ret->{$this->flabel
});
565 $this->getType() . ' ' . $id . ' deleted successfully.',
569 $this->zdb
->connection
->commit();
571 } catch (Throwable
$e) {
572 $this->zdb
->connection
->rollBack();
574 'Unable to delete ' . $this->getType() . ' ' . $id .
575 ' | ' . $e->getMessage(),
583 * Check if this entry is used.
585 * @param integer $id Entry ID
589 public function isUsed($id)
592 $select = $this->zdb
->select($this->used
);
593 $select->where($this->fpk
. ' = ' . $id);
595 $results = $this->zdb
->execute($select);
596 $result = $results->current();
598 if ($result !== null) {
603 } catch (Throwable
$e) {
605 'Unable to check if ' . $this->getType
. ' `' . $id .
606 '` is used. | ' . $e->getMessage(),
609 //in case of error, we consider that it is used, to avoid errors
615 * Get textual type representation
619 abstract protected function getType();
622 * Get translated textual representation
626 abstract public function getI18nType();
629 * Global getter method
631 * @param string $name name of the property we want to retrive
633 * @return false|object the called property
635 public function __get($name)
637 $forbidden = array();
638 $virtuals = array('extension', 'libelle');
640 in_array($name, $virtuals)
641 ||
!in_array($name, $forbidden)
642 && isset($this->$name)
646 return _T($this->label
);
665 public function getErrors(): array
667 return $this->errors
;