]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Entity/FieldsConfig.php
580802e96bdd7796155e82fbcffa4ae5c4faf601
[galette.git] / galette / lib / Galette / Entity / FieldsConfig.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Fields config handling
7 *
8 * PHP version 5
9 *
10 * Copyright © 2009-2020 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 2009-2020 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 - 2009-03-26
35 */
36
37 namespace Galette\Entity;
38
39 use ArrayObject;
40 use Throwable;
41 use Analog\Analog;
42 use Laminas\Db\Adapter\Adapter;
43 use Galette\Core\Db;
44 use Galette\Core\Login;
45 use Galette\Core\Authentication;
46
47 /**
48 * Fields config class for galette :
49 * defines fields visibility for lists and forms
50 * defines fields order and requirement flag for forms
51 *
52 * @category Entity
53 * @name FieldsConfig
54 * @package Galette
55 * @author Johan Cwiklinski <johan@x-tnd.be>
56 * @copyright 2009-2020 The Galette Team
57 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
58 * @link http://galette.tuxfamily.org
59 * @since Available since 0.7dev - 2009-03-26
60 */
61 class FieldsConfig
62 {
63 public const NOBODY = 0;
64 public const USER_WRITE = 1;
65 public const ADMIN = 2;
66 public const STAFF = 3;
67 public const MANAGER = 4;
68 public const USER_READ = 5;
69
70 public const TYPE_STR = 0;
71 public const TYPE_HIDDEN = 1;
72 public const TYPE_BOOL = 2;
73 public const TYPE_INT = 3;
74 public const TYPE_DEC = 4;
75 public const TYPE_DATE = 5;
76 public const TYPE_TXT = 6;
77 public const TYPE_PASS = 7;
78 public const TYPE_EMAIL = 8;
79 public const TYPE_URL = 9;
80 public const TYPE_RADIO = 10;
81 public const TYPE_SELECT = 11;
82
83 protected $zdb;
84 protected $core_db_fields = array();
85 protected $all_required = array();
86 protected $all_visibles = array();
87 protected $categorized_fields = array();
88 protected $table;
89 protected $defaults = null;
90 protected $cats_defaults = null;
91
92 private $staff_fields = array(
93 'activite_adh',
94 'id_statut',
95 'bool_exempt_adh',
96 'date_crea_adh',
97 'info_adh'
98 );
99 private $admin_fields = array(
100 'bool_admin_adh'
101 );
102
103 public const TABLE = 'fields_config';
104
105 /*
106 * Fields that are not visible in the
107 * form should not be visible here.
108 */
109 private $non_required = array(
110 'id_adh',
111 'date_echeance',
112 'bool_display_info',
113 'bool_exempt_adh',
114 'bool_admin_adh',
115 'activite_adh',
116 'date_crea_adh',
117 'date_modif_adh',
118 //Fields we do not want to be set as required
119 'societe_adh',
120 'id_statut',
121 'pref_lang',
122 'sexe_adh',
123 'parent_id'
124 );
125
126 private $non_form_elements = array(
127 'date_echeance',
128 'date_modif_adh'
129 );
130
131 private $non_display_elements = array(
132 'date_echeance',
133 'mdp_adh',
134 'titre_adh',
135 'sexe_adh',
136 'prenom_adh',
137 'adresse2_adh'
138 );
139
140 /**
141 * Default constructor
142 *
143 * @param Db $zdb Database
144 * @param string $table the table for which to get fields configuration
145 * @param array $defaults default values
146 * @param array $cats_defaults default categories values
147 * @param boolean $install Are we calling from installer?
148 */
149 public function __construct(Db $zdb, string $table, array $defaults, array $cats_defaults, bool $install = false)
150 {
151 $this->zdb = $zdb;
152 $this->table = $table;
153 $this->defaults = $defaults;
154 $this->cats_defaults = $cats_defaults;
155 //prevent check at install time...
156 if (!$install) {
157 $this->load();
158 $this->checkUpdate();
159 }
160 }
161
162 /**
163 * Load current fields configuration from database.
164 *
165 * @return boolean
166 */
167 public function load()
168 {
169 try {
170 $select = $this->zdb->select(self::TABLE);
171 $select
172 ->where(array('table_name' => $this->table))
173 ->order(array(FieldsCategories::PK, 'position ASC'));
174
175 $results = $this->zdb->execute($select);
176 $this->core_db_fields = [];
177
178 foreach ($results as $k) {
179 $field = $this->buildField($k);
180 $this->core_db_fields[$k->field_id] = $field;
181 }
182
183 $this->buildLists();
184 return true;
185 } catch (Throwable $e) {
186 Analog::log(
187 'Fields configuration cannot be loaded!',
188 Analog::URGENT
189 );
190 throw $e;
191 }
192 }
193
194 /**
195 * Prepare a field (required data, automation)
196 *
197 * @param ArrayObject $rset DB ResultSet row
198 *
199 * @return ArrayObject
200 */
201 protected function prepareField(ArrayObject $rset): ArrayObject
202 {
203 if ($rset->field_id === 'parent_id') {
204 $rset->readonly = true;
205 $rset->required = false;
206 }
207 return $rset;
208 }
209
210 /**
211 * Prepare a field (required data, automation)
212 *
213 * @param ArrayObject $rset DB ResultSet row
214 *
215 * @return array
216 */
217 protected function buildField(ArrayObject $rset): array
218 {
219 $rset = $this->prepareField($rset);
220 $f = array(
221 'field_id' => $rset->field_id,
222 'label' => $this->defaults[$rset->field_id]['label'],
223 'category' => (int)$rset->id_field_category,
224 'visible' => (int)$rset->visible,
225 'required' => (bool)$rset->required,
226 'propname' => $this->defaults[$rset->field_id]['propname'],
227 'position' => (int)$rset->position,
228 'disabled' => false
229 );
230 return $f;
231 }
232
233 /**
234 * Create field array configuration,
235 * Several lists of fields are kept (visible, requireds, etc), build them.
236 *
237 * @return void
238 */
239 protected function buildLists()
240 {
241
242 $this->categorized_fields = [];
243 $this->all_required = [];
244 $this->all_visibles = [];
245
246 foreach ($this->core_db_fields as $field) {
247 $this->addToLists($field);
248 }
249 }
250
251 /**
252 * Adds a field to lists
253 *
254 * @param array $field Field values
255 *
256 * @return void
257 */
258 protected function addToLists(array $field)
259 {
260 if ($field['position'] >= 0) {
261 $this->categorized_fields[$field['category']][] = $field;
262 }
263
264 //array of all required fields
265 if ($field['required']) {
266 $this->all_required[$field['field_id']] = $field['required'];
267 }
268
269 //array of all fields visibility
270 $this->all_visibles[$field['field_id']] = $field['visible'];
271 }
272
273 /**
274 * Is a field set as required?
275 *
276 * @param string $field Field name
277 *
278 * @return boolean
279 */
280 public function isRequired($field)
281 {
282 return isset($this->all_required[$field]);
283 }
284
285 /**
286 * Temporary set a field as not required
287 * (password for existing members for example)
288 *
289 * @param string $field Field name
290 *
291 * @return void
292 */
293 public function setNotRequired($field)
294 {
295 if (isset($this->all_required[$field])) {
296 unset($this->all_required[$field]);
297 }
298
299 foreach ($this->categorized_fields as &$cat) {
300 foreach ($cat as &$f) {
301 if ($f['field_id'] === $field) {
302 $f['required'] = false;
303 return;
304 }
305 }
306 }
307 }
308
309 /**
310 * Checks if all fields are present in the database.
311 *
312 * For now, this function only checks if count matches.
313 *
314 * @return void
315 */
316 private function checkUpdate()
317 {
318 $class = get_class($this);
319
320 try {
321 $_all_fields = array();
322 if (count($this->core_db_fields)) {
323 array_walk(
324 $this->core_db_fields,
325 function ($field) use (&$_all_fields) {
326 $_all_fields[$field['field_id']] = $field;
327 }
328 );
329 } else {
330 //hum... no records. Let's check if any category exists
331 $select = $this->zdb->select(FieldsCategories::TABLE);
332 $results = $this->zdb->execute($select);
333
334 if ($results->count() == 0) {
335 //categories are missing, add them
336 $categories = new FieldsCategories($this->zdb, $this->cats_defaults);
337 $categories->installInit();
338 }
339 }
340
341 if (count($this->defaults) != count($_all_fields)) {
342 Analog::log(
343 'Fields configuration count for `' . $this->table .
344 '` columns does not match records. Is : ' .
345 count($_all_fields) . ' and should be ' .
346 count($this->defaults),
347 Analog::WARNING
348 );
349
350 $params = array();
351 foreach ($this->defaults as $k => $f) {
352 if (!isset($_all_fields[$k])) {
353 Analog::log(
354 'Missing field configuration for field `' . $k . '`',
355 Analog::INFO
356 );
357 $params[] = array(
358 'field_id' => $k,
359 'table_name' => $this->table,
360 'required' => $f['required'],
361 'visible' => $f['visible'],
362 'position' => $f['position'],
363 'category' => $f['category'],
364 'list_visible' => $f['list_visible'] ?? false,
365 'list_position' => $f['list_position'] ?? null
366 );
367 }
368 }
369
370 if (count($params) > 0) {
371 $this->insert($params);
372 $this->load();
373 }
374 }
375 } catch (Throwable $e) {
376 Analog::log(
377 '[' . $class . '] An error occurred while checking update for ' .
378 'fields configuration for table `' . $this->table . '`. ' .
379 $e->getMessage(),
380 Analog::ERROR
381 );
382 throw $e;
383 }
384 }
385
386 /**
387 * Set default fields configuration at install time. All previous
388 * existing values will be dropped first, including fields categories.
389 *
390 * @return boolean|\Exception
391 */
392 public function installInit()
393 {
394 try {
395 $fields = array_keys($this->defaults);
396 $categories = new FieldsCategories($this->zdb, $this->cats_defaults);
397
398 //first, we drop all values
399 $delete = $this->zdb->delete(self::TABLE);
400 $delete->where(
401 array('table_name' => $this->table)
402 );
403 $this->zdb->execute($delete);
404 //take care of fields categories, for db relations
405 $categories->installInit($this->zdb);
406
407 $fields = array_keys($this->defaults);
408 foreach ($fields as $f) {
409 //build default config for each field
410 $params[] = array(
411 'field_id' => $f,
412 'table_name' => $this->table,
413 'required' => $this->defaults[$f]['required'],
414 'visible' => $this->defaults[$f]['visible'],
415 'position' => (int)$this->defaults[$f]['position'],
416 'category' => $this->defaults[$f]['category'],
417 'list_visible' => $this->defaults[$f]['list_visible'] ?? false,
418 'list_position' => $this->defaults[$f]['list_position'] ?? -1
419 );
420 }
421 $this->insert($params);
422
423 Analog::log(
424 'Default fields configuration were successfully stored.',
425 Analog::INFO
426 );
427 return true;
428 } catch (Throwable $e) {
429 Analog::log(
430 'Unable to initialize default fields configuration.' . $e->getMessage(),
431 Analog::ERROR
432 );
433
434 throw $e;
435 }
436 }
437
438 /**
439 * Get non required fields
440 *
441 * @return array
442 */
443 public function getNonRequired()
444 {
445 return $this->non_required;
446 }
447
448 /**
449 * Retrieve form elements
450 *
451 * @param Login $login Login instance
452 * @param boolean $new True when adding a new member
453 * @param boolean $selfs True if we're called from self subscription page
454 *
455 * @return array
456 */
457 public function getFormElements(Login $login, $new, $selfs = false)
458 {
459 global $preferences;
460
461 $hidden_elements = [];
462 $form_elements = [];
463
464 //get columns descriptions
465 $columns = $this->zdb->getColumns($this->table);
466
467 $access_level = $login->getAccessLevel();
468 $categories = FieldsCategories::getList($this->zdb);
469 try {
470 foreach ($categories as $c) {
471 $cpk = FieldsCategories::PK;
472 $cat_label = null;
473 foreach ($this->cats_defaults as $conf_cat) {
474 if ($conf_cat['id'] == $c->$cpk) {
475 $cat_label = $conf_cat['category'];
476 break;
477 }
478 }
479 if ($cat_label === null) {
480 $cat_label = $c->category;
481 }
482 $cat = (object)array(
483 'id' => (int)$c->$cpk,
484 'label' => $cat_label,
485 'elements' => array()
486 );
487
488 $elements = $this->categorized_fields[$c->$cpk];
489 $cat->elements = array();
490
491 foreach ($elements as $elt) {
492 $o = (object)$elt;
493 $o->readonly = false;
494
495 if ($o->field_id == 'id_adh') {
496 // ignore access control, as member ID is always needed
497 if (!$preferences->pref_show_id || $new === true) {
498 $hidden_elements[] = $o;
499 } else {
500 $o->type = self::TYPE_STR;
501 $o->readonly = true;
502 $cat->elements[$o->field_id] = $o;
503 }
504 } elseif ($o->field_id == 'parent_id') {
505 $hidden_elements[] = $o;
506 } else {
507 // skip fields blacklisted for edition
508 if (
509 in_array($o->field_id, $this->non_form_elements)
510 || $selfs && $this->isSelfExcluded($o->field_id)
511 ) {
512 continue;
513 }
514
515 // skip fields according to access control
516 if (
517 $o->visible == self::NOBODY ||
518 ($o->visible == self::ADMIN &&
519 $access_level < Authentication::ACCESS_ADMIN) ||
520 ($o->visible == self::STAFF &&
521 $access_level < Authentication::ACCESS_STAFF) ||
522 ($o->visible == self::MANAGER &&
523 $access_level < Authentication::ACCESS_MANAGER)
524 ) {
525 continue;
526 }
527
528 if (preg_match('/date/', $o->field_id)) {
529 $o->type = self::TYPE_DATE;
530 } elseif (preg_match('/bool/', $o->field_id)) {
531 $o->type = self::TYPE_BOOL;
532 } elseif (
533 $o->field_id == 'titre_adh'
534 || $o->field_id == 'pref_lang'
535 || $o->field_id == 'id_statut'
536 ) {
537 $o->type = self::TYPE_SELECT;
538 } elseif ($o->field_id == 'sexe_adh') {
539 $o->type = self::TYPE_RADIO;
540 } else {
541 $o->type = self::TYPE_STR;
542 }
543
544 //retrieve field information from DB
545 foreach ($columns as $column) {
546 if ($column->getName() === $o->field_id) {
547 $o->max_length
548 = $column->getCharacterMaximumLength();
549 $o->default = $column->getColumnDefault();
550 $o->datatype = $column->getDataType();
551 break;
552 }
553 }
554
555 // disabled field according to access control
556 if (
557 $o->visible == self::USER_READ &&
558 $access_level == Authentication::ACCESS_USER
559 ) {
560 $o->disabled = true;
561 } else {
562 $o->disabled = false;
563 }
564
565 if ($selfs === true) {
566 //email, login and password are always required for self subscription
567 $srequireds = ['email_adh', 'login_adh'];
568 if (in_array($o->field_id, $srequireds)) {
569 $o->required = true;
570 }
571 }
572 $cat->elements[$o->field_id] = $o;
573 }
574 }
575
576 if (count($cat->elements) > 0) {
577 $form_elements[] = $cat;
578 }
579 }
580 return array(
581 'fieldsets' => $form_elements,
582 'hiddens' => $hidden_elements
583 );
584 } catch (Throwable $e) {
585 Analog::log(
586 'An error occurred getting form elements',
587 Analog::ERROR
588 );
589 throw $e;
590 }
591 }
592
593 /**
594 * Retrieve display elements
595 *
596 * @param Login $login Login instance
597 *
598 * @return array
599 */
600 public function getDisplayElements(Login $login)
601 {
602 global $preferences;
603
604 $display_elements = [];
605 $access_level = $login->getAccessLevel();
606 $categories = FieldsCategories::getList($this->zdb);
607 try {
608 foreach ($categories as $c) {
609 $cpk = FieldsCategories::PK;
610 $cat_label = null;
611 foreach ($this->cats_defaults as $conf_cat) {
612 if ($conf_cat['id'] == $c->$cpk) {
613 $cat_label = $conf_cat['category'];
614 break;
615 }
616 }
617 if ($cat_label === null) {
618 $cat_label = $c->category;
619 }
620 $cat = (object)array(
621 'id' => (int)$c->$cpk,
622 'label' => $cat_label,
623 'elements' => array()
624 );
625
626 $elements = $this->categorized_fields[$c->$cpk];
627 $cat->elements = array();
628
629 foreach ($elements as $elt) {
630 $o = (object)$elt;
631
632 if ($o->field_id == 'id_adh') {
633 // ignore access control, as member ID is always needed
634 if (!isset($preferences) || !$preferences->pref_show_id) {
635 $hidden_elements[] = $o;
636 } else {
637 $o->type = self::TYPE_STR;
638 $cat->elements[$o->field_id] = $o;
639 }
640 } else {
641 // skip fields blacklisted for display
642 if (in_array($o->field_id, $this->non_display_elements)) {
643 continue;
644 }
645
646 // skip fields according to access control
647 if (
648 $o->visible == self::NOBODY ||
649 ($o->visible == self::ADMIN &&
650 $access_level < Authentication::ACCESS_ADMIN) ||
651 ($o->visible == self::STAFF &&
652 $access_level < Authentication::ACCESS_STAFF) ||
653 ($o->visible == self::MANAGER &&
654 $access_level < Authentication::ACCESS_MANAGER)
655 ) {
656 continue;
657 }
658
659 $cat->elements[$o->field_id] = $o;
660 }
661 }
662
663 if (count($cat->elements) > 0) {
664 $display_elements[] = $cat;
665 }
666 }
667 return $display_elements;
668 } catch (Throwable $e) {
669 Analog::log(
670 'An error occurred getting display elements',
671 Analog::ERROR
672 );
673 throw $e;
674 }
675 }
676
677 /**
678 * Get required fields
679 *
680 * @return array of all required fields. Field names = keys
681 */
682 public function getRequired()
683 {
684 return $this->all_required;
685 }
686
687 /**
688 * Get visible fields
689 *
690 * @return array of all visibles fields
691 */
692 public function getVisibilities()
693 {
694 return $this->all_visibles;
695 }
696
697 /**
698 * Get visibility for specified field
699 *
700 * @param string $field The requested field
701 *
702 * @return boolean
703 */
704 public function getVisibility($field)
705 {
706 return $this->all_visibles[$field];
707 }
708
709 /**
710 * Get all fields with their categories
711 *
712 * @return array
713 */
714 public function getCategorizedFields()
715 {
716 return $this->categorized_fields;
717 }
718
719 /**
720 * Set fields
721 *
722 * @param array $fields categorized fields array
723 *
724 * @return boolean
725 */
726 public function setFields($fields)
727 {
728 $this->categorized_fields = $fields;
729 return $this->store();
730 }
731
732 /**
733 * Store config in database
734 *
735 * @return boolean
736 */
737 private function store()
738 {
739 $class = get_class($this);
740
741 try {
742 $this->zdb->connection->beginTransaction();
743
744 $update = $this->zdb->update(self::TABLE);
745 $update->set(
746 array(
747 'required' => ':required',
748 'visible' => ':visible',
749 'position' => ':position',
750 FieldsCategories::PK => ':' . FieldsCategories::PK
751 )
752 )->where(
753 array(
754 'field_id' => ':field_id',
755 'table_name' => $this->table
756 )
757 );
758 $stmt = $this->zdb->sql->prepareStatementForSqlObject($update);
759
760 $params = null;
761 foreach ($this->categorized_fields as $cat) {
762 foreach ($cat as $pos => $field) {
763 if (in_array($field['field_id'], $this->non_required)) {
764 $field['required'] = $this->zdb->isPostgres() ? 'false' : 0;
765 }
766
767 if ($field['field_id'] === 'parent_id') {
768 $field['visible'] = 0;
769 }
770
771 $params = array(
772 'required' => $field['required'],
773 'visible' => $field['visible'],
774 'position' => $pos,
775 FieldsCategories::PK => $field['category'],
776 'field_id' => $field['field_id']
777 );
778
779 $stmt->execute($params);
780 }
781 }
782
783 Analog::log(
784 '[' . $class . '] Fields configuration stored successfully! ',
785 Analog::DEBUG
786 );
787 Analog::log(
788 str_replace(
789 '%s',
790 $this->table,
791 '[' . $class . '] Fields configuration for table %s stored ' .
792 'successfully.'
793 ),
794 Analog::INFO
795 );
796
797 $this->zdb->connection->commit();
798 return $this->load();
799 } catch (Throwable $e) {
800 $this->zdb->connection->rollBack();
801 Analog::log(
802 '[' . $class . '] An error occurred while storing fields ' .
803 'configuration for table `' . $this->table . '`.' .
804 $e->getMessage(),
805 Analog::ERROR
806 );
807 Analog::log(
808 $e->getTraceAsString(),
809 Analog::ERROR
810 );
811 throw $e;
812 }
813 }
814
815 /**
816 * Migrate old required fields configuration
817 * Only needeed for 0.7.4 upgrade
818 * (should have been 0.7.3 - but I missed that.)
819 *
820 * @return boolean
821 */
822 public function migrateRequired()
823 {
824 $old_required = null;
825
826 try {
827 $select = $this->zdb->select('required');
828 $select->from(PREFIX_DB . 'required');
829
830 $old_required = $this->zdb->execute($select);
831 } catch (\Exception $pe) {
832 Analog::log(
833 'Unable to retrieve required fields_config. Maybe ' .
834 'the table does not exists?',
835 Analog::WARNING
836 );
837 //not a blocker
838 return true;
839 }
840
841 $this->zdb->connection->beginTransaction();
842 try {
843 $update = $this->zdb->update(self::TABLE);
844 $update->set(
845 array(
846 'required' => ':required'
847 )
848 )->where(
849 array(
850 'field_id' => ':field_id',
851 'table_name' => $this->table
852 )
853 );
854
855 $stmt = $this->zdb->sql->prepareStatementForSqlObject($update);
856
857 foreach ($old_required as $or) {
858 $stmt->execute(
859 array(
860 'required' => ($or->required === false) ?
861 ($this->zdb->isPostgres() ? 'false' : 0) : true,
862 'field_id' => $or->field_id
863 )
864 );
865 }
866
867 $class = get_class($this);
868 Analog::log(
869 str_replace(
870 '%s',
871 $this->table,
872 '[' . $class . '] Required fields for table %s upgraded ' .
873 'successfully.'
874 ),
875 Analog::INFO
876 );
877
878 $this->zdb->db->query(
879 'DROP TABLE ' . PREFIX_DB . 'required',
880 Adapter::QUERY_MODE_EXECUTE
881 );
882
883 $this->zdb->connection->commit();
884 return true;
885 } catch (Throwable $e) {
886 $this->zdb->connection->rollBack();
887 Analog::log(
888 'An error occurred migrating old required fields. | ' .
889 $e->getMessage(),
890 Analog::ERROR
891 );
892 return false;
893 }
894 }
895
896 /**
897 * Insert values in database
898 *
899 * @param array $values Values to insert
900 *
901 * @return void
902 */
903 private function insert($values)
904 {
905 $insert = $this->zdb->insert(self::TABLE);
906 $insert->values(
907 array(
908 'field_id' => ':field_id',
909 'table_name' => ':table_name',
910 'required' => ':required',
911 'visible' => ':visible',
912 FieldsCategories::PK => ':category',
913 'position' => ':position',
914 'list_visible' => ':list_visible',
915 'list_position' => ':list_position'
916 )
917 );
918 $stmt = $this->zdb->sql->prepareStatementForSqlObject($insert);
919 foreach ($values as $d) {
920 $required = $d['required'];
921 if ($required === false) {
922 $required = $this->zdb->isPostgres() ? 'false' : 0;
923 }
924
925 $list_visible = $f['list_visible'] ?? false;
926 if ($list_visible === false) {
927 $list_visible = $this->zdb->isPostgres() ? 'false' : 0;
928 }
929
930 $stmt->execute(
931 array(
932 'field_id' => $d['field_id'],
933 'table_name' => $d['table_name'],
934 'required' => $required,
935 'visible' => $d['visible'],
936 'category' => $d['category'],
937 'position' => $d['position'],
938 'list_visible' => $list_visible,
939 'list_position' => $d['list_position'] ?? -1
940 )
941 );
942 }
943 }
944
945 /**
946 * Does field should be displayed in self subscription page
947 *
948 * @param string $name Field name
949 *
950 * @return boolean
951 */
952 public function isSelfExcluded($name)
953 {
954 return in_array(
955 $name,
956 array_merge(
957 $this->staff_fields,
958 $this->admin_fields
959 )
960 );
961 }
962
963 /**
964 * Get fields for massive changes
965 * @see FieldsConfig::getFormElements
966 *
967 * @param array $fields Member fields
968 * @param Login $login Login instance
969 *
970 * @return array
971 */
972 public function getMassiveFormElements(array $fields, Login $login)
973 {
974 $visibles = $this->getVisibilities();
975 $access_level = $login->getAccessLevel();
976
977 //remove not searchable fields
978 unset($fields['mdp_adh']);
979
980 foreach ($fields as $k => $f) {
981 if (
982 $visibles[$k] == FieldsConfig::NOBODY ||
983 ($visibles[$k] == FieldsConfig::ADMIN &&
984 $access_level < Authentication::ACCESS_ADMIN) ||
985 ($visibles[$k] == FieldsConfig::STAFF &&
986 $access_level < Authentication::ACCESS_STAFF) ||
987 ($visibles[$k] == FieldsConfig::MANAGER &&
988 $access_level < Authentication::ACCESS_MANAGER)
989 ) {
990 unset($fields[$k]);
991 }
992 }
993
994 $mass_fields = [
995 'titre_adh',
996 'sexe_adh',
997 'pref_lang',
998 'cp_adh',
999 'ville_adh',
1000 'pays_adh',
1001 'bool_display_info',
1002 'activite_adh',
1003 Status::PK,
1004 'bool_admin_adh',
1005 'bool_exempt_adh',
1006 ];
1007 $mass_fields = array_intersect(array_keys($fields), $mass_fields);
1008
1009 foreach ($mass_fields as $mass_field) {
1010 $this->setNotRequired($mass_field);
1011 }
1012 $form_elements = $this->getFormElements($login, false);
1013 unset($form_elements['hiddens']);
1014
1015 foreach ($form_elements['fieldsets'] as &$form_element) {
1016 $form_element->elements = array_intersect_key($form_element->elements, array_flip($mass_fields));
1017 }
1018 return $form_elements;
1019 }
1020
1021 /**
1022 * Get field configuration
1023 *
1024 * @param string $name Field name
1025 *
1026 * @return array
1027 */
1028 public function getField($name): array
1029 {
1030 if (!isset($this->core_db_fields[$name])) {
1031 throw new \UnexpectedValueException("$name fied does not exists");
1032 }
1033 return $this->core_db_fields[$name];
1034 }
1035 }