]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Repository/Members.php
Search value was not quoted
[galette.git] / galette / lib / Galette / Repository / Members.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Members class
7 *
8 * PHP version 5
9 *
10 * Copyright © 2009-2014 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 Repository
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2009-2014 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @version SVN: $Id$
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.7dev - 2009-02-28
36 */
37
38 namespace Galette\Repository;
39
40 use Galette\DynamicFields\DynamicField;
41 use Galette\Entity\DynamicFieldsHandle;
42
43 use Analog\Analog;
44 use Zend\Db\Sql\Expression;
45 use Zend\Db\Sql\Predicate\PredicateSet;
46 use Zend\Db\Sql\Predicate\Operator;
47 use Galette\Entity\Adherent;
48 use Galette\Entity\Contribution;
49 use Galette\Entity\Transaction;
50 use Galette\Entity\Reminder;
51 use Galette\Filters\MembersList;
52 use Galette\Filters\AdvancedMembersList;
53 use Galette\Core\Picture;
54 use Galette\Entity\Group;
55 use Galette\Repository\Groups;
56 use Galette\Entity\Status;
57 use Galette\Core\Db;
58
59 /**
60 * Members class for galette
61 *
62 * @name Members
63 * @category Repository
64 * @package Galette
65 *
66 * @author Johan Cwiklinski <johan@x-tnd.be>
67 * @copyright 2009-2014 The Galette Team
68 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
69 * @link http://galette.tuxfamily.org
70 */
71 class Members
72 {
73 const TABLE = Adherent::TABLE;
74 const PK = Adherent::PK;
75
76 const ALL_ACCOUNTS = 0;
77 const ACTIVE_ACCOUNT = 1;
78 const INACTIVE_ACCOUNT = 2;
79
80 const SHOW_LIST = 0;
81 const SHOW_PUBLIC_LIST = 1;
82 const SHOW_ARRAY_LIST = 2;
83 const SHOW_STAFF = 3;
84 const SHOW_MANAGED = 4;
85 const SHOW_EXPORT = 5;
86
87 const FILTER_NAME = 0;
88 const FILTER_ADDRESS = 1;
89 const FILTER_MAIL = 2;
90 const FILTER_JOB = 3;
91 const FILTER_INFOS = 4;
92 const FILTER_DC_EMAIL = 5;
93 const FILTER_W_EMAIL = 6;
94 const FILTER_WO_EMAIL = 7;
95 const FILTER_COMPANY_NAME = 8;
96 const FILTER_DC_PUBINFOS = 9;
97 const FILTER_W_PUBINFOS = 10;
98 const FILTER_WO_PUBINFOS = 11;
99 const FILTER_NUMBER = 12;
100
101 const MEMBERSHIP_ALL = 0;
102 const MEMBERSHIP_UP2DATE = 3;
103 const MEMBERSHIP_NEARLY = 1;
104 const MEMBERSHIP_LATE = 2;
105 const MEMBERSHIP_NEVER = 4;
106 const MEMBERSHIP_STAFF = 5;
107 const MEMBERSHIP_ADMIN = 6;
108 const MEMBERSHIP_NONE = 7;
109
110 const ORDERBY_NAME = 0;
111 const ORDERBY_NICKNAME = 1;
112 const ORDERBY_STATUS = 2;
113 const ORDERBY_FEE_STATUS = 3;
114 const ORDERBY_MODIFDATE = 4;
115 const ORDERBY_ID = 5;
116
117 const NON_STAFF_MEMBERS = 30;
118
119 private $filters = false;
120 private $count = null;
121 private $errors = array();
122
123 /**
124 * Default constructor
125 *
126 * @param MembersList $filters Filtering
127 */
128 public function __construct($filters = null)
129 {
130 if ($filters === null) {
131 $this->filters = new MembersList();
132 } else {
133 $this->filters = $filters;
134 }
135 }
136
137 /**
138 * Get staff members list
139 *
140 * @param bool $as_members return the results as an array of
141 * Member object.
142 * @param array $fields field(s) name(s) to get. Should be a string or
143 * an array. If null, all fields will be
144 * returned
145 * @param boolean $count true if we want to count members
146 * @param boolean $limit true to LIMIT query
147 *
148 * @return Adherent[]|ResultSet
149 */
150 public function getStaffMembersList(
151 $as_members = false,
152 $fields = null,
153 $count = true,
154 $limit = true
155 ) {
156 return $this->getMembersList(
157 $as_members,
158 $fields,
159 $count,
160 true,
161 false,
162 $limit
163 );
164 }
165
166 /**
167 * Get managed members list (for groups managers)
168 *
169 * @param bool $as_members return the results as an array of
170 * Member object.
171 * @param array $fields field(s) name(s) to get. Should be a string or
172 * an array. If null, all fields will be
173 * returned
174 * @param boolean $count true if we want to count members
175 * @param boolean $limit true to LIMIT query
176 *
177 * @return Adherent[]|ResultSet
178 */
179 public function getManagedMembersList(
180 $as_members = false,
181 $fields = null,
182 $count = true,
183 $limit = true
184 ) {
185 return $this->getMembersList(
186 $as_members,
187 $fields,
188 $count,
189 false,
190 true,
191 $limit
192 );
193 }
194
195 /**
196 * Get members list
197 *
198 * @param bool $as_members return the results as an array of
199 * Member object.
200 * @param array $fields field(s) name(s) to get. Should be a string or
201 * an array. If null, all fields will be
202 * returned
203 * @param boolean $count true if we want to count members
204 * @param boolean $staff true if we want only staff members
205 * @param boolean $managed true if we want only managed groups
206 * @param boolean $limit true if we want records pagination
207 * @param boolean $export true if we are exporting
208 *
209 * @return Adherent[]|ResultSet
210 */
211 public function getMembersList(
212 $as_members = false,
213 $fields = null,
214 $count = true,
215 $staff = false,
216 $managed = false,
217 $limit = true,
218 $export = false
219 ) {
220 global $zdb;
221
222 if ($limit === true) {
223 //force count if limit is active
224 $count = true;
225 }
226
227 try {
228 $_mode = self::SHOW_LIST;
229 if ($staff !== false) {
230 $_mode = self::SHOW_STAFF;
231 }
232 if ($managed !== false) {
233 $_mode = self::SHOW_MANAGED;
234 }
235 if ($export !== false) {
236 $_mode = self::SHOW_EXPORT;
237 }
238
239 $select = $this->buildSelect(
240 $_mode,
241 $fields,
242 false,
243 $count
244 );
245
246 //add limits to retrieve only relavant rows
247 if ($limit === true) {
248 $this->filters->setLimits($select);
249 }
250
251 $rows = $zdb->execute($select);
252 $this->filters->query = $zdb->query_string;
253
254 $members = array();
255 if ($as_members) {
256 $deps = array(
257 'picture' => false,
258 'groups' => false
259 );
260 foreach ($rows as $row) {
261 $members[] = new Adherent($zdb, $row, $deps);
262 }
263 } else {
264 $members = $rows;
265 }
266 return $members;
267 } catch (\Exception $e) {
268 Analog::log(
269 'Cannot list members | ' . $e->getMessage(),
270 Analog::WARNING
271 );
272 }
273 }
274
275 /**
276 * Remove specified members
277 *
278 * @param integer|array $ids Members identifiers to delete
279 *
280 * @return boolean
281 */
282 public function removeMembers($ids)
283 {
284 global $zdb, $hist;
285
286 $list = array();
287 if (is_numeric($ids)) {
288 //we've got only one identifier
289 $list[] = $ids;
290 } else {
291 $list = $ids;
292 }
293
294 if (is_array($list)) {
295 try {
296 $zdb->connection->beginTransaction();
297
298 //Retrieve some informations
299 $select = $zdb->select(self::TABLE);
300 $select->columns(
301 array(self::PK, 'nom_adh', 'prenom_adh')
302 )->where->in(self::PK, $list);
303
304 $results = $zdb->execute($select);
305
306 $infos = null;
307 foreach ($results as $member) {
308 $str_adh = $member->id_adh . ' (' . $member->nom_adh . ' ' .
309 $member->prenom_adh . ')';
310 $infos .= $str_adh . "\n";
311
312 $p = new Picture($member->id_adh);
313 if ($p->hasPicture()) {
314 if (!$p->delete(false)) {
315 Analog::log(
316 'Unable to delete picture for member ' . $str_adh,
317 Analog::ERROR
318 );
319 throw new \Exception(
320 'Unable to delete picture for member ' .
321 $str_adh
322 );
323 } else {
324 $hist->add(
325 _T("Member Picture deleted"),
326 $str_adh
327 );
328 }
329 }
330 }
331
332 //delete contributions
333 $del_qry = $zdb->delete(Contribution::TABLE);
334 $del_qry->where->in(
335 self::PK,
336 $list
337 );
338 $zdb->execute($del_qry);
339
340 //get transactions
341 $select = $zdb->select(Transaction::TABLE);
342 $select->where->in(self::PK, $list);
343 $results = $zdb->execute($select);
344
345 //if members has transactions;
346 //reset link with other contributions
347 //and remove them
348 if ($results->count() > 0) {
349 $transactions = [];
350 foreach ($results as $transaction) {
351 $transactions[] = $transaction[Transaction::PK];
352 }
353
354 $update = $zdb->update(Contribution::TABLE);
355 $update->set([
356 Transaction::PK => new Expression('NULL')
357 ])->where->in(
358 Transaction::PK,
359 $transactions
360 );
361 $zdb->execute($update);
362 }
363
364 //delete transactions
365 $del_qry = $zdb->delete(Transaction::TABLE);
366 $del_qry->where->in(self::PK, $list);
367 $zdb->execute($del_qry);
368
369 //delete groups membership/mamagmentship
370 Groups::removeMembersFromGroups($list);
371
372 //delete reminders
373 $del_qry = $zdb->delete(Reminder::TABLE);
374 $del_qry->where->in(
375 'reminder_dest',
376 $list
377 );
378 $zdb->execute($del_qry);
379
380 //delete dynamic fields values
381 $del_qry = $zdb->delete(DynamicFieldsHandle::TABLE);
382 $del_qry->where(['field_form' => 'adh']);
383 $del_qry->where->in('item_id', $list);
384 $zdb->execute($del_qry);
385
386 //delete members
387 $del_qry = $zdb->delete(self::TABLE);
388 $del_qry->where->in(
389 self::PK,
390 $list
391 );
392 $zdb->execute($del_qry);
393
394 //commit all changes
395 $zdb->connection->commit();
396
397 //add an history entry
398 $hist->add(
399 _T("Delete members cards, transactions and dues"),
400 $infos
401 );
402
403 return true;
404 } catch (\Exception $e) {
405 $zdb->connection->rollBack();
406 if ($e instanceof \Zend_Db_Statement_Exception
407 && $e->getCode() == 23000
408 ) {
409 Analog::log(
410 'Member still have existing dependencies in the ' .
411 'database, maybe a mailing or some content from a ' .
412 'plugin. Please remove dependencies before trying ' .
413 'to remove him.',
414 Analog::ERROR
415 );
416 $this->errors[] = _T("Cannot remove a member who still have dependencies (mailings, ...)");
417 } else {
418 Analog::log(
419 'Unable to delete selected member(s) |' .
420 $e->getMessage(),
421 Analog::ERROR
422 );
423 }
424 return false;
425 }
426 } else {
427 //not numeric and not an array: incorrect.
428 Analog::log(
429 'Asking to remove members, but without providing an array or a single numeric value.',
430 Analog::ERROR
431 );
432 return false;
433 }
434 }
435
436 /**
437 * Get members list
438 *
439 * @param boolean $as_members return the results as an array of
440 * Member object.
441 * @param array $fields field(s) name(s) to get. Should be a string or
442 * an array. If null, all fields will be
443 * returned
444 *
445 * @return Adherent[]|ResultSet
446 */
447 public function getList($as_members = false, $fields = null)
448 {
449 return $this->getMembersList(
450 $as_members,
451 $fields,
452 false,
453 false,
454 false,
455 true,
456 false
457 );
458 }
459
460 /**
461 * Get members list with public informations available
462 *
463 * @param boolean $with_photos get only members which have uploaded a
464 * photo (for trombinoscope)
465 *
466 * @return Adherent[]
467 */
468 public function getPublicList($with_photos)
469 {
470 global $zdb;
471
472 try {
473 $select = $this->buildSelect(
474 self::SHOW_PUBLIC_LIST,
475 null,
476 $with_photos
477 );
478
479 if ($this->filters) {
480 $select->order($this->buildOrderClause(null));
481 }
482
483 $this->proceedCount($select);
484
485 $this->filters->setLimits($select);
486
487 $results = $zdb->execute($select);
488 $members = array();
489 foreach ($results as $row) {
490 $deps = array(
491 'groups' => false,
492 'dues' => false,
493 'picture' => $with_photos
494 );
495 $members[] = new Adherent($zdb, $row, $deps);
496 }
497 return $members;
498 } catch (\Exception $e) {
499 Analog::log(
500 'Cannot list members with public informations (photos: '
501 . $with_photos . ') | ' . $e->getMessage(),
502 Analog::WARNING
503 );
504 return false;
505 }
506 }
507
508 /**
509 * Get list of members that has been selected
510 *
511 * @param array $ids an array of members id that has been selected
512 * @param array $orderby SQL order clause (optionnal)
513 * @param boolean $with_photos Should photos be loaded?
514 * @param boolean $as_members Return Adherent[] or simple ResultSet
515 * @param array $fields Fields to use
516 * @param boolean $export True if we are exporting
517 * @param boolean $dues True if load dues as Adherent dependency
518 * @param boolean $parent True if load parent as Adherent dependency
519 *
520 * @return Adherent[]
521 */
522 public function getArrayList(
523 $ids,
524 $orderby = null,
525 $with_photos = false,
526 $as_members = true,
527 $fields = null,
528 $export = false,
529 $dues = false,
530 $parent = false
531 ) {
532 global $zdb;
533
534 if (!is_array($ids) || count($ids) < 1) {
535 Analog::log('No member selected for labels.', Analog::INFO);
536 return false;
537 }
538
539 try {
540 $damode = self::SHOW_ARRAY_LIST;
541 if ($export === true) {
542 $damode = self::SHOW_EXPORT;
543 }
544 $select = $this->buildSelect(
545 $damode,
546 $fields,
547 false,
548 false
549 );
550 $select->where->in('a.' . self::PK, $ids);
551 if ($orderby != null && count($orderby) > 0) {
552 if (is_array($orderby)) {
553 foreach ($orderby as $o) {
554 $select->order($o);
555 }
556 } else {
557 $select->order($orderby);
558 }
559 }
560
561 $results = $zdb->execute($select);
562
563 $members = array();
564 foreach ($results as $o) {
565 $deps = array(
566 'picture' => $with_photos,
567 'groups' => false,
568 'dues' => $dues,
569 'parent' => $parent
570 );
571 if ($as_members === true) {
572 $members[] = new Adherent($zdb, $o, $deps);
573 } else {
574 $members[] = $o;
575 }
576 }
577 return $members;
578 } catch (\Exception $e) {
579 Analog::log(
580 'Cannot load members form ids array | ' . $e->getMessage(),
581 Analog::WARNING
582 );
583 }
584 }
585
586 /**
587 * Builds the SELECT statement
588 *
589 * @param int $mode the current mode (see self::SHOW_*)
590 * @param array $fields fields list to retrieve
591 * @param bool $photos true if we want to get only members with photos
592 * Default to false, only relevant for SHOW_PUBLIC_LIST
593 * @param bool $count true if we want to count members, defaults to false
594 *
595 * @return Select SELECT statement
596 */
597 private function buildSelect($mode, $fields, $photos, $count = false)
598 {
599 global $zdb, $login;
600
601 try {
602 if ($fields != null && is_array($fields) && !in_array('id_adh', $fields)) {
603 $fields[] = 'id_adh';
604 }
605 $fieldsList = ( $fields != null )
606 ? (( !is_array($fields) || count($fields) < 1 ) ? (array)'*'
607 : $fields) : (array)'*';
608
609 $select = $zdb->select(self::TABLE, 'a');
610
611 $select->columns($fieldsList);
612
613 $select->quantifier('DISTINCT');
614
615 switch ($mode) {
616 case self::SHOW_STAFF:
617 case self::SHOW_LIST:
618 case self::SHOW_ARRAY_LIST:
619 $select->join(
620 array('p' => PREFIX_DB . Status::TABLE),
621 'a.' . Status::PK . '=p.' . Status::PK,
622 array()
623 );
624 break;
625 case self::SHOW_EXPORT:
626 //basically the same as above, but without any fields
627 $select->join(
628 array('p' => PREFIX_DB . Status::TABLE),
629 'a.' . Status::PK . '=p.' . Status::PK,
630 array()
631 );
632 break;
633 case self::SHOW_MANAGED:
634 $select->join(
635 array('p' => PREFIX_DB . Status::TABLE),
636 'a.' . Status::PK . '=p.' . Status::PK
637 )->join(
638 array('gr' => PREFIX_DB . Group::GROUPSUSERS_TABLE),
639 'a.' . Adherent::PK . '=gr.' . Adherent::PK,
640 array()
641 )->join(
642 array('m' => PREFIX_DB . Group::GROUPSMANAGERS_TABLE),
643 'gr.' . Group::PK . '=m.' . Group::PK,
644 array()
645 )->where('m.' . Adherent::PK . ' = ' . $login->id);
646 break;
647 case self::SHOW_PUBLIC_LIST:
648 if ($photos) {
649 $select->join(
650 array('p' => PREFIX_DB . Picture::TABLE),
651 'a.' . self::PK . '= p.' . self::PK
652 );
653 }
654 break;
655 }
656
657 //check for contributions filtering
658 if ($this->filters instanceof AdvancedMembersList
659 && $this->filters->withinContributions()
660 ) {
661 $select->join(
662 array('ct' => PREFIX_DB . Contribution::TABLE),
663 'ct.' . self::PK . '=a.' . self::PK,
664 array(),
665 $select::JOIN_LEFT
666 );
667 }
668
669 //check if there are dynamic fields in filter
670 $hasDf = false;
671 $dfs = array();
672
673 if ($this->filters instanceof AdvancedMembersList
674 && $this->filters->free_search
675 && count($this->filters->free_search) > 0
676 && !isset($this->filters->free_search['empty'])
677 ) {
678 $free_searches = $this->filters->free_search;
679 foreach ($free_searches as $fs) {
680 if (strpos($fs['field'], 'dyn_') === 0) {
681 // simple dynamic fields
682 $hasDf = true;
683 $dfs[] = str_replace('dyn_', '', $fs['field']);
684 }
685 }
686 }
687
688 //check if there are dynamic fields for contributions in filter
689 $hasDfc = false;
690 $hasCdfc = false;
691 $cdfcs = array();
692
693 if ($this->filters instanceof AdvancedMembersList
694 && $this->filters->withinContributions()
695 ) {
696 if ($this->filters->contrib_dynamic
697 && count($this->filters->contrib_dynamic) > 0
698 && !isset($this->filters->contrib_dynamic['empty'])
699 ) {
700 $hasDfc = true;
701
702 //check if there are dynamic fields in the filter
703 foreach ($this->filters->contrib_dynamic as $k => $cd) {
704 if (is_array($cd)) {
705 $hasCdfc = true;
706 $cdfcs[] = $k;
707 }
708 }
709 }
710 }
711
712 if ($hasDfc === true || $hasCdfc === true) {
713 $select->join(
714 array('dfc' => PREFIX_DB . DynamicFieldsHandle::TABLE),
715 'dfc.item_id=ct.' . Contribution::PK,
716 array(),
717 $select::JOIN_LEFT
718 );
719 }
720
721 // simple dynamic fields
722 if ($hasDf === true) {
723 foreach ($dfs as $df) {
724 $subselect = $zdb->select(DynamicFieldsHandle::TABLE, 'df');
725 $subselect->columns(
726 [
727 'item_id' => 'item_id',
728 'val' => 'field_val'
729 ]
730 );
731 $subselect->where('df.field_form = \'adh\'');
732 $subselect->where('df.field_id = ' . $df);
733 $select->join(
734 array('df' . $df => $subselect),
735 'a.id_adh = df' . $df . '.item_id',
736 array(),
737 $select::JOIN_LEFT
738 );
739 }
740 }
741
742 // choice dynamic fields
743 if ($hasCdfc === true) {
744 $cdf_field = 'cdf.id';
745 if (TYPE_DB === 'pgsql') {
746 $cdf_field .= '::text';
747 }
748
749 $cdf_field = 'cdfc.id';
750 if (TYPE_DB === 'pgsql') {
751 $cdf_field .= '::text';
752 }
753 foreach ($cdfcs as $cdf) {
754 $rcdf_field = str_replace(
755 'cdfc.',
756 'cdfc' . $cdf . '.',
757 $cdf_field
758 );
759 $select->join(
760 array('cdfc' . $cdf => DynamicField::getFixedValuesTableName($cdf, true)),
761 $rcdf_field . '=dfc.field_val',
762 array(),
763 $select::JOIN_LEFT
764 );
765 }
766 }
767
768 if ($mode == self::SHOW_LIST || $mode == self::SHOW_MANAGED) {
769 if ($this->filters !== false) {
770 $this->buildWhereClause($select);
771 }
772 $select->order($this->buildOrderClause($fields));
773 } elseif ($mode == self::SHOW_PUBLIC_LIST) {
774 $select->where(
775 array(
776 new PredicateSet(
777 array(
778 new Operator(
779 'date_echeance',
780 '>=',
781 date('Y-m-d')
782 ),
783 new Operator(
784 'bool_exempt_adh',
785 '=',
786 new Expression('true')
787 )
788 ),
789 PredicateSet::OP_OR
790 ),
791 new PredicateSet(
792 array(
793 new Operator(
794 'bool_display_info',
795 '=',
796 new Expression('true')
797 ),
798 new Operator(
799 'activite_adh',
800 '=',
801 new Expression('true')
802 )
803 ),
804 PredicateSet::OP_AND
805 )
806 )
807 );
808 }
809
810 if ($mode === self::SHOW_STAFF) {
811 $select->where->lessThan(
812 'p.priorite_statut',
813 self::NON_STAFF_MEMBERS
814 );
815 }
816
817 if ($count) {
818 $this->proceedCount($select);
819 }
820
821 return $select;
822 } catch (\Exception $e) {
823 Analog::log(
824 'Cannot build SELECT clause for members | ' . $e->getMessage(),
825 Analog::WARNING
826 );
827 return false;
828 }
829 }
830
831 /**
832 * Count members from the query
833 *
834 * @param Select $select Original select
835 *
836 * @return void
837 */
838 private function proceedCount($select)
839 {
840 global $zdb;
841
842 try {
843 $countSelect = clone $select;
844 $countSelect->reset($countSelect::COLUMNS);
845 $countSelect->reset($countSelect::ORDER);
846 $countSelect->reset($countSelect::HAVING);
847 $countSelect->columns(
848 array(
849 'count' => new Expression('count(DISTINCT a.' . self::PK . ')')
850 )
851 );
852
853 $have = $select->having;
854 if ($have->count() > 0) {
855 foreach ($have->getPredicates() as $h) {
856 $countSelect->where($h);
857 }
858 }
859
860 $results = $zdb->execute($countSelect);
861
862 $this->count = $results->current()->count;
863 if (isset($this->filters) && $this->count > 0) {
864 $this->filters->setCounter($this->count);
865 }
866 } catch (\Exception $e) {
867 Analog::log(
868 'Cannot count members | ' . $e->getMessage(),
869 Analog::WARNING
870 );
871 return false;
872 }
873 }
874
875 /**
876 * Builds the order clause
877 *
878 * @param array $fields Fields list to ensure ORDER clause
879 * references selected fields. Optionnal.
880 *
881 * @return string SQL ORDER clause
882 */
883 private function buildOrderClause($fields = null)
884 {
885 $order = array();
886
887 switch ($this->filters->orderby) {
888 case self::ORDERBY_NICKNAME:
889 if ($this->canOrderBy('pseudo_adh', $fields)) {
890 $order[] = 'pseudo_adh ' . $this->filters->getDirection();
891 }
892 break;
893 case self::ORDERBY_STATUS:
894 if ($this->canOrderBy('priorite_statut', $fields)) {
895 $order[] = 'priorite_statut ' . $this->filters->getDirection();
896 }
897 break;
898 case self::ORDERBY_MODIFDATE:
899 if ($this->canOrderBy('date_modif_adh', $fields)) {
900 $order[] = 'date_modif_adh ' . $this->filters->getDirection();
901 }
902 break;
903 case self::ORDERBY_FEE_STATUS:
904 if ($this->canOrderBy('bool_exempt_adh', $fields)) {
905 $order[] = 'bool_exempt_adh ' . $this->filters->getDirection();
906 }
907
908 if ($this->canOrderBy('date_echeance', $fields)) {
909 $order[] = 'date_echeance ' . $this->filters->getDirection();
910 }
911 break;
912 case self::ORDERBY_ID:
913 if ($this->canOrderBy('id_adh', $fields)) {
914 $order[] = 'id_adh ' . $this->filters->getDirection();
915 }
916 break;
917 }
918
919 //anyways, we want to order by firstname, lastname
920 if ($this->canOrderBy('nom_adh', $fields)) {
921 $order[] = 'nom_adh ' . $this->filters->getDirection();
922 }
923 if ($this->canOrderBy('prenom_adh', $fields)) {
924 $order[] = 'prenom_adh ' . $this->filters->getDirection();
925 }
926 return $order;
927 }
928
929 /**
930 * Is field allowed to order? it shoulsd be present in
931 * provided fields list (those that are SELECT'ed).
932 *
933 * @param string $field_name Field name to order by
934 * @param array $fields SELECTE'ed fields
935 *
936 * @return boolean
937 */
938 private function canOrderBy($field_name, $fields)
939 {
940 if (!is_array($fields)) {
941 return true;
942 } elseif (in_array($field_name, $fields)) {
943 return true;
944 } else {
945 Analog::log(
946 'Trying to order by ' . $field_name . ' while it is not in ' .
947 'selected fields.',
948 Analog::WARNING
949 );
950 return false;
951 }
952 }
953
954 /**
955 * Builds where clause, for filtering on simple list mode
956 *
957 * @param Select $select Original select
958 *
959 * @return string SQL WHERE clause
960 */
961 private function buildWhereClause($select)
962 {
963 global $zdb, $login;
964
965 try {
966 if ($this->filters->email_filter == self::FILTER_W_EMAIL) {
967 $select->where('email_adh != \'\'');
968 }
969 if ($this->filters->email_filter == self::FILTER_WO_EMAIL) {
970 $select->where('(email_adh = \'\' OR email_adh IS NULL)');
971 }
972
973 if ($this->filters->filter_str != '') {
974 $token = $zdb->platform->quoteValue(
975 '%' . strtolower($this->filters->filter_str) . '%'
976 );
977 switch ($this->filters->field_filter) {
978 case self::FILTER_NAME:
979 if (TYPE_DB === 'pgsql') {
980 $sep = " || ' ' || ";
981 $pre = '';
982 $post = '';
983 } else {
984 $sep = ', " ", ';
985 $pre = 'CONCAT(';
986 $post=')';
987 }
988 //$sep = ( TYPE_DB === 'pgsql' ) ? " || ' ' || " : ', " ", ';
989 $select->where(
990 '(' .
991 $pre . 'LOWER(nom_adh)' . $sep .
992 'LOWER(prenom_adh)' . $sep .
993 'LOWER(pseudo_adh)' . $post . ' LIKE ' .
994 $token
995 . ' OR ' .
996 $pre . 'LOWER(prenom_adh)' . $sep .
997 'LOWER(nom_adh)' . $sep .
998 'LOWER(pseudo_adh)' . $post . ' LIKE ' .
999 $token
1000 . ')'
1001 );
1002 break;
1003 case self::FILTER_COMPANY_NAME:
1004 $select->where(
1005 'LOWER(societe_adh) LIKE ' .
1006 $token
1007 );
1008 break;
1009 case self::FILTER_ADDRESS:
1010 $select->where(
1011 '(' .
1012 'LOWER(adresse_adh) LIKE ' . $token
1013 . ' OR ' .
1014 'LOWER(adresse2_adh) LIKE ' . $token
1015 . ' OR ' .
1016 'cp_adh LIKE ' . $token
1017 . ' OR ' .
1018 'LOWER(ville_adh) LIKE ' . $token
1019 . ' OR ' .
1020 'LOWER(pays_adh) LIKE ' . $token
1021 . ')'
1022 );
1023 break;
1024 case self::FILTER_MAIL:
1025 $select->where(
1026 '(' .
1027 'LOWER(email_adh) LIKE ' . $token
1028 . ' OR ' .
1029 'LOWER(url_adh) LIKE ' . $token
1030 . ' OR ' .
1031 'LOWER(msn_adh) LIKE ' . $token
1032 . ' OR ' .
1033 'LOWER(icq_adh) LIKE ' . $token
1034 . ' OR ' .
1035 'LOWER(jabber_adh) LIKE ' . $token
1036 . ')'
1037 );
1038 break;
1039 case self::FILTER_JOB:
1040 $select->where(
1041 'LOWER(prof_adh) LIKE ' . $token
1042 );
1043 break;
1044 case self::FILTER_INFOS:
1045 $more = '';
1046 if ($login->isAdmin() || $login->isStaff()) {
1047 $more = ' OR LOWER(info_adh) LIKE ' . $token;
1048 }
1049 $select->where(
1050 '(LOWER(info_public_adh) LIKE ' .
1051 $token . $more . ')'
1052 );
1053 break;
1054 case self::FILTER_NUMBER:
1055 $select->where->equalTo('a.id_adh', $this->filters->filter_str);
1056 break;
1057 }
1058 }
1059
1060 if ($this->filters->membership_filter) {
1061 switch ($this->filters->membership_filter) {
1062 case self::MEMBERSHIP_NEARLY:
1063 $now = new \DateTime();
1064 $duedate = new \DateTime();
1065 $duedate->modify('+1 month');
1066 $select->where->greaterThanOrEqualTo(
1067 'date_echeance',
1068 $now->format('Y-m-d')
1069 )->lessThan(
1070 'date_echeance',
1071 $duedate->format('Y-m-d')
1072 );
1073 break;
1074 case self::MEMBERSHIP_LATE:
1075 $select->where
1076 ->lessThan(
1077 'date_echeance',
1078 date('Y-m-d', time())
1079 )->equalTo('bool_exempt_adh', new Expression('false'));
1080 break;
1081 case self::MEMBERSHIP_UP2DATE:
1082 $select->where(
1083 '(' . 'date_echeance >= \'' . date('Y-m-d', time())
1084 . '\' OR bool_exempt_adh=true)'
1085 );
1086 break;
1087 case self::MEMBERSHIP_NEVER:
1088 $select->where('date_echeance IS NULL')
1089 ->where('bool_exempt_adh = false');
1090 break;
1091 case self::MEMBERSHIP_STAFF:
1092 $select->where->lessThan(
1093 'p.priorite_statut',
1094 self::NON_STAFF_MEMBERS
1095 );
1096 break;
1097 case self::MEMBERSHIP_ADMIN:
1098 $select->where->equalTo('bool_admin_adh', true);
1099 break;
1100 case self::MEMBERSHIP_NONE:
1101 $select->where->equalTo('a.id_statut', Status::DEFAULT_STATUS);
1102 break;
1103 }
1104 }
1105
1106 if ($this->filters->filter_account) {
1107 switch ($this->filters->filter_account) {
1108 case self::ACTIVE_ACCOUNT:
1109 $select->where('activite_adh=true');
1110 break;
1111 case self::INACTIVE_ACCOUNT:
1112 $select->where('activite_adh=false');
1113 break;
1114 }
1115 }
1116
1117 if ($this->filters->group_filter) {
1118 $select->join(
1119 array('g' => PREFIX_DB . Group::GROUPSUSERS_TABLE),
1120 'a.' . Adherent::PK . '=g.' . Adherent::PK,
1121 array(),
1122 $select::JOIN_LEFT
1123 )->join(
1124 array('gs' => PREFIX_DB . Group::TABLE),
1125 'gs.' . Group::PK . '=g.' . Group::PK,
1126 array(),
1127 $select::JOIN_LEFT
1128 )->where(
1129 '(g.' . Group::PK . ' = ' . $this->filters->group_filter .
1130 ' OR gs.parent_group = NULL OR gs.parent_group = ' .
1131 $this->filters->group_filter . ')'
1132 );
1133 }
1134
1135 if ($this->filters instanceof AdvancedMembersList) {
1136 if ($this->filters->rbirth_date_begin
1137 || $this->filters->rbirth_date_end
1138 ) {
1139 if ($this->filters->rbirth_date_begin) {
1140 $d = new \DateTime($this->filters->rbirth_date_begin);
1141 $select->where->greaterThanOrEqualTo(
1142 'ddn_adh',
1143 $d->format('Y-m-d')
1144 );
1145 }
1146 if ($this->filters->rbirth_date_end) {
1147 $d = new \DateTime($this->filters->rbirth_date_end);
1148 $select->where->lessThanOrEqualTo(
1149 'ddn_adh',
1150 $d->format('Y-m-d')
1151 );
1152 }
1153 }
1154
1155 if ($this->filters->rcreation_date_begin
1156 || $this->filters->rcreation_date_end
1157 ) {
1158 if ($this->filters->rcreation_date_begin) {
1159 $d = new \DateTime($this->filters->rcreation_date_begin);
1160 $select->where->greaterThanOrEqualTo(
1161 'date_crea_adh',
1162 $d->format('Y-m-d')
1163 );
1164 }
1165 if ($this->filters->rcreation_date_end) {
1166 $d = new \DateTime($this->filters->rcreation_date_end);
1167 $select->where->lessThanOrEqualTo(
1168 'date_crea_adh',
1169 $d->format('Y-m-d')
1170 );
1171 }
1172 }
1173
1174 if ($this->filters->rmodif_date_begin
1175 || $this->filters->rmodif_date_end
1176 ) {
1177 if ($this->filters->rmodif_date_begin) {
1178 $d = new \DateTime($this->filters->rmodif_date_begin);
1179 $select->where->greaterThanOrEqualTo(
1180 'date_modif_adh',
1181 $d->format('Y-m-d')
1182 );
1183 }
1184 if ($this->filters->rmodif_date_end) {
1185 $d = new \DateTime($this->filters->rmodif_date_end);
1186 $select->where->lessThanOrEqualTo(
1187 'date_modif_adh',
1188 $d->format('Y-m-d')
1189 );
1190 }
1191 }
1192
1193 if ($this->filters->rdue_date_begin
1194 || $this->filters->rdue_date_end
1195 ) {
1196 if ($this->filters->rdue_date_begin) {
1197 $d = new \DateTime($this->filters->rdue_date_begin);
1198 $select->where->greaterThanOrEqualTo(
1199 'date_echeance',
1200 $d->format('Y-m-d')
1201 );
1202 }
1203 if ($this->filters->rdue_date_end) {
1204 $d = new \DateTime($this->filters->rdue_date_end);
1205 $select->where->lessThanOrEqualTo(
1206 'date_echeance',
1207 $d->format('Y-m-d')
1208 );
1209 }
1210 }
1211
1212 if ($this->filters->show_public_infos) {
1213 switch ($this->filters->show_public_infos) {
1214 case self::FILTER_W_PUBINFOS:
1215 $select->where('bool_display_info = true');
1216 break;
1217 case self::FILTER_WO_PUBINFOS:
1218 $select->where('bool_display_info = false');
1219 break;
1220 case self::FILTER_DC_PUBINFOS:
1221 //nothing to do here.
1222 break;
1223 }
1224 }
1225
1226 if ($this->filters->status) {
1227 $select->where->in(
1228 'a.id_statut',
1229 $this->filters->status
1230 );
1231 }
1232
1233 if ($this->filters->rcontrib_creation_date_begin
1234 || $this->filters->rcontrib_creation_date_end
1235 ) {
1236 if ($this->filters->rcontrib_creation_date_begin) {
1237 $d = new \DateTime(
1238 $this->filters->rcontrib_creation_date_begin
1239 );
1240 $select->where->greaterThanOrEqualTo(
1241 'ct.date_enreg',
1242 $d->format('Y-m-d')
1243 );
1244 }
1245 if ($this->filters->rcontrib_creation_date_end) {
1246 $d = new \DateTime(
1247 $this->filters->rcontrib_creation_date_end
1248 );
1249 $select->where->lessThanOrEqualTo(
1250 'ct.date_enreg',
1251 $d->format('Y-m-d')
1252 );
1253 }
1254 }
1255
1256 if ($this->filters->rcontrib_begin_date_begin
1257 || $this->filters->rcontrib_begin_date_end
1258 ) {
1259 if ($this->filters->rcontrib_begin_date_begin) {
1260 $d = new \DateTime(
1261 $this->filters->rcontrib_begin_date_begin
1262 );
1263 $select->where->greaterThanOrEqualTo(
1264 'ct.date_debut_cotis',
1265 $d->format('Y-m-d')
1266 );
1267 }
1268 if ($this->filters->rcontrib_begin_date_end) {
1269 $d = new \DateTime(
1270 $this->filters->rcontrib_begin_date_end
1271 );
1272 $select->where->lessThanOrEqualTo(
1273 'ct.date_debut_cotis',
1274 $d->format('Y-m-d')
1275 );
1276 }
1277 }
1278
1279 if ($this->filters->rcontrib_end_date_begin
1280 || $this->filters->rcontrib_end_date_end
1281 ) {
1282 if ($this->filters->rcontrib_end_date_begin) {
1283 $d = new \DateTime(
1284 $this->filters->rcontrib_end_date_begin
1285 );
1286 $select->where->greaterThanOrEqualTo(
1287 'ct.date_fin_cotis',
1288 $d->format('Y-m-d')
1289 );
1290 }
1291 if ($this->filters->rcontrib_end_date_end) {
1292 $d = new \DateTime(
1293 $this->filters->rcontrib_end_date_end
1294 );
1295 $select->where->lessThanOrEqualTo(
1296 'ct.date_fin_cotis',
1297 $d->format('Y-m-d')
1298 );
1299 }
1300 }
1301
1302 if ($this->filters->contrib_min_amount
1303 || $this->filters->contrib_max_amount
1304 ) {
1305 if ($this->filters->contrib_min_amount) {
1306 $select->where->greaterThanOrEqualTo(
1307 'ct.montant_cotis',
1308 $this->filters->contrib_min_amount
1309 );
1310 }
1311 if ($this->filters->contrib_max_amount) {
1312 $select->where->lessThanOrEqualTo(
1313 'ct.montant_cotis',
1314 $this->filters->contrib_max_amount
1315 );
1316 }
1317 }
1318
1319 if ($this->filters->contributions_types) {
1320 $select->where->in(
1321 'ct.id_type_cotis',
1322 $this->filters->contributions_types
1323 );
1324 }
1325
1326 if ($this->filters->payments_types) {
1327 $select->where->in(
1328 'ct.type_paiement_cotis',
1329 $this->filters->payments_types
1330 );
1331 }
1332
1333 if (count($this->filters->contrib_dynamic) > 0
1334 && !isset($this->filters->contrib_dynamic['empty'])
1335 ) {
1336 foreach ($this->filters->contrib_dynamic as $k => $cd) {
1337 $qry = '';
1338 $prefix = 'a.';
1339 $field = null;
1340 $qop = ' LIKE ';
1341
1342 if (is_array($cd)) {
1343 //dynamic choice spotted!
1344 $prefix = 'cdfc' . $k . '.';
1345 $qry = 'dfc.field_form = \'contrib\' AND ' .
1346 'dfc.field_id = ' . $k . ' AND ';
1347 $field = 'id';
1348 $select->where->in($prefix . $field, $cd);
1349 } else {
1350 //dynamic field spotted!
1351 $prefix = 'dfc.';
1352 $qry = 'dfc.field_form = \'contrib\' AND ' .
1353 'dfc.field_id = ' . $k . ' AND ';
1354 $field = 'field_val';
1355 $qry .= 'LOWER(' . $prefix . $field . ') ' .
1356 $qop . ' ' ;
1357 $select->where($qry . $zdb->platform->quoteValue('%' .strtolower($cd) . '%'));
1358 }
1359 }
1360 }
1361
1362 if (count($this->filters->free_search) > 0
1363 && !isset($this->filters->free_search['empty'])
1364 ) {
1365 foreach ($this->filters->free_search as $fs) {
1366 $fs['search'] = mb_strtolower($fs['search']);
1367 $qop = null;
1368 switch ($fs['qry_op']) {
1369 case AdvancedMembersList::OP_EQUALS:
1370 $qop = '=';
1371 break;
1372 case AdvancedMembersList::OP_CONTAINS:
1373 $qop = 'LIKE';
1374 $fs['search'] = '%' . $fs['search'] . '%';
1375 break;
1376 case AdvancedMembersList::OP_NOT_EQUALS:
1377 $qop = '!=';
1378 break;
1379 case AdvancedMembersList::OP_NOT_CONTAINS:
1380 $qop = 'NOT LIKE';
1381 $fs['search'] = '%' . $fs['search'] . '%';
1382 break;
1383 case AdvancedMembersList::OP_STARTS_WITH:
1384 $qop = 'LIKE';
1385 $fs['search'] = $fs['search'] . '%';
1386 break;
1387 case AdvancedMembersList::OP_ENDS_WITH:
1388 $qop = 'LIKE';
1389 $fs['search'] = '%' . $fs['search'];
1390 break;
1391 case AdvancedMembersList::OP_BEFORE:
1392 $qop = '<';
1393 break;
1394 case AdvancedMembersList::OP_AFTER:
1395 $qop = '>';
1396 break;
1397 default:
1398 Analog::log(
1399 'Unknown query operator: ' . $fs['qry_op'] .
1400 ' (will fallback to equals)',
1401 Analog::WARNING
1402 );
1403 $qop = '=';
1404 break;
1405 }
1406
1407 $qry = '';
1408 $prefix = 'a.';
1409 $dyn_field = false;
1410 if (strpos($fs['field'], 'dyn_') === 0) {
1411 // simple dynamic field spotted!
1412 $index = str_replace('dyn_', '', $fs['field']);
1413 $dyn_field = DynamicField::loadFieldType($zdb, (int)$index);
1414 $prefix = 'df' . $index . '.';
1415 $fs['field'] = 'val';
1416 }
1417
1418 if ($dyn_field && $dyn_field instanceof \Galette\DynamicFields\Boolean) {
1419 if ($fs['search'] != 0) {
1420 $qry .= $prefix . $fs['field'] . $qop . ' ' .
1421 $fs['search'] ;
1422 } else {
1423 $qry .= $prefix . $fs['field'] . ' IS NULL';
1424 }
1425 } elseif (!strncmp($fs['field'], 'bool_', strlen('bool_'))) {
1426 $qry .= $prefix . $fs['field'] . $qop . ' ' .
1427 $fs['search'] ;
1428 } elseif ($fs['qry_op'] === AdvancedMembersList::OP_BEFORE
1429 || $fs['qry_op'] === AdvancedMembersList::OP_AFTER
1430 ) {
1431 if ($prefix === 'a.') {
1432 //dates are OK in the main fields. no cast, just query!
1433 $qry .= $prefix . $fs['field'] . $qop . ' ' .
1434 $zdb->platform->quoteValue($fs['search']);
1435 } else {
1436 //dynamic dates are stored in their localized format :/
1437 //use current lang format to query for now
1438 if ($zdb->isPostgres()) {
1439 $fs['search'] = "to_date('" . $fs['search'] . "', 'YYYY-MM-DD')";
1440 $store_fmt = __("Y-m-d") === 'Y-m-d' ? 'YYYY-MM-DD' : 'DD/MM/YYYY';
1441 $qry .= "to_date('" . $prefix . $fs['field'] . "', '$store_fmt')";
1442 } else {
1443 $fs['search'] = "STR_TO_DATE('" . $fs['search'] . "', '%Y-%m-%d')";
1444 $store_fmt = __("Y-m-d") === 'Y-m-d' ? '%Y-%m-%d' : '%d/%m/%Y';
1445 $qry .= 'STR_TO_DATE(' . $prefix . $fs['field'] . ', \'' . $store_fmt . '\') ';
1446 }
1447
1448 $qry .= $qop . ' ' . $fs['search'] ;
1449 }
1450 } elseif ($fs['field'] == 'status_label') {
1451 $qry_pattern = '%p%field %op %value';
1452 $qry .= str_replace(
1453 [
1454 '%p',
1455 '%field',
1456 '%op',
1457 '%value'
1458 ],
1459 [
1460 'p.',
1461 'libelle_statut',
1462 $qop,
1463 $zdb->platform->quoteValue($fs['search'])
1464 ],
1465 $qry_pattern
1466 );
1467 } else {
1468 $qry .= 'LOWER(' . $prefix . $fs['field'] . ') ' .
1469 $qop . ' ' . $zdb->platform->quoteValue($fs['search']);
1470 }
1471
1472 if ($fs['log_op'] === AdvancedMembersList::OP_AND) {
1473 $select->where($qry);
1474 } elseif ($fs['log_op'] === AdvancedMembersList::OP_OR) {
1475 $select->where($qry, PredicateSet::OP_OR);
1476 }
1477 }
1478 }
1479 }
1480 } catch (\Exception $e) {
1481 Analog::log(
1482 __METHOD__ . ' | ' . $e->getMessage(),
1483 Analog::WARNING
1484 );
1485 }
1486 }
1487
1488 /**
1489 * Login and password field cannot be empty.
1490 *
1491 * If those ones are not required, or if a file has been imported
1492 * (from a CSV file for example), we fill here random values.
1493 *
1494 * @return boolean
1495 */
1496 public function emptyLogins()
1497 {
1498 global $zdb;
1499
1500 try {
1501 $zdb->connection->beginTransaction();
1502 $select = $zdb->select(Adherent::TABLE);
1503 $select->columns(
1504 array('id_adh', 'login_adh', 'mdp_adh')
1505 )->where(
1506 array(
1507 'login_adh' => new Expression('NULL'),
1508 'login_adh' => '',
1509 'mdp_adh' => new Expression('NULL'),
1510 'mdp_adh' => ''
1511 ),
1512 PredicateSet::OP_OR
1513 );
1514
1515 $results = $zdb->execute($select);
1516
1517 $processed = 0;
1518 if ($results->count() > 0) {
1519 $update = $zdb->update(Adherent::TABLE);
1520 $update->set(
1521 array(
1522 'login_adh' => ':login',
1523 'mdp_adh' => ':pass'
1524 )
1525 )->where->equalTo(Adherent::PK, ':id');
1526
1527 $stmt = $zdb->sql->prepareStatementForSqlObject($update);
1528
1529 $p = new \Galette\Core\Password($zdb);
1530
1531 foreach ($results as $m) {
1532 $dirty = false;
1533 if ($m->login_adh == ''
1534 || !isset($m->login_adh)
1535 || $m->login_adh == 'NULL'
1536 ) {
1537 $m->login_adh = $p->makeRandomPassword(15);
1538 $dirty = true;
1539 }
1540
1541 if ($m->mdp_adh == ''
1542 || !isset($m->mdp_adh)
1543 || $m->mdp_adh == 'NULL'
1544 ) {
1545 $randomp = $p->makeRandomPassword(15);
1546 $m->mdp_adh = password_hash(
1547 $randomp,
1548 PASSWORD_BCRYPT
1549 );
1550 $dirty = true;
1551 }
1552
1553 if ($dirty === true) {
1554 /** Why where parameter is named where1 ?? */
1555 $stmt->execute(
1556 array(
1557 'login_adh' => $m->login_adh,
1558 'mdp_adh' => $m->mdp_adh,
1559 'where1' => $m->id_adh
1560 )
1561 );
1562 $processed++;
1563 }
1564 }
1565 }
1566 $zdb->connection->commit();
1567 $this->count = $processed;
1568 return true;
1569 } catch (\Exception $e) {
1570 $zdb->connection->rollBack();
1571 Analog::log(
1572 'An error occurred trying to retrieve members with ' .
1573 'empty logins/passwords (' . $e->getMessage(),
1574 Analog::ERROR
1575 );
1576 return false;
1577 }
1578 }
1579
1580 /**
1581 * Loads data to produce a Pie chart based on members state of dues
1582 *
1583 * @return void
1584 */
1585 public function getRemindersCount()
1586 {
1587 global $zdb;
1588
1589 $reminders = array();
1590
1591 $soon_date = new \DateTime();
1592 $soon_date->modify('+1 month');
1593
1594 $now = new \DateTime();
1595
1596 $select = $zdb->select(Adherent::TABLE, 'a');
1597 $select->columns(
1598 array(
1599 'cnt' => new Expression('count(a.' . Adherent::PK . ')')
1600 )
1601 );
1602
1603 $select->join(
1604 array('p' => PREFIX_DB . self::TABLE),
1605 'a.parent_id=p.' . self::PK,
1606 array(),
1607 $select::JOIN_LEFT
1608 );
1609
1610 $select->where
1611 ->lessThan('a.date_echeance', $soon_date->format('Y-m-d'))
1612 ->greaterThanOrEqualTo('a.date_echeance', $now->format('Y-m-d'));
1613 $select
1614 ->where('a.activite_adh=true')
1615 ->where('a.bool_exempt_adh=false');
1616
1617 $select_wo_mail = clone $select;
1618
1619 $select->where('(a.email_adh != \'\' OR p.email_adh != \'\')');
1620 $select_wo_mail->where('a.email_adh = \'\' AND p.email_adh = \'\'');
1621
1622 $results = $zdb->execute($select);
1623 $res = $results->current();
1624 $reminders['impending'] = $res->cnt;
1625
1626 $results_wo_mail = $zdb->execute($select_wo_mail);
1627 $res_wo_mail = $results_wo_mail->current();
1628 $reminders['nomail']['impending'] = $res_wo_mail->cnt;
1629
1630 $select = $zdb->select(Adherent::TABLE, 'a');
1631 $select->columns(
1632 array(
1633 'cnt' => new Expression('count(a.' . Adherent::PK . ')')
1634 )
1635 );
1636
1637 $select->join(
1638 array('p' => PREFIX_DB . self::TABLE),
1639 'a.parent_id=p.' . self::PK,
1640 array(),
1641 $select::JOIN_LEFT
1642 );
1643
1644 $select->where
1645 ->lessThan('a.date_echeance', $now->format('Y-m-d'));
1646 $select
1647 ->where('a.activite_adh=true')
1648 ->where('a.bool_exempt_adh=false');
1649
1650 $select_wo_mail = clone $select;
1651
1652 $select->where('(a.email_adh != \'\' OR p.email_adh != \'\')');
1653 $select_wo_mail->where('a.email_adh = \'\' AND p.email_adh = \'\'');
1654
1655 $results = $zdb->execute($select);
1656 $res = $results->current();
1657 $reminders['late'] = $res->cnt;
1658
1659 $results_wo_mail = $zdb->execute($select_wo_mail);
1660 $res_wo_mail = $results_wo_mail->current();
1661 $reminders['nomail']['late'] = $res_wo_mail->cnt;
1662
1663 return $reminders;
1664 }
1665
1666 /**
1667 * Get count for current query
1668 *
1669 * @return int
1670 */
1671 public function getCount()
1672 {
1673 return $this->count;
1674 }
1675
1676 /**
1677 * Get registered errors
1678 *
1679 * @return array
1680 */
1681 public function getErrors()
1682 {
1683 return $this->errors;
1684 }
1685
1686 /**
1687 * Get all existing emails
1688 *
1689 * @param Db $zdb Database instance
1690 *
1691 * @return array ['email' => 'id_adh']
1692 */
1693 public static function getEmails(Db $zdb)
1694 {
1695 $emails = [];
1696 $select = $zdb->select(self::TABLE);
1697 $select->columns([
1698 self::PK,
1699 'email_adh'
1700 ]);
1701 $select->where('email_adh != \'\' AND email_adh IS NOT NULL');
1702 $rows = $zdb->execute($select);
1703 foreach ($rows as $row) {
1704 $emails[$row->email_adh] = $row->{self::PK};
1705 }
1706 return $emails;
1707 }
1708
1709 /**
1710 * Get current filters
1711 *
1712 * @return MembersList
1713 */
1714 public function getFilters()
1715 {
1716 return $this->filters;
1717 }
1718 }