]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Controllers/Crud/MembersController.php
Clean unreachable code
[galette.git] / galette / lib / Galette / Controllers / Crud / MembersController.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette members controller
7 *
8 * PHP version 5
9 *
10 * Copyright © 2019-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 Controllers
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2019-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.9.4dev - 2019-12-02
35 */
36
37 namespace Galette\Controllers\Crud;
38
39 use Galette\Controllers\CrudController;
40 use Slim\Http\Request;
41 use Slim\Http\Response;
42 use Galette\Core\Authentication;
43 use Galette\Core\GaletteMail;
44 use Galette\Core\Password;
45 use Galette\Core\PasswordImage;
46 use Galette\Core\Picture;
47 use Galette\Entity\Adherent;
48 use Galette\Entity\Contribution;
49 use Galette\Entity\ContributionsTypes;
50 use Galette\Entity\DynamicFieldsHandle;
51 use Galette\Entity\Group;
52 use Galette\Entity\Status;
53 use Galette\Entity\FieldsConfig;
54 use Galette\Entity\Texts;
55 use Galette\Filters\AdvancedMembersList;
56 use Galette\Filters\MembersList;
57 use Galette\IO\File;
58 use Galette\IO\MembersCsv;
59 use Galette\Repository\Groups;
60 use Galette\Repository\Members;
61 use Galette\Repository\PaymentTypes;
62 use Galette\Repository\Titles;
63 use Analog\Analog;
64
65 /**
66 * Galette members controller
67 *
68 * @category Controllers
69 * @name GaletteController
70 * @package Galette
71 * @author Johan Cwiklinski <johan@x-tnd.be>
72 * @copyright 2019-2020 The Galette Team
73 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
74 * @link http://galette.tuxfamily.org
75 * @since Available since 0.9.4dev - 2019-12-02
76 */
77
78 class MembersController extends CrudController
79 {
80 // CRUD - Create
81
82 /**
83 * Add page
84 *
85 * @param Request $request PSR Request
86 * @param Response $response PSR Response
87 * @param array $args Request arguments
88 *
89 * @return Response
90 */
91 public function add(Request $request, Response $response, array $args = []): Response
92 {
93 $args['action'] = 'add';
94 return $this->edit($request, $response, $args);
95 }
96
97 /**
98 * Self subscription page
99 *
100 * @param Request $request PSR Request
101 * @param Response $response PSR Response
102 * @param array $args Request arguments
103 *
104 * @return Response
105 */
106 public function selfSubscribe(Request $request, Response $response, array $args = []): Response
107 {
108 if (!$this->preferences->pref_bool_selfsubscribe || $this->login->isLogged()) {
109 return $response
110 ->withStatus(301)
111 ->withHeader('Location', $this->router->pathFor('slash'));
112 }
113
114 if ($this->session->member !== null) {
115 $member = $this->session->member;
116 $this->session->member = null;
117 } else {
118 $deps = [
119 'dynamics' => true
120 ];
121 $member = new Adherent($this->zdb, null, $deps);
122 }
123
124 //mark as self membership
125 $member->setSelfMembership();
126
127 // flagging required fields
128 $fc = $this->fields_config;
129 $form_elements = $fc->getFormElements($this->login, true, true);
130
131 //image to defeat mass filling forms
132 $spam = new PasswordImage();
133 $spam_pass = $spam->newImage();
134 $spam_img = $spam->getImage();
135
136 // members
137 $m = new Members();
138 $members = $m->getSelectizedMembers(
139 $this->zdb,
140 $member->hasParent() ? $member->parent->id : null
141 );
142
143 $params = [
144 'members' => [
145 'filters' => $m->getFilters(),
146 'count' => $m->getCount()
147 ]
148 ];
149
150 if (count($members)) {
151 $params['members']['list'] = $members;
152 }
153
154 // display page
155 $this->view->render(
156 $response,
157 'member.tpl',
158 array(
159 'page_title' => _T("Subscription"),
160 'parent_tpl' => 'public_page.tpl',
161 'member' => $member,
162 'self_adh' => true,
163 'autocomplete' => true,
164 // pseudo random int
165 'time' => time(),
166 'titles_list' => Titles::getList($this->zdb),
167 //self_adh specific
168 'spam_pass' => $spam_pass,
169 'spam_img' => $spam_img,
170 'fieldsets' => $form_elements['fieldsets'],
171 'hidden_elements' => $form_elements['hiddens']
172 ) + $params
173 );
174 return $response;
175 }
176
177 /**
178 * Add action
179 *
180 * @param Request $request PSR Request
181 * @param Response $response PSR Response
182 * @param array $args Request arguments
183 *
184 * @return Response
185 */
186 public function doAdd(Request $request, Response $response, array $args = []): Response
187 {
188 return $this->store($request, $response, $args);
189 }
190
191 /**
192 * Duplicate action
193 *
194 * @param Request $request PSR Request
195 * @param Response $response PSR Response
196 * @param array $args Request arguments
197 *
198 * @return Response
199 */
200 public function duplicate(Request $request, Response $response, array $args = []): Response
201 {
202 $id_adh = (int)$args[Adherent::PK];
203 $adh = new Adherent($this->zdb, $id_adh, ['dynamics' => true, 'parent' => true]);
204 $adh->setDuplicate();
205
206 //store entity in session
207 $this->session->member = $adh;
208
209 return $response
210 ->withStatus(301)
211 ->withHeader('Location', $this->router->pathFor('addMember'));
212 }
213
214 // /CRUD - Create
215 // CRUD - Read
216
217 /**
218 * Display member card
219 *
220 * @param Request $request PSR Request
221 * @param Response $response PSR Response
222 * @param array $args Request arguments
223 *
224 * @return Response
225 */
226 public function show(Request $request, Response $response, array $args): Response
227 {
228 $id = (int)$args['id'];
229
230 $deps = array(
231 'picture' => true,
232 'groups' => true,
233 'dues' => true,
234 'parent' => true,
235 'children' => true,
236 'dynamics' => true
237 );
238 $member = new Adherent($this->zdb, $id, $deps);
239
240 if (!$member->canEdit($this->login)) {
241 $this->flash->addMessage(
242 'error_detected',
243 _T("You do not have permission for requested URL.")
244 );
245
246 return $response
247 ->withStatus(301)
248 ->withHeader(
249 'Location',
250 $this->router->pathFor('me')
251 );
252 }
253
254 if ($member->id == null) {
255 //member does not exists!
256 $this->flash->addMessage(
257 'error_detected',
258 str_replace('%id', $args['id'], _T("No member #%id."))
259 );
260
261 return $response
262 ->withStatus(404)
263 ->withHeader(
264 'Location',
265 $this->router->pathFor('slash')
266 );
267 }
268
269 // flagging fields visibility
270 $fc = $this->fields_config;
271 $display_elements = $fc->getDisplayElements($this->login);
272
273 // display page
274 $this->view->render(
275 $response,
276 'voir_adherent.tpl',
277 array(
278 'page_title' => _T("Member Profile"),
279 'member' => $member,
280 'pref_lang' => $this->i18n->getNameFromId($member->language),
281 'pref_card_self' => $this->preferences->pref_card_self,
282 'groups' => Groups::getSimpleList(),
283 'time' => time(),
284 'display_elements' => $display_elements
285 )
286 );
287 return $response;
288 }
289
290 /**
291 * Own card show
292 *
293 * @param Request $request PSR Request
294 * @param Response $response PSR Response
295 * @param array $args Request arguments
296 *
297 * @return Response
298 */
299 public function showMe(Request $request, Response $response, array $args = []): Response
300 {
301 if ($this->login->isSuperAdmin()) {
302 return $response
303 ->withStatus(301)
304 ->withHeader('Location', $this->router->pathFor('slash'));
305 }
306 $args['show_me'] = true;
307 $args['id'] = $this->login->id;
308 return $this->show($request, $response, $args);
309 }
310
311 /**
312 * Public pages (trombinoscope, public list)
313 *
314 * @param Request $request PSR Request
315 * @param Response $response PSR Response
316 * @param array $args Request arguments
317 *
318 * @return Response
319 */
320 public function publicList(Request $request, Response $response, array $args = []): Response
321 {
322 $option = null;
323 $type = $args['type'];
324 if (isset($args['option'])) {
325 $option = $args['option'];
326 }
327 $value = null;
328 if (isset($args['value'])) {
329 $value = $args['value'];
330 }
331
332 $varname = 'public_filter_' . $type;
333 if (isset($this->session->$varname)) {
334 $filters = $this->session->$varname;
335 } else {
336 $filters = new MembersList();
337 }
338
339 if ($option !== null) {
340 switch ($option) {
341 case 'page':
342 $filters->current_page = (int)$value;
343 break;
344 case 'order':
345 $filters->orderby = $value;
346 break;
347 }
348 }
349
350 $m = new Members($filters);
351 $members = $m->getPublicList($type === 'trombi');
352
353 $this->session->$varname = $filters;
354
355 //assign pagination variables to the template and add pagination links
356 $filters->setSmartyPagination($this->router, $this->view->getSmarty(), false);
357
358 // display page
359 $this->view->render(
360 $response,
361 ($type === 'list' ? 'liste_membres' : 'trombinoscope') . '.tpl',
362 array(
363 'page_title' => ($type === 'list' ? _T("Members list") : _T('Trombinoscope')),
364 'additionnal_html_class' => ($type === 'list' ? '' : 'trombinoscope'),
365 'type' => $type,
366 'members' => $members,
367 'nb_members' => $m->getCount(),
368 'filters' => $filters
369 )
370 );
371 return $response;
372 }
373
374 /**
375 * Public pages (trombinoscope, public list)
376 *
377 * @param Request $request PSR Request
378 * @param Response $response PSR Response
379 * @param array $args Request arguments
380 *
381 * @return Response
382 */
383 public function filterPublicList(Request $request, Response $response, array $args = []): Response
384 {
385 $type = $args['type'];
386 $post = $request->getParsedBody();
387
388 $varname = 'public_filter_' . $type;
389 if (isset($this->session->$varname)) {
390 $filters = $this->session->$varname;
391 } else {
392 $filters = new MembersList();
393 }
394
395 //reintialize filters
396 if (isset($post['clear_filter'])) {
397 $filters->reinit();
398 } else {
399 //number of rows to show
400 if (isset($post['nbshow'])) {
401 $filters->show = $post['nbshow'];
402 }
403 }
404
405 $this->session->$varname = $filters;
406
407 return $response
408 ->withStatus(301)
409 ->withHeader('Location', $this->router->pathFor('publicList', ['type' => $type]));
410 }
411
412 /**
413 * Get a dynamic file
414 *
415 * @param Request $request PSR Request
416 * @param Response $response PSR Response
417 * @param array $args Request arguments
418 *
419 * @return Response
420 */
421 public function getDynamicFile(Request $request, Response $response, array $args): Response
422 {
423 $id = (int)$args['id'];
424 $deps = array(
425 'picture' => false,
426 'groups' => false,
427 'dues' => false,
428 'parent' => false,
429 'children' => false,
430 'dynamics' => true
431 );
432 $member = new Adherent($this->zdb, $id, $deps);
433
434 $denied = null;
435 if (!$member->canEdit($this->login)) {
436 $fields = $member->getDynamicFields()->getFields();
437 if (!isset($fields[$args['fid']])) {
438 //field does not exists or access is forbidden
439 $denied = true;
440 } else {
441 $denied = false;
442 }
443 }
444
445 if ($denied === true) {
446 $this->flash->addMessage(
447 'error_detected',
448 _T("You do not have permission for requested URL.")
449 );
450
451 return $response
452 ->withStatus(403)
453 ->withHeader(
454 'Location',
455 $this->router->pathFor(
456 'member',
457 ['id' => $id]
458 )
459 );
460 }
461
462 $filename = str_replace(
463 [
464 '%mid',
465 '%fid',
466 '%pos'
467 ],
468 [
469 $args['id'],
470 $args['fid'],
471 $args['pos']
472 ],
473 'member_%mid_field_%fid_value_%pos'
474 );
475
476 if (file_exists(GALETTE_FILES_PATH . $filename)) {
477 $type = File::getMimeType(GALETTE_FILES_PATH . $filename);
478
479 $response = $response->withHeader('Content-Description', 'File Transfer')
480 ->withHeader('Content-Type', $type)
481 ->withHeader('Content-Disposition', 'attachment;filename="' . $args['name'] . '"')
482 ->withHeader('Pragma', 'no-cache')
483 ->withHeader('Content-Transfer-Encoding', 'binary')
484 ->withHeader('Expires', '0')
485 ->withHeader('Cache-Control', 'must-revalidate')
486 ->withHeader('Pragma', 'public');
487
488 $stream = fopen('php://memory', 'r+');
489 fwrite($stream, file_get_contents(GALETTE_FILES_PATH . $filename));
490 rewind($stream);
491
492 return $response->withBody(new \Slim\Http\Stream($stream));
493 } else {
494 Analog::log(
495 'A request has been made to get a dynamic file named `' .
496 $filename . '` that does not exists.',
497 Analog::WARNING
498 );
499
500 $this->flash->addMessage(
501 'error_detected',
502 _T("The file does not exists or cannot be read :(")
503 );
504
505 return $response
506 ->withStatus(404)
507 ->withHeader(
508 'Location',
509 $this->router->pathFor('member', ['id' => $args['id']])
510 );
511 }
512 }
513
514 /**
515 * Members list
516 *
517 * @param Request $request PSR Request
518 * @param Response $response PSR Response
519 * @param array $args Request arguments
520 *
521 * @return Response
522 */
523 public function list(Request $request, Response $response, array $args = []): Response
524 {
525 $option = $args['option'] ?? null;
526 $value = $args['value'] ?? null;
527
528 if (isset($this->session->filter_members)) {
529 $filters = $this->session->filter_members;
530 } else {
531 $filters = new MembersList();
532 }
533
534 if ($option !== null) {
535 switch ($option) {
536 case 'page':
537 $filters->current_page = (int)$value;
538 break;
539 case 'order':
540 $filters->orderby = $value;
541 break;
542 }
543 }
544
545 $members = new Members($filters);
546
547 $members_list = array();
548 if ($this->login->isAdmin() || $this->login->isStaff()) {
549 $members_list = $members->getMembersList(true);
550 } else {
551 $members_list = $members->getManagedMembersList(true);
552 }
553
554 $groups = new Groups($this->zdb, $this->login);
555 $groups_list = $groups->getList();
556
557 //assign pagination variables to the template and add pagination links
558 $filters->setSmartyPagination($this->router, $this->view->getSmarty(), false);
559 $filters->setViewCommonsFilters($this->preferences, $this->view->getSmarty());
560
561 $this->session->filter_members = $filters;
562
563 // display page
564 $this->view->render(
565 $response,
566 'gestion_adherents.tpl',
567 array(
568 'page_title' => _T("Members management"),
569 'require_mass' => true,
570 'members' => $members_list,
571 'filter_groups_options' => $groups_list,
572 'nb_members' => $members->getCount(),
573 'filters' => $filters,
574 'adv_filters' => $filters instanceof AdvancedMembersList,
575 'galette_list' => $this->lists_config->getDisplayElements($this->login)
576 )
577 );
578 return $response;
579 }
580
581 /**
582 * Members filtering
583 *
584 * @param Request $request PSR Request
585 * @param Response $response PSR Response
586 *
587 * @return Response
588 */
589 public function filter(Request $request, Response $response): Response
590 {
591 $post = $request->getParsedBody();
592 if (isset($this->session->filter_members)) {
593 //CAUTION: this one may be simple or advanced, display must change
594 $filters = $this->session->filter_members;
595 } else {
596 $filters = new MembersList();
597 }
598
599 //reintialize filters
600 if (isset($post['clear_filter'])) {
601 $filters = new MembersList();
602 } elseif (isset($post['clear_adv_filter'])) {
603 $this->session->filter_members = null;
604 unset($this->session->filter_members);
605
606 return $response
607 ->withStatus(301)
608 ->withHeader('Location', $this->router->pathFor('advanced-search'));
609 } elseif (isset($post['adv_criteria'])) {
610 return $response
611 ->withStatus(301)
612 ->withHeader('Location', $this->router->pathFor('advanced-search'));
613 } else {
614 //string to filter
615 if (isset($post['filter_str'])) { //filter search string
616 $filters->filter_str = stripslashes(
617 htmlspecialchars($post['filter_str'], ENT_QUOTES)
618 );
619 }
620 //field to filter
621 if (isset($post['field_filter'])) {
622 if (is_numeric($post['field_filter'])) {
623 $filters->field_filter = $post['field_filter'];
624 }
625 }
626 //membership to filter
627 if (isset($post['membership_filter'])) {
628 if (is_numeric($post['membership_filter'])) {
629 $filters->membership_filter
630 = $post['membership_filter'];
631 }
632 }
633 //account status to filter
634 if (isset($post['filter_account'])) {
635 if (is_numeric($post['filter_account'])) {
636 $filters->filter_account = $post['filter_account'];
637 }
638 }
639 //email filter
640 if (isset($post['email_filter'])) {
641 $filters->email_filter = (int)$post['email_filter'];
642 }
643 //group filter
644 if (
645 isset($post['group_filter'])
646 && $post['group_filter'] > 0
647 ) {
648 $filters->group_filter = (int)$post['group_filter'];
649 }
650 //number of rows to show
651 if (isset($post['nbshow'])) {
652 $filters->show = $post['nbshow'];
653 }
654
655 if (isset($post['advanced_filtering'])) {
656 if (!$filters instanceof AdvancedMembersList) {
657 $filters = new AdvancedMembersList($filters);
658 }
659 //Advanced filters
660 $filters->reinit();
661 unset($post['advanced_filtering']);
662 $freed = false;
663 foreach ($post as $k => $v) {
664 if (strpos($k, 'free_', 0) === 0) {
665 if (!$freed) {
666 $i = 0;
667 foreach ($post['free_field'] as $f) {
668 if (
669 trim($f) !== ''
670 && trim($post['free_text'][$i]) !== ''
671 ) {
672 $fs_search = $post['free_text'][$i];
673 $log_op
674 = (int)$post['free_logical_operator'][$i];
675 $qry_op
676 = (int)$post['free_query_operator'][$i];
677 $type = (int)$post['free_type'][$i];
678 $fs = array(
679 'idx' => $i,
680 'field' => $f,
681 'type' => $type,
682 'search' => $fs_search,
683 'log_op' => $log_op,
684 'qry_op' => $qry_op
685 );
686 $filters->free_search = $fs;
687 }
688 $i++;
689 }
690 $freed = true;
691 }
692 } elseif ($k == 'groups_search') {
693 $i = 0;
694 $filters->groups_search_log_op = (int)$post['groups_logical_operator'];
695 foreach ($post['groups_search'] as $g) {
696 if (trim($g) !== '') {
697 $gs = array(
698 'idx' => $i,
699 'group' => $g
700 );
701 $filters->groups_search = $gs;
702 }
703 $i++;
704 }
705 } else {
706 switch ($k) {
707 case 'contrib_min_amount':
708 case 'contrib_max_amount':
709 if (trim($v) !== '') {
710 $v = (float)$v;
711 } else {
712 $v = null;
713 }
714 break;
715 }
716 $filters->$k = $v;
717 }
718 }
719 }
720 }
721
722 if (isset($post['savesearch'])) {
723 return $response
724 ->withStatus(301)
725 ->withHeader(
726 'Location',
727 $this->router->pathFor(
728 'saveSearch',
729 $post
730 )
731 );
732 }
733
734 $this->session->filter_members = $filters;
735
736 return $response
737 ->withStatus(301)
738 ->withHeader('Location', $this->router->pathFor('members'));
739 }
740
741 /**
742 * Advanced search page
743 *
744 * @param Request $request PSR Request
745 * @param Response $response PSR Response
746 *
747 * @return Response
748 */
749 public function advancedSearch(Request $request, Response $response): Response
750 {
751 if (isset($this->session->filter_members)) {
752 $filters = $this->session->filter_members;
753 if (!$filters instanceof AdvancedMembersList) {
754 $filters = new AdvancedMembersList($filters);
755 }
756 } else {
757 $filters = new AdvancedMembersList();
758 }
759
760 $groups = new Groups($this->zdb, $this->login);
761 $groups_list = $groups->getList();
762
763 //we want only visibles fields
764 $fields = $this->members_fields;
765 $fc = $this->fields_config;
766 $visibles = $fc->getVisibilities();
767 $access_level = $this->login->getAccessLevel();
768
769 //remove not searchable fields
770 unset($fields['mdp_adh']);
771
772 foreach ($fields as $k => $f) {
773 if (
774 $visibles[$k] == FieldsConfig::NOBODY ||
775 ($visibles[$k] == FieldsConfig::ADMIN &&
776 $access_level < Authentication::ACCESS_ADMIN) ||
777 ($visibles[$k] == FieldsConfig::STAFF &&
778 $access_level < Authentication::ACCESS_STAFF) ||
779 ($visibles[$k] == FieldsConfig::MANAGER &&
780 $access_level < Authentication::ACCESS_MANAGER)
781 ) {
782 unset($fields[$k]);
783 }
784 }
785
786 //add status label search
787 if ($pos = array_search(Status::PK, array_keys($fields))) {
788 $fields = array_slice($fields, 0, $pos, true) +
789 ['status_label' => ['label' => _T('Status label')]] +
790 array_slice($fields, $pos, count($fields) - 1, true);
791 }
792
793 //dynamic fields
794 $deps = array(
795 'picture' => false,
796 'groups' => false,
797 'dues' => false,
798 'parent' => false,
799 'children' => false,
800 'dynamics' => false
801 );
802 $member = new Adherent($this->zdb, $this->login->login, $deps);
803 $adh_dynamics = new DynamicFieldsHandle($this->zdb, $this->login, $member);
804
805 $contrib = new Contribution($this->zdb, $this->login);
806 $contrib_dynamics = new DynamicFieldsHandle($this->zdb, $this->login, $contrib);
807
808 //Status
809 $statuts = new Status($this->zdb);
810
811 //Contributions types
812 $ct = new ContributionsTypes($this->zdb);
813
814 //Payments types
815 $ptypes = new PaymentTypes(
816 $this->zdb,
817 $this->preferences,
818 $this->login
819 );
820 $ptlist = $ptypes->getList();
821
822 $filters->setViewCommonsFilters($this->preferences, $this->view->getSmarty());
823
824 // display page
825 $this->view->render(
826 $response,
827 'advanced_search.tpl',
828 array(
829 'page_title' => _T("Advanced search"),
830 'filter_groups_options' => $groups_list,
831 'search_fields' => $fields,
832 'adh_dynamics' => $adh_dynamics->getFields(),
833 'contrib_dynamics' => $contrib_dynamics->getFields(),
834 'statuts' => $statuts->getList(),
835 'contributions_types' => $ct->getList(),
836 'filters' => $filters,
837 'payments_types' => $ptlist
838 )
839 );
840 return $response;
841 }
842
843 /**
844 * Members list for ajax
845 *
846 * @param Request $request PSR Request
847 * @param Response $response PSR Response
848 * @param array $args Request arguments
849 *
850 * @return Response
851 */
852 public function ajaxList(Request $request, Response $response, array $args = []): Response
853 {
854 $post = $request->getParsedBody();
855
856 if (isset($this->session->ajax_members_filters)) {
857 $filters = $this->session->ajax_members_filters;
858 } else {
859 $filters = new MembersList();
860 }
861
862 if (isset($args['option']) && $args['option'] == 'page') {
863 $filters->current_page = (int)$args['value'];
864 }
865
866 //numbers of rows to display
867 if (isset($post['nbshow']) && is_numeric($post['nbshow'])) {
868 $filters->show = $post['nbshow'];
869 }
870
871 $members = new Members($filters);
872 if (!$this->login->isAdmin() && !$this->login->isStaff()) {
873 if ($this->login->isGroupManager()) {
874 $members_list = $members->getManagedMembersList(true);
875 } else {
876 Analog::log(
877 str_replace(
878 ['%id', '%login'],
879 [$this->login->id, $this->login->login],
880 'Trying to list group members without access from #%id (%login)'
881 ),
882 Analog::ERROR
883 );
884 throw new \Exception('Access denied.');
885 }
886 } else {
887 $members_list = $members->getMembersList(true);
888 }
889
890 //assign pagination variables to the template and add pagination links
891 $filters->setSmartyPagination($this->router, $this->view->getSmarty(), false);
892
893 $this->session->ajax_members_filters = $filters;
894
895 $selected_members = null;
896 $unreachables_members = null;
897 if (!isset($post['from'])) {
898 $mailing = $this->session->mailing;
899 if (!isset($post['members'])) {
900 $selected_members = $mailing->recipients;
901 $unreachables_members = $mailing->unreachables;
902 } else {
903 $m = new Members();
904 $selected_members = $m->getArrayList($post['members']);
905 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
906 $unreachables_members = $m->getArrayList($post['unreachables']);
907 }
908 }
909 } else {
910 switch ($post['from']) {
911 case 'groups':
912 if (!isset($post['gid'])) {
913 Analog::log(
914 'Trying to list group members with no group id provided',
915 Analog::ERROR
916 );
917 throw new \Exception('A group id is required.');
918 }
919 if (!isset($post['members'])) {
920 $group = new Group((int)$post['gid']);
921 $selected_members = array();
922 if (!isset($post['mode']) || $post['mode'] == 'members') {
923 $selected_members = $group->getMembers();
924 } elseif ($post['mode'] == 'managers') {
925 $selected_members = $group->getManagers();
926 } else {
927 Analog::log(
928 'Trying to list group members with unknown mode',
929 Analog::ERROR
930 );
931 throw new \Exception('Unknown mode.');
932 exit(0);
933 }
934 } else {
935 $m = new Members();
936 $selected_members = $m->getArrayList($post['members']);
937 if (isset($post['unreachables']) && is_array($post['unreachables'])) {
938 $unreachables_members = $m->getArrayList($post['unreachables']);
939 }
940 }
941 break;
942 case 'attach':
943 if (!isset($post['id_adh'])) {
944 throw new \RuntimeException(
945 'Current selected member must be excluded while attaching!'
946 );
947 exit(0);
948 }
949 break;
950 }
951 }
952
953 $params = [
954 'filters' => $filters,
955 'members_list' => $members_list,
956 'selected_members' => $selected_members,
957 'unreachables_members' => $unreachables_members
958 ];
959
960 if (isset($post['multiple'])) {
961 $params['multiple'] = true;
962 }
963
964 if (isset($post['gid'])) {
965 $params['the_id'] = $post['gid'];
966 }
967
968 if (isset($post['id_adh'])) {
969 $params['excluded'] = $post['id_adh'];
970 }
971
972 // display page
973 $this->view->render(
974 $response,
975 'ajax_members.tpl',
976 $params
977 );
978 return $response;
979 }
980
981 /**
982 * Batch actions handler
983 *
984 * @param Request $request PSR Request
985 * @param Response $response PSR Response
986 *
987 * @return Response
988 */
989 public function handleBatch(Request $request, Response $response): Response
990 {
991 $post = $request->getParsedBody();
992
993 if (isset($post['member_sel'])) {
994 if (isset($this->session->filter_members)) {
995 $filters = $this->session->filter_members;
996 } else {
997 $filters = new MembersList();
998 }
999
1000 $filters->selected = $post['member_sel'];
1001 $this->session->filter_members = $filters;
1002
1003 if (isset($post['cards'])) {
1004 return $response
1005 ->withStatus(301)
1006 ->withHeader('Location', $this->router->pathFor('pdf-members-cards'));
1007 }
1008
1009 if (isset($post['labels'])) {
1010 return $response
1011 ->withStatus(301)
1012 ->withHeader('Location', $this->router->pathFor('pdf-members-labels'));
1013 }
1014
1015 if (isset($post['mailing'])) {
1016 return $response
1017 ->withStatus(301)
1018 ->withHeader('Location', $this->router->pathFor('mailing') . '?mailing_new=new');
1019 }
1020
1021 if (isset($post['attendance_sheet'])) {
1022 return $response
1023 ->withStatus(301)
1024 ->withHeader('Location', $this->router->pathFor('attendance_sheet_details'));
1025 }
1026
1027 if (isset($post['csv'])) {
1028 return $response
1029 ->withStatus(301)
1030 ->withHeader('Location', $this->router->pathFor('csv-memberslist'));
1031 }
1032
1033 if (isset($post['delete'])) {
1034 return $response
1035 ->withStatus(301)
1036 ->withHeader('Location', $this->router->pathFor('removeMembers'));
1037 }
1038
1039 if (isset($post['masschange'])) {
1040 return $response
1041 ->withStatus(301)
1042 ->withHeader('Location', $this->router->pathFor('masschangeMembers'));
1043 }
1044
1045 throw new \RuntimeException('Does not know what to batch :(');
1046 } else {
1047 $this->flash->addMessage(
1048 'error_detected',
1049 _T("No member was selected, please check at least one name.")
1050 );
1051
1052 return $response
1053 ->withStatus(301)
1054 ->withHeader('Location', $this->router->pathFor('members'));
1055 }
1056 }
1057
1058 // /CRUD - Read
1059 // CRUD - Update
1060
1061 /**
1062 * Edit page
1063 *
1064 * @param Request $request PSR Request
1065 * @param Response $response PSR Response
1066 * @param array $args Request arguments
1067 *
1068 * @return Response
1069 */
1070 public function edit(Request $request, Response $response, array $args = []): Response
1071 {
1072 $action = $args['action'] ?? 'edit';
1073 $id = null;
1074 if (isset($args['id'])) {
1075 $id = (int)$args['id'];
1076 }
1077
1078 $deps = array(
1079 'picture' => true,
1080 'groups' => true,
1081 'dues' => true,
1082 'parent' => true,
1083 'children' => true,
1084 'dynamics' => true
1085 );
1086
1087 if ($this->session->member !== null) {
1088 $member = $this->session->member;
1089 $this->session->member = null;
1090 } else {
1091 $member = new Adherent($this->zdb, $id, $deps);
1092 }
1093
1094 if ($id !== null) {
1095 $member->load($id);
1096 if (!$member->canEdit($this->login)) {
1097 $this->flash->addMessage(
1098 'error_detected',
1099 _T("You do not have permission for requested URL.")
1100 );
1101
1102 return $response
1103 ->withStatus(403)
1104 ->withHeader(
1105 'Location',
1106 $this->router->pathFor('me')
1107 );
1108 }
1109 } else {
1110 if ($member->id != $id) {
1111 $member->load($this->login->id);
1112 }
1113 }
1114
1115 // flagging required fields
1116 $fc = $this->fields_config;
1117
1118 // password required if we create a new member
1119 if ($member->id != '') {
1120 $fc->setNotRequired('mdp_adh');
1121 }
1122
1123 //handle requirements for parent fields
1124 $parent_fields = $member->getParentFields();
1125 $tpl_parent_fields = []; //for JS when detaching
1126 foreach ($parent_fields as $field) {
1127 if ($fc->isRequired($field)) {
1128 $tpl_parent_fields[] = $field;
1129 if ($member->hasParent()) {
1130 $fc->setNotRequired($field);
1131 }
1132 }
1133 }
1134
1135 // flagging required fields invisible to members
1136 if ($this->login->isAdmin() || $this->login->isStaff()) {
1137 $fc->setNotRequired('activite_adh');
1138 $fc->setNotRequired('id_statut');
1139 }
1140
1141 // template variable declaration
1142 $title = _T("Member Profile");
1143 if ($member->id != '') {
1144 $title .= ' (' . _T("modification") . ')';
1145 } else {
1146 $title .= ' (' . _T("creation") . ')';
1147 }
1148
1149 //Status
1150 $statuts = new Status($this->zdb);
1151
1152 //Groups
1153 $groups = new Groups($this->zdb, $this->login);
1154 $groups_list = $groups->getSimpleList(true);
1155
1156 $form_elements = $fc->getFormElements(
1157 $this->login,
1158 $member->id == ''
1159 );
1160
1161 // members
1162 $m = new Members();
1163 $id = null;
1164 if ($member->hasParent()) {
1165 $id = ($member->parent instanceof Adherent ? $member->parent->id : $member->parent);
1166 }
1167 $members = $m->getSelectizedMembers(
1168 $this->zdb,
1169 $id
1170 );
1171
1172 $route_params['members'] = [
1173 'filters' => $m->getFilters(),
1174 'count' => $m->getCount()
1175 ];
1176
1177 if (count($members)) {
1178 $route_params['members']['list'] = $members;
1179 }
1180
1181 // display page
1182 $this->view->render(
1183 $response,
1184 'member.tpl',
1185 array(
1186 'parent_tpl' => 'page.tpl',
1187 'autocomplete' => true,
1188 'page_title' => $title,
1189 'member' => $member,
1190 'self_adh' => false,
1191 // pseudo random int
1192 'time' => time(),
1193 'titles_list' => Titles::getList($this->zdb),
1194 'statuts' => $statuts->getList(),
1195 'groups' => $groups_list,
1196 'fieldsets' => $form_elements['fieldsets'],
1197 'hidden_elements' => $form_elements['hiddens'],
1198 'parent_fields' => $tpl_parent_fields
1199 ) + $route_params
1200 );
1201 return $response;
1202 }
1203
1204 /**
1205 * Edit action
1206 *
1207 * @param Request $request PSR Request
1208 * @param Response $response PSR Response
1209 * @param array $args Request arguments
1210 *
1211 * @return Response
1212 */
1213 public function doEdit(Request $request, Response $response, array $args = []): Response
1214 {
1215 return $this->store($request, $response, $args);
1216 }
1217
1218 /**
1219 * Massive change page
1220 *
1221 * @param Request $request PSR Request
1222 * @param Response $response PSR Response
1223 * @param array $args Request arguments
1224 *
1225 * @return Response
1226 */
1227 public function massChange(Request $request, Response $response, array $args = []): Response
1228 {
1229 $filters = $this->session->filter_members;
1230
1231 $data = [
1232 'id' => $filters->selected,
1233 'redirect_uri' => $this->router->pathFor('members')
1234 ];
1235
1236 $fc = $this->fields_config;
1237 $form_elements = $fc->getMassiveFormElements($this->members_fields, $this->login);
1238
1239 //dynamic fields
1240 $deps = array(
1241 'picture' => false,
1242 'groups' => false,
1243 'dues' => false,
1244 'parent' => false,
1245 'children' => false,
1246 'dynamics' => false
1247 );
1248 $member = new Adherent($this->zdb, null, $deps);
1249
1250 //Status
1251 $statuts = new Status($this->zdb);
1252
1253 // display page
1254 $this->view->render(
1255 $response,
1256 'mass_change_members.tpl',
1257 array(
1258 'mode' => $request->isXhr() ? 'ajax' : '',
1259 'page_title' => str_replace(
1260 '%count',
1261 count($data['id']),
1262 _T('Mass change %count members')
1263 ),
1264 'form_url' => $this->router->pathFor('masschangeMembersReview'),
1265 'cancel_uri' => $this->router->pathFor('members'),
1266 'data' => $data,
1267 'member' => $member,
1268 'fieldsets' => $form_elements['fieldsets'],
1269 'titles_list' => Titles::getList($this->zdb),
1270 'statuts' => $statuts->getList(),
1271 'require_mass' => true
1272 )
1273 );
1274 return $response;
1275 }
1276
1277 /**
1278 * Massive changes validation page
1279 *
1280 * @param Request $request PSR Request
1281 * @param Response $response PSR Response
1282 * @param array $args Request arguments
1283 *
1284 * @return Response
1285 */
1286 public function validateMassChange(Request $request, Response $response, array $args = []): Response
1287 {
1288 $post = $request->getParsedBody();
1289
1290 if (!isset($post['confirm'])) {
1291 $this->flash->addMessage(
1292 'error_detected',
1293 _T("Mass changes has not been confirmed!")
1294 );
1295 } else {
1296 //we want only visibles fields
1297 $fc = $this->fields_config;
1298 $form_elements = $fc->getMassiveFormElements($this->members_fields, $this->login);
1299
1300 $changes = [];
1301 foreach ($form_elements['fieldsets'] as $form_element) {
1302 foreach ($form_element->elements as $field) {
1303 if (
1304 isset($post['mass_' . $field->field_id])
1305 && (isset($post[$field->field_id]) || $field->type === FieldsConfig::TYPE_BOOL)
1306 ) {
1307 $changes[$field->field_id] = [
1308 'label' => $field->label,
1309 'value' => $post[$field->field_id] ?? 0
1310 ];
1311 }
1312 }
1313 }
1314 }
1315
1316 $filters = $this->session->filter_members;
1317 $data = [
1318 'id' => $filters->selected,
1319 'redirect_uri' => $this->router->pathFor('members')
1320 ];
1321
1322 //Status
1323 $statuts = new Status($this->zdb);
1324
1325 // display page
1326 $this->view->render(
1327 $response,
1328 'mass_change_members.tpl',
1329 array(
1330 'mode' => $request->isXhr() ? 'ajax' : '',
1331 'page_title' => str_replace(
1332 '%count',
1333 count($data['id']),
1334 _T('Review mass change %count members')
1335 ),
1336 'form_url' => $this->router->pathFor('massstoremembers'),
1337 'cancel_uri' => $this->router->pathFor('members'),
1338 'data' => $data,
1339 'titles_list' => Titles::getList($this->zdb),
1340 'statuts' => $statuts->getList(),
1341 'changes' => $changes
1342 )
1343 );
1344 return $response;
1345 }
1346
1347 /**
1348 * Do massive changes
1349 *
1350 * @param Request $request PSR Request
1351 * @param Response $response PSR Response
1352 * @param array $args Request arguments
1353 *
1354 * @return Response
1355 */
1356 public function doMassChange(Request $request, Response $response, array $args = []): Response
1357 {
1358 $post = $request->getParsedBody();
1359 $redirect_url = $post['redirect_uri'];
1360 $error_detected = [];
1361 $mass = 0;
1362
1363 unset($post['redirect_uri']);
1364 if (!isset($post['confirm'])) {
1365 $error_detected[] = _T("Mass changes has not been confirmed!");
1366 } else {
1367 unset($post['confirm']);
1368 $ids = $post['id'];
1369 unset($post['id']);
1370
1371 $fc = $this->fields_config;
1372 $form_elements = $fc->getMassiveFormElements($this->members_fields, $this->login);
1373 $disabled = $this->members_fields;
1374 foreach (array_keys($post) as $key) {
1375 $found = false;
1376 foreach ($form_elements['fieldsets'] as $fieldset) {
1377 if (isset($fieldset->elements[$key])) {
1378 $found = true;
1379 continue;
1380 }
1381 }
1382 if (!$found) {
1383 Analog::log(
1384 'Permission issue mass editing field ' . $key,
1385 Analog::WARNING
1386 );
1387 unset($post[$key]);
1388 } else {
1389 unset($disabled[$key]);
1390 }
1391 }
1392
1393 if (!count($post)) {
1394 $error_detected[] = _T("Nothing to do!");
1395 } else {
1396 foreach ($ids as $id) {
1397 $is_manager = !$this->login->isAdmin()
1398 && !$this->login->isStaff()
1399 && $this->login->isGroupManager();
1400 $deps = array(
1401 'picture' => false,
1402 'groups' => $is_manager,
1403 'dues' => false,
1404 'parent' => false,
1405 'children' => false,
1406 'dynamics' => false
1407 );
1408 $member = new Adherent($this->zdb, (int)$id, $deps);
1409 $member->setDependencies(
1410 $this->preferences,
1411 $this->members_fields,
1412 $this->history
1413 );
1414 if (!$member->canEdit($this->login)) {
1415 continue;
1416 }
1417
1418 $valid = $member->check($post, [], $disabled);
1419 if ($valid === true) {
1420 $done = $member->store();
1421 if (!$done) {
1422 $error_detected[] = _T("An error occurred while storing the member.");
1423 } else {
1424 ++$mass;
1425 }
1426 } else {
1427 $error_detected = array_merge($error_detected, $valid);
1428 }
1429 }
1430 }
1431 }
1432
1433 if ($mass == 0 && !count($error_detected)) {
1434 $error_detected[] = _T('Something went wront during mass edition!');
1435 } else {
1436 $this->flash->addMessage(
1437 'success_detected',
1438 str_replace(
1439 '%count',
1440 $mass,
1441 _T('%count members has been changed successfully!')
1442 )
1443 );
1444 }
1445
1446 if (count($error_detected) > 0) {
1447 foreach ($error_detected as $error) {
1448 $this->flash->addMessage(
1449 'error_detected',
1450 $error
1451 );
1452 }
1453 }
1454
1455 if (!$request->isXhr()) {
1456 return $response
1457 ->withStatus(301)
1458 ->withHeader('Location', $redirect_url);
1459 } else {
1460 return $response->withJson(
1461 [
1462 'success' => count($error_detected) === 0
1463 ]
1464 );
1465 }
1466 }
1467
1468 /**
1469 * Store
1470 *
1471 * @param Request $request PSR Request
1472 * @param Response $response PSR Response
1473 * @param array $args Request arguments
1474 *
1475 * @return Response
1476 */
1477 public function store(Request $request, Response $response, array $args = []): Response
1478 {
1479 if (!$this->preferences->pref_bool_selfsubscribe && !$this->login->isLogged()) {
1480 return $response
1481 ->withStatus(301)
1482 ->withHeader('Location', $this->router->pathFor('slash'));
1483 }
1484
1485 $post = $request->getParsedBody();
1486 $deps = array(
1487 'picture' => true,
1488 'groups' => true,
1489 'dues' => true,
1490 'parent' => true,
1491 'children' => true,
1492 'dynamics' => true
1493 );
1494 $member = new Adherent($this->zdb, null, $deps);
1495 $member->setDependencies(
1496 $this->preferences,
1497 $this->members_fields,
1498 $this->history
1499 );
1500 if (isset($args['self'])) {
1501 //mark as self membership
1502 $member->setSelfMembership();
1503 }
1504
1505 $success_detected = [];
1506 $warning_detected = [];
1507 $error_detected = [];
1508
1509 //check captcha
1510 if (isset($args['self'])) {
1511 if (
1512 !$post['mdp_crypt']
1513 || !$post['mdp_adh']
1514 || !crypt($post['mdp_adh'], $post['mdp_crypt']) == $post['mdp_crypt']
1515 ) {
1516 $error_detected[] = __('Please repeat in the field the password shown in the image.');
1517 } else {
1518 unset($post['mdp_adh']);
1519 unset($post['mdp_crypt']);
1520 }
1521 }
1522
1523 // new or edit
1524 $adherent['id_adh'] = get_numeric_form_value('id_adh', '');
1525 if ($this->login->isAdmin() || $this->login->isStaff() || $this->login->isGroupManager()) {
1526 if ($adherent['id_adh']) {
1527 $member->load((int)$adherent['id_adh']);
1528 if (!$member->canEdit($this->login)) {
1529 //redirection should have been done before. Just throw an Exception.
1530 throw new \RuntimeException(
1531 str_replace(
1532 '%id',
1533 $member->id,
1534 'No right to store member #%id'
1535 )
1536 );
1537 }
1538 }
1539 } else {
1540 $member->load($this->login->id);
1541 $adherent['id_adh'] = $this->login->id;
1542 }
1543
1544 // flagging required fields
1545 $fc = $this->fields_config;
1546
1547 // password required if we create a new member but not from self subscription
1548 if ($member->id != '' || isset($args['self'])) {
1549 $fc->setNotRequired('mdp_adh');
1550 }
1551
1552 if (
1553 $member->hasParent() && !isset($post['detach_parent'])
1554 || isset($post['parent_id']) && !empty($post['parent_id'])
1555 ) {
1556 $parent_fields = $member->getParentFields();
1557 foreach ($parent_fields as $field) {
1558 if ($fc->isRequired($field)) {
1559 $fc->setNotRequired($field);
1560 }
1561 }
1562 }
1563
1564 // flagging required fields invisible to members
1565 if ($this->login->isAdmin() || $this->login->isStaff()) {
1566 $fc->setNotRequired('activite_adh');
1567 $fc->setNotRequired('id_statut');
1568 }
1569
1570 $form_elements = $fc->getFormElements(
1571 $this->login,
1572 $member->id == '',
1573 isset($args['self'])
1574 );
1575 $fieldsets = $form_elements['fieldsets'];
1576 $required = array();
1577 $disabled = array();
1578
1579 foreach ($fieldsets as $category) {
1580 foreach ($category->elements as $field) {
1581 if ($field->required == true) {
1582 $required[$field->field_id] = true;
1583 }
1584 if ($field->disabled == true) {
1585 $disabled[$field->field_id] = true;
1586 } elseif (!isset($post[$field->field_id])) {
1587 switch ($field->field_id) {
1588 //unchecked booleans are not sent from form
1589 case 'bool_admin_adh':
1590 case 'bool_exempt_adh':
1591 case 'bool_display_info':
1592 $post[$field->field_id] = 0;
1593 break;
1594 }
1595 }
1596 }
1597 }
1598
1599 $real_requireds = array_diff(array_keys($required), array_keys($disabled));
1600
1601 // Validation
1602 $redirect_url = $this->router->pathFor('member', ['id' => $member->id]);
1603 if (isset($post[array_shift($real_requireds)])) {
1604 // regular fields
1605 $valid = $member->check($post, $required, $disabled);
1606 if ($valid !== true) {
1607 $error_detected = array_merge($error_detected, $valid);
1608 }
1609
1610 if (count($error_detected) == 0) {
1611 //all goes well, we can proceed
1612
1613 $new = false;
1614 if ($member->id == '') {
1615 $new = true;
1616 }
1617
1618 // send email to member
1619 if (isset($args['self']) || isset($post['mail_confirm']) && $post['mail_confirm'] == '1') {
1620 $member->setSendmail(); //flag to send creation email
1621 }
1622
1623 $store = $member->store();
1624 if ($store === true) {
1625 //member has been stored :)
1626 if ($new) {
1627 if (isset($args['self'])) {
1628 $success_detected[] = _T("Your account has been created!");
1629 if (
1630 $this->preferences->pref_mail_method > GaletteMail::METHOD_DISABLED
1631 && $member->getEmail() != ''
1632 ) {
1633 $success_detected[] = _T("An email has been sent to you, check your inbox.");
1634 }
1635 } else {
1636 $success_detected[] = _T("New member has been successfully added.");
1637 }
1638 } else {
1639 $success_detected[] = _T("Member account has been modified.");
1640 }
1641
1642 //store requested groups
1643 $add_groups = null;
1644 $groups_adh = null;
1645 $managed_groups_adh = null;
1646
1647 //add/remove user from groups
1648 if (isset($post['groups_adh'])) {
1649 $groups_adh = $post['groups_adh'];
1650 }
1651 $add_groups = Groups::addMemberToGroups(
1652 $member,
1653 $groups_adh
1654 );
1655
1656 if ($add_groups === false) {
1657 $error_detected[] = _T("An error occurred adding member to its groups.");
1658 }
1659
1660 //add/remove manager from groups
1661 if (isset($post['groups_managed_adh'])) {
1662 $managed_groups_adh = $post['groups_managed_adh'];
1663 }
1664 $add_groups = Groups::addMemberToGroups(
1665 $member,
1666 $managed_groups_adh,
1667 true
1668 );
1669 $member->loadGroups();
1670
1671 if ($add_groups === false) {
1672 $error_detected[] = _T("An error occurred adding member to its groups as manager.");
1673 }
1674 } else {
1675 //something went wrong :'(
1676 $error_detected[] = _T("An error occurred while storing the member.");
1677 }
1678 }
1679
1680 if (count($error_detected) === 0) {
1681 $files_res = $member->handleFiles($_FILES);
1682 if (is_array($files_res)) {
1683 $error_detected = array_merge($error_detected, $files_res);
1684 }
1685
1686 if (isset($post['del_photo'])) {
1687 if (!$member->picture->delete($member->id)) {
1688 $error_detected[] = _T("Delete failed");
1689 $str_adh = $member->id . ' (' . $member->sname . ' ' . ')';
1690 Analog::log(
1691 'Unable to delete picture for member ' . $str_adh,
1692 Analog::ERROR
1693 );
1694 }
1695 }
1696 }
1697
1698 if (count($error_detected) > 0) {
1699 foreach ($error_detected as $error) {
1700 if (strpos($error, '%member_url_') !== false) {
1701 preg_match('/%member_url_(\d+)/', $error, $matches);
1702 $url = $this->router->pathFor('member', ['id' => $matches[1]]);
1703 $error = str_replace(
1704 '%member_url_' . $matches[1],
1705 $url,
1706 $error
1707 );
1708 }
1709 $this->flash->addMessage(
1710 'error_detected',
1711 $error
1712 );
1713 }
1714 }
1715
1716 if (count($warning_detected) > 0) {
1717 foreach ($warning_detected as $warning) {
1718 $this->flash->addMessage(
1719 'warning_detected',
1720 $warning
1721 );
1722 }
1723 }
1724 if (count($success_detected) > 0) {
1725 foreach ($success_detected as $success) {
1726 $this->flash->addMessage(
1727 'success_detected',
1728 $success
1729 );
1730 }
1731 }
1732
1733 if (count($error_detected) === 0) {
1734 if (isset($args['self'])) {
1735 $redirect_url = $this->router->pathFor('login');
1736 } elseif (
1737 isset($post['redirect_on_create'])
1738 && $post['redirect_on_create'] > Adherent::AFTER_ADD_DEFAULT
1739 ) {
1740 switch ($post['redirect_on_create']) {
1741 case Adherent::AFTER_ADD_TRANS:
1742 $redirect_url = $this->router->pathFor('addTransaction');
1743 break;
1744 case Adherent::AFTER_ADD_NEW:
1745 $redirect_url = $this->router->pathFor('addMember');
1746 break;
1747 case Adherent::AFTER_ADD_SHOW:
1748 $redirect_url = $this->router->pathFor('member', ['id' => $member->id]);
1749 break;
1750 case Adherent::AFTER_ADD_LIST:
1751 $redirect_url = $this->router->pathFor('members');
1752 break;
1753 case Adherent::AFTER_ADD_HOME:
1754 $redirect_url = $this->router->pathFor('slash');
1755 break;
1756 }
1757 } elseif (!isset($post['id_adh']) && !$member->isDueFree()) {
1758 $redirect_url = $this->router->pathFor(
1759 'addContribution',
1760 ['type' => 'fee']
1761 ) . '?id_adh=' . $member->id;
1762 } else {
1763 $redirect_url = $this->router->pathFor('member', ['id' => $member->id]);
1764 }
1765 } else {
1766 //store entity in session
1767 $this->session->member = $member;
1768
1769 if (isset($args['self'])) {
1770 $redirect_url = $this->router->pathFor('subscribe');
1771 } else {
1772 if ($member->id) {
1773 $redirect_url = $this->router->pathFor(
1774 'editMember',
1775 ['id' => $member->id]
1776 );
1777 } else {
1778 $redirect_url = $this->router->pathFor('addMember');
1779 }
1780 }
1781 }
1782 }
1783
1784 return $response
1785 ->withStatus(301)
1786 ->withHeader('Location', $redirect_url);
1787 }
1788
1789
1790 // /CRUD - Update
1791 // CRUD - Delete
1792
1793 /**
1794 * Get redirection URI
1795 *
1796 * @param array $args Route arguments
1797 *
1798 * @return string
1799 */
1800 public function redirectUri(array $args = [])
1801 {
1802 return $this->router->pathFor('members');
1803 }
1804
1805 /**
1806 * Get form URI
1807 *
1808 * @param array $args Route arguments
1809 *
1810 * @return string
1811 */
1812 public function formUri(array $args = [])
1813 {
1814 return $this->router->pathFor(
1815 'doRemoveMember',
1816 $args
1817 );
1818 }
1819
1820
1821 /**
1822 * Get ID to remove
1823 *
1824 * In simple cases, we get the ID in the route arguments; but for
1825 * batchs, it should be found elsewhere.
1826 * In post values, we look for id key, as well as all {sthing}_sel keys (like members_sel or contrib_sel)
1827 *
1828 * @param array $args Request arguments
1829 * @param array $post POST values
1830 *
1831 * @return null|integer|integer[]
1832 */
1833 protected function getIdsToRemove(&$args, $post)
1834 {
1835 if (isset($args['id'])) {
1836 return $args['id'];
1837 } else {
1838 $filters = $this->session->filter_members;
1839 return $filters->selected;
1840 }
1841 }
1842
1843 /**
1844 * Get confirmation removal page title
1845 *
1846 * @param array $args Route arguments
1847 *
1848 * @return string
1849 */
1850 public function confirmRemoveTitle(array $args = [])
1851 {
1852 if (isset($args['id_adh'])) {
1853 //one member removal
1854 $adh = new Adherent($this->zdb, (int)$args['id_adh']);
1855 return sprintf(
1856 _T('Remove member %1$s'),
1857 $adh->sfullname
1858 );
1859 } else {
1860 //batch members removal
1861 $filters = $this->session->filter_members;
1862 return str_replace(
1863 '%count',
1864 count($filters->selected),
1865 _T('You are about to remove %count members.')
1866 );
1867 }
1868 }
1869
1870 /**
1871 * Remove object
1872 *
1873 * @param array $args Route arguments
1874 * @param array $post POST values
1875 *
1876 * @return boolean
1877 */
1878 protected function doDelete(array $args, array $post)
1879 {
1880 if (isset($this->session->filter_members)) {
1881 $filters = $this->session->filter_members;
1882 } else {
1883 $filters = new MembersList();
1884 }
1885 $members = new Members($filters);
1886
1887 if (!is_array($post['id'])) {
1888 $ids = (array)$post['id'];
1889 } else {
1890 $ids = $post['id'];
1891 }
1892
1893 return $members->removeMembers($ids);
1894 }
1895
1896 // CRUD - Delete
1897 }