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
;
42 use Laminas\Db\Adapter\Adapter
;
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);
138 throw new \
RuntimeException(
139 'Unknown ID ' . $id . '!'
142 } catch (Throwable
$e) {
144 'Cannot load ' . $this->getType() . ' from id `' . $id . '` | ' .
153 * Populate object from a resultset row
155 * @param ResultSet $r the resultset row
159 private function loadFromRS($r)
163 $flabel = $this->flabel
;
164 $this->label
= $r->$flabel;
165 $fthird = $this->fthird
;
166 $this->third
= $r->$fthird;
170 * Set defaults at install time
172 * @return boolean|Exception
174 public function installInit()
176 $class = get_class($this);
179 //first, we drop all values
180 $delete = $this->zdb
->delete($this->table
);
181 $this->zdb
->execute($delete);
184 foreach ($class::$fields as $key => $f) {
185 $values[$f] = ':' . $key;
188 $insert = $this->zdb
->insert($this->table
);
189 $insert->values($values);
190 $stmt = $this->zdb
->sql
->prepareStatementForSqlObject($insert);
192 $this->zdb
->handleSequence(
194 count(static::$defaults)
197 $fnames = array_values($values);
198 foreach ($class::$defaults as $d) {
200 if (isset($d['priority'])) {
201 $val = $d['priority'];
203 $val = $d['extension'];
208 $fnames[0] => $d['id'],
209 $fnames[1] => $d['libelle'],
216 'Defaults (' . $this->getType() .
217 ') were successfully stored into database.',
221 } catch (Throwable
$e) {
223 'Unable to initialize defaults (' . $this->getType() . ').' .
232 * Get list in an array built as:
233 * $array[id] = "translated label"
235 * @param boolean|null $extent Filter on (non) cotisations types
237 * @return array|false
239 public function getList(bool $extent = null)
244 $select = $this->zdb
->select($this->table
);
245 $fields = array($this->fpk
, $this->flabel
);
247 $this->order_field
!== false
248 && $this->order_field
!== $this->fpk
249 && $this->order_field
!== $this->flabel
251 $fields[] = $this->order_field
;
253 $select->quantifier('DISTINCT');
254 $select->columns($fields);
256 if ($this->order_field
!== false) {
257 $select->order($this->order_field
, $this->fpk
);
259 if ($extent !== null) {
260 if ($extent === true) {
261 $select->where(array($this->fthird
=> new Expression('true')));
262 } elseif ($extent === false) {
263 $select->where(array($this->fthird
=> new Expression('false')));
267 $results = $this->zdb
->execute($select);
269 foreach ($results as $r) {
271 $flabel = $this->flabel
;
272 $list[$r->$fpk] = _T($r->$flabel);
275 } catch (Throwable
$e) {
277 __METHOD__
. ' | ' . $e->getMessage(),
287 * @return array of all objects if succeeded, false otherwise
289 public function getCompleteList()
294 $select = $this->zdb
->select($this->table
);
295 if ($this->order_field
!== false) {
296 $select->order(array($this->order_field
, $this->fpk
));
299 $results = $this->zdb
->execute($select);
301 if ($results->count() == 0) {
303 'No entries (' . $this->getType() . ') defined in database.',
308 $flabel = $this->flabel
;
309 $fprio = $this->fthird
;
311 foreach ($results as $r) {
312 $list[$r->$pk] = array(
313 'name' => _T($r->$flabel),
314 'extra' => $r->$fprio
319 } catch (Throwable
$e) {
321 'Cannot list entries (' . $this->getType() .
322 ') | ' . $e->getMessage(),
332 * @param integer $id Entry ID
334 * @return mixed|false Row if succeed ; false: no such id
336 public function get($id)
338 if (!is_numeric($id)) {
339 $this->errors
[] = _T("ID must be an integer!");
344 $select = $this->zdb
->select($this->table
);
345 $select->where($this->fpk
. '=' . $id);
347 $results = $this->zdb
->execute($select);
348 $result = $results->current();
351 $this->errors
[] = _T("Label does not exist");
356 } catch (Throwable
$e) {
358 __METHOD__
. ' | ' . $e->getMessage(),
368 * @param integer $id Id
369 * @param boolean $translated Do we want translated or original label?
374 public function getLabel($id, $translated = true)
376 $res = $this->get($id);
377 if ($res === false) {
379 return self
::ID_NOT_EXITS
;
381 $field = $this->flabel
;
382 return ($translated) ?
_T($res->$field) : $res->$field;
386 * Get an ID from a label
388 * @param string $label The label
390 * @return int|false Return id if it exists false otherwise
392 public function getIdByLabel($label)
396 $select = $this->zdb
->select($this->table
);
397 $select->columns(array($pk))
398 ->where(array($this->flabel
=> $label));
400 $results = $this->zdb
->execute($select);
401 $result = $results->current();
407 } catch (Throwable
$e) {
409 'Unable to retrieve ' . $this->getType() . ' from label `' .
410 $label . '` | ' . $e->getMessage(),
420 * @param string $label The label
421 * @param integer $extra Extra values (priority for statuses,
422 * extension for contributions types, ...)
424 * @return integer id if success ; -1 : DB error ; -2 : label already exists
426 public function add($label, $extra)
429 $ret = $this->getIdByLabel($label);
431 if ($ret !== false) {
433 $this->getType() . ' with label `' . $label . '` already exists',
440 $this->zdb
->connection
->beginTransaction();
442 $this->flabel
=> $label,
443 $this->fthird
=> $extra
446 $insert = $this->zdb
->insert($this->table
);
447 $insert->values($values);
449 $ret = $this->zdb
->execute($insert);
451 if ($ret->count() > 0) {
453 'New ' . $this->getType() . ' `' . $label .
454 '` added successfully.',
458 $this->id
= $this->zdb
->getLastGeneratedValue($this);
460 $this->addTranslation($label);
462 throw new \
Exception('New ' . $this->getType() . ' not added.');
464 $this->zdb
->connection
->commit();
466 } catch (Throwable
$e) {
467 $this->zdb
->connection
->rollBack();
469 'Unable to add new entry `' . $label . '` | ' .
478 * Update in database.
480 * @param integer $id Entry ID
481 * @param string $label The label
482 * @param integer $extra Extra values (priority for statuses,
483 * extension for contributions types, ...)
485 * @return ID_NOT_EXITS|boolean
487 public function update($id, $label, $extra)
489 $ret = $this->get($id);
491 /* get() already logged and set $this->error. */
492 return self
::ID_NOT_EXITS
;
495 $class = get_class($this);
498 $oldlabel = $ret->{$this->flabel
};
499 $this->zdb
->connection
->beginTransaction();
501 $this->flabel
=> $label,
502 $this->fthird
=> $extra
505 $update = $this->zdb
->update($this->table
);
506 $update->set($values);
507 $update->where($this->fpk
. ' = ' . $id);
509 $ret = $this->zdb
->execute($update);
511 if ($oldlabel != $label) {
512 $this->deleteTranslation($oldlabel);
513 $this->addTranslation($label);
517 $this->getType() . ' #' . $id . ' updated successfully.',
520 $this->zdb
->connection
->commit();
522 } catch (Throwable
$e) {
523 $this->zdb
->connection
->rollBack();
525 'Unable to update ' . $this->getType() . ' #' . $id . ' | ' .
536 * @param integer $id Entry ID
538 * @return ID_NOT_EXITS|boolean
540 public function delete($id)
542 $ret = $this->get($id);
544 /* get() already logged */
545 return self
::ID_NOT_EXITS
;
548 if ($this->isUsed($id)) {
549 $this->errors
[] = _T("Cannot delete this label: it's still used");
554 $this->zdb
->connection
->beginTransaction();
555 $delete = $this->zdb
->delete($this->table
);
556 $delete->where($this->fpk
. ' = ' . $id);
558 $this->zdb
->execute($delete);
559 $this->deleteTranslation($ret->{$this->flabel
});
562 $this->getType() . ' ' . $id . ' deleted successfully.',
566 $this->zdb
->connection
->commit();
568 } catch (Throwable
$e) {
569 $this->zdb
->connection
->rollBack();
571 'Unable to delete ' . $this->getType() . ' ' . $id .
572 ' | ' . $e->getMessage(),
580 * Check if this entry is used.
582 * @param integer $id Entry ID
586 public function isUsed($id)
589 $select = $this->zdb
->select($this->used
);
590 $select->where($this->fpk
. ' = ' . $id);
592 $results = $this->zdb
->execute($select);
593 $result = $results->current();
595 if ($result !== null) {
600 } catch (Throwable
$e) {
602 'Unable to check if ' . $this->getType
. ' `' . $id .
603 '` is used. | ' . $e->getMessage(),
606 //in case of error, we consider that it is used, to avoid errors
612 * Get textual type representation
616 abstract protected function getType();
619 * Get translated textual representation
623 abstract public function getI18nType();
626 * Global getter method
628 * @param string $name name of the property we want to retrive
630 * @return false|object the called property
632 public function __get($name)
634 $forbidden = array();
635 $virtuals = array('extension', 'libelle');
637 in_array($name, $virtuals)
638 ||
!in_array($name, $forbidden)
639 && isset($this->$name)
643 return _T($this->label
);
662 public function getErrors(): array
664 return $this->errors
;