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