3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * Dynamic fields handle, aggregating field descriptors and values
10 * Copyright © 2011-2014 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 2011-2014 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
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.7dev - 2011-06-20
38 namespace Galette\Entity
;
41 use Laminas\Db\Sql\Expression
;
42 use Laminas\Db\Sql\Predicate\Expression
as PredicateExpression
;
44 use Galette\Core\Login
;
45 use Galette\Core\Authentication
;
46 use Galette\DynamicFields\Separator
;
47 use Galette\DynamicFields\Text
;
48 use Galette\DynamicFields\Line
;
49 use Galette\DynamicFields\Choice
;
50 use Galette\DynamicFields\Date
;
51 use Galette\DynamicFields\Boolean
;
52 use Galette\DynamicFields\File
;
53 use Galette\DynamicFields\DynamicField
;
54 use Galette\Repository\DynamicFieldsSet
;
57 * Dynamic fields handle, aggregating field descriptors and values
59 * @name DynamicFieldsHandle
63 * @author Johan Cwiklinski <johan@x-tnd.be>
64 * @copyright 2011-2014 The Galette Team
65 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
66 * @link http://galette.tuxfamily.org
69 class DynamicFieldsHandle
71 const TABLE
= 'dynamic_fields';
73 private $dynamic_fields = [];
74 private $current_values = [];
78 private $errors = array();
86 private $has_changed = false;
91 * @param Db $zdb Database instance
92 * @param Login $login Login instance
93 * @param mixed $instance Object instance
95 public function __construct(Db
$zdb, Login
$login, $instance = null)
98 $this->login
= $login;
99 if ($instance !== null) {
100 $this->load($instance);
105 * Load dynamic fields values for specified object
107 * @param mixed $object Object instance
109 * @return array|false
111 public function load($object)
113 switch (get_class($object)) {
114 case 'Galette\Entity\Adherent':
115 $this->form_name
= 'adh';
117 case 'Galette\Entity\Contribution':
118 $this->form_name
= 'contrib';
120 case 'Galette\Entity\Transaction':
121 $this->form_name
= 'trans';
124 throw new \
RuntimeException('Class ' . get_class($object) . ' does not handle dynamic fields!');
129 $this->item_id
= $object->id
;
130 $fields = new DynamicFieldsSet($this->zdb
, $this->login
);
131 $this->dynamic_fields
= $fields->getList($this->form_name
);
133 $results = $this->getCurrentFields();
135 if ($results->count() > 0) {
138 foreach ($results as $f) {
139 if (isset($this->dynamic_fields
[$f->{DynamicField
::PK
}])) {
140 $field = $this->dynamic_fields
[$f->{DynamicField
::PK
}];
141 if ($field->hasFixedValues()) {
142 $choices = $field->getValues();
143 $f['text_val'] = $choices[$f->field_val
];
145 $this->current_values
[$f->{DynamicField
::PK
}][] = array_filter(
148 return $k != DynamicField
::PK
;
154 'Dynamic values found for ' . get_class($object) . ' #' . $this->item_id
.
155 '; but no dynamic field configured!',
164 } catch (\Exception
$e) {
166 __METHOD__
. ' | ' . $e->getMessage(),
178 public function getErrors()
180 return $this->errors
;
188 public function getFields()
190 return $this->dynamic_fields
;
196 * @param integer $field Field ID
200 public function getValues($field)
202 if (!isset($this->current_values
[$field])) {
203 $this->current_values
[$field][] = [
205 'field_form' => $this->dynamic_fields
[$field]->getForm(),
211 return $this->current_values
[$field];
217 * @param integer $item Item ID
218 * @param integer $field Field ID
219 * @param integer $index Value index
220 * @param mixed $value Value
224 public function setValue($item, $field, $index, $value)
227 if (isset($this->current_values
[$field][$idx])) {
228 $this->current_values
[$field][$idx]['field_val'] = $value;
230 $this->current_values
[$field][$idx] = [
232 'field_form' => $this->dynamic_fields
[$field]->getForm(),
233 'val_index' => $index,
234 'field_val' => $value,
243 * @param integer $item Item ID
244 * @param integer $field Field ID
245 * @param integer $index Value index
249 public function unsetValue($item, $field, $index)
252 if (isset($this->current_values
[$field][$idx])) {
253 unset($this->current_values
[$field][$idx]);
260 * @param integer $item_id Curent item id to use (will be used if current item_id is 0)
261 * @param boolean $transaction True if a transaction already exists
265 public function storeValues($item_id = null, $transaction = false)
268 if ($item_id !== null && ($this->item_id
== null ||
$this->item_id
== 0)) {
269 $this->item_id
= $item_id;
272 $this->zdb
->connection
->beginTransaction();
275 $this->handleRemovals();
277 foreach ($this->current_values
as $field_id => $values) {
278 foreach ($values as $value) {
279 $value[DynamicField
::PK
] = $field_id;
280 if ($value['item_id'] == 0) {
281 $value['item_id'] = $this->item_id
;
284 if (isset($value['is_new'])) {
285 if ($this->insert_stmt
=== null) {
286 $insert = $this->zdb
->insert(self
::TABLE
);
288 'item_id' => ':item_id',
289 'field_id' => ':field_id',
290 'field_form' => ':field_form',
291 'val_index' => ':val_index',
292 'field_val' => ':field_val'
294 $this->insert_stmt
= $this->zdb
->sql
->prepareStatementForSqlObject($insert);
296 unset($value['is_new']);
297 $this->insert_stmt
->execute($value);
298 $this->has_changed
= true;
300 if ($this->update_stmt
=== null) {
301 $update = $this->zdb
->update(self
::TABLE
);
303 'field_val' => ':field_val',
304 'val_index' => ':val_index'
306 'item_id' => ':item_id',
307 'field_id' => ':field_id',
308 'field_form' => ':field_form',
309 'val_index' => ':val_index'
311 $this->update_stmt
= $this->zdb
->sql
->prepareStatementForSqlObject($update);
314 'field_val' => $value['field_val'],
315 'val_index' => $value['val_index'],
316 'where1' => $value['item_id'],
317 'where2' => $value['field_id'],
318 'where3' => $value['field_form'],
319 'where4' => isset($value['old_val_index']) ?
320 $value['old_val_index'] : $value['val_index']
322 $this->update_stmt
->execute($params);
323 $this->has_changed
= true;
329 $this->zdb
->connection
->commit();
332 } catch (\Exception
$e) {
334 $this->zdb
->connection
->rollBack();
339 'An error occurred storing dynamic field. Form name: ' . $this->form_name
.
340 ' | Error was: ' . $e->getMessage(),
345 unset($this->update_stmt
);
346 unset($this->insert_stmt
);
351 * Handle values that have been removed
355 private function handleRemovals()
357 $fields = new DynamicFieldsSet($this->zdb
, $this->login
);
358 $this->dynamic_fields
= $fields->getList($this->form_name
, $this->login
);
360 $results = $this->getCurrentFields();
363 if ($results->count() > 0) {
364 foreach ($results as $result) {
365 $fromdb[$result->field_id
. '_' . $result->val_index
] = [
366 'where1' => $this->item_id
,
367 'where2' => $this->form_name
,
368 'where3' => $result->field_id
,
369 'where4' => $result->val_index
374 if (!count($fromdb)) {
375 //no entry in database, nothing to do.
379 foreach ($this->current_values
as $field_id => $values) {
380 foreach ($values as $value) {
381 $key = $field_id . '_' . $value['val_index'];
382 if (isset($fromdb[$key])) {
383 unset($fromdb[$key]);
388 if (count($fromdb)) {
389 foreach ($fromdb as $entry) {
390 if ($this->delete_stmt
=== null) {
391 $delete = $this->zdb
->delete(self
::TABLE
);
393 'item_id' => ':item_id',
394 'field_form' => ':field_form',
395 'field_id' => ':field_id',
396 'val_index' => ':val_index'
398 $this->delete_stmt
= $this->zdb
->sql
->prepareStatementForSqlObject($delete);
400 $this->delete_stmt
->execute($entry);
402 $field_id = $entry['where3'];
404 isset($this->current_values
[$field_id])
405 && count($this->current_values
[$field_id])
407 $val_index = (int)$entry['where4'];
408 foreach ($this->current_values
[$field_id] as &$current) {
409 if ((int)$current['val_index'] === $val_index +
1) {
410 $current['val_index'] = $val_index;
412 $current['old_val_index'] = $val_index;
417 $this->has_changed
= true;
422 * Is there any change in dynamic filelds?
426 public function hasChanged()
428 return $this->has_changed
;
434 * @param integer $item_id Curent item id to use (will be used if current item_id is 0)
435 * @param boolean $transaction True if a transaction already exists
439 public function removeValues($item_id = null, $transaction = false)
442 if ($item_id !== null && ($this->item_id
== null ||
$this->item_id
== 0)) {
443 $this->item_id
= $item_id;
446 $this->zdb
->connection
->beginTransaction();
449 $delete = $this->zdb
->delete(self
::TABLE
);
452 'item_id' => $this->item_id
,
453 'field_form' => $this->form_name
456 $this->zdb
->execute($delete);
459 $this->zdb
->connection
->commit();
462 } catch (\Exception
$e) {
464 $this->zdb
->connection
->rollBack();
469 'An error occurred removing dynamic field. Form name: ' . $this->form_name
.
470 ' | Error was: ' . $e->getMessage(),
478 * Get current fields resultset
482 protected function getCurrentFields()
484 $select = $this->zdb
->select(self
::TABLE
, 'd');
486 array('t' => PREFIX_DB
. DynamicField
::TABLE
),
487 'd.' . DynamicField
::PK
. '=t.' . DynamicField
::PK
,
491 'item_id' => $this->item_id
,
492 'd.field_form' => $this->form_name
496 /** only load values for accessible fields*/
497 $accessible_fields = [];
498 $access_level = $this->login
->getAccessLevel();
500 foreach ($this->dynamic_fields
as $field) {
501 $perm = $field->getPerm();
503 ($perm == DynamicField
::PERM_MANAGER
&&
504 $access_level < Authentication
::ACCESS_MANAGER
) ||
505 ($perm == DynamicField
::PERM_STAFF
&&
506 $access_level < Authentication
::ACCESS_STAFF
) ||
507 ($perm == DynamicField
::PERM_ADMIN
&&
508 $access_level < Authentication
::ACCESS_ADMIN
)
512 $accessible_fields[] = $field->getId();
515 if (count($accessible_fields)) {
516 $select->where
->in('d.' . DynamicField
::PK
, $accessible_fields);
519 $results = $this->zdb
->execute($select);