]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Filters/AdvancedMembersList.php
Remove 'svn' lines
[galette.git] / galette / lib / Galette / Filters / AdvancedMembersList.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Members list advanced filters
7 *
8 * PHP version 5
9 *
10 * Copyright © 2012-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 Filters
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2012-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 * @link http://galette.tuxfamily.org
34 * @since 0.73dev 2012-10-16
35 */
36
37 namespace Galette\Filters;
38
39 use Analog\Analog;
40 use Galette\Entity\Status;
41 use Galette\Entity\ContributionsTypes;
42 use Galette\Entity\Contribution;
43 use Galette\Repository\Members;
44 use Galette\DynamicFields\DynamicField;
45 use Galette\Repository\PaymentTypes;
46
47 /**
48 * Members list filters and paginator
49 *
50 * @name AdvancedMembersList
51 * @category Filters
52 * @package Galette
53 *
54 * @author Johan Cwiklinski <johan@x-tnd.be>
55 * @copyright 2012-2014 The Galette Team
56 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
57 * @link http://galette.tuxfamily.org
58 */
59
60 class AdvancedMembersList extends MembersList
61 {
62
63 const OP_AND = 0;
64 const OP_OR = 1;
65
66 const OP_EQUALS = 0;
67 const OP_CONTAINS = 1;
68 const OP_NOT_EQUALS = 2;
69 const OP_NOT_CONTAINS = 3;
70 const OP_STARTS_WITH = 4;
71 const OP_ENDS_WITH = 5;
72 const OP_BEFORE = 6;
73 const OP_AFTER = 7;
74
75 private $_creation_date_begin;
76 private $_creation_date_end;
77 private $_modif_date_begin;
78 private $_modif_date_end;
79 private $_due_date_begin;
80 private $_due_date_end;
81 private $_birth_date_begin;
82 private $_birth_date_end;
83 private $_show_public_infos = Members::FILTER_DC_PUBINFOS;
84 private $_status = array();
85 private $_contrib_creation_date_begin;
86 private $_contrib_creation_date_end;
87 private $_contrib_begin_date_begin;
88 private $_contrib_begin_date_end;
89 private $_contrib_end_date_begin;
90 private $_contrib_end_date_end;
91 private $_contributions_types;
92 private $_payments_types;
93 private $_contrib_min_amount;
94 private $_contrib_max_amount;
95
96 protected $advancedmemberslist_fields = array(
97 'creation_date_begin',
98 'creation_date_end',
99 'modif_date_begin',
100 'modif_date_end',
101 'due_date_begin',
102 'due_date_end',
103 'birth_date_begin',
104 'birth_date_end',
105 'show_public_infos',
106 'status',
107 'contrib_creation_date_begin',
108 'contrib_creation_date_end',
109 'contrib_begin_date_begin',
110 'contrib_begin_date_end',
111 'contrib_end_date_begin',
112 'contrib_end_date_end',
113 'contributions_types',
114 'payments_types',
115 'contrib_min_amount',
116 'contrib_max_amount',
117 'contrib_dynamic',
118 'free_search',
119 'groups_search',
120 'groups_search_log_op'
121 );
122
123 protected $virtuals_advancedmemberslist_fields = array(
124 'rcreation_date_begin',
125 'rcreation_date_end',
126 'rmodif_date_begin',
127 'rmodif_date_end',
128 'rdue_date_begin',
129 'rdue_date_end',
130 'rbirth_date_begin',
131 'rbirth_date_end',
132 'rcontrib_creation_date_begin',
133 'rcontrib_creation_date_end',
134 'rcontrib_begin_date_begin',
135 'rcontrib_begin_date_end',
136 'rcontrib_end_date_begin',
137 'rcontrib_end_date_end',
138 'search_fields'
139 );
140
141 //an empty free search criteria to begin
142 private $_free_search = array(
143 'empty' => array(
144 'field' => '',
145 'search' => '',
146 'log_op' => self::OP_AND,
147 'qry_op' => self::OP_EQUALS
148 )
149 );
150
151 //an empty group search criteria to begin
152 private $_groups_search = array(
153 'empty' => array(
154 'group' => '',
155 )
156 );
157
158 //defaults to 'OR' for group search
159 private $_groups_search_log_op = self::OP_OR;
160
161
162 //an empty contributions dynamic field criteria to begin
163 private $_contrib_dynamic = array();
164
165 /**
166 * Default constructor
167 *
168 * @param MembersList $simple A simple filter search to keep
169 */
170 public function __construct($simple = null)
171 {
172 parent::__construct();
173 if ($simple instanceof MembersList) {
174 foreach ($this->pagination_fields as $pf) {
175 $this->$pf = $simple->$pf;
176 }
177 foreach ($this->memberslist_fields as $mlf) {
178 $this->$mlf = $simple->$mlf;
179 }
180 }
181 }
182
183 /**
184 * Do we want to filter within contributions?
185 *
186 * @return boolean
187 */
188 public function withinContributions()
189 {
190 if (
191 $this->_contrib_creation_date_begin != null
192 || $this->_contrib_creation_date_end != null
193 || $this->_contrib_begin_date_begin != null
194 || $this->_contrib_begin_date_end != null
195 || $this->_contrib_end_date_begin != null
196 || $this->_contrib_begin_date_end != null
197 || $this->_contrib_min_amount != null
198 || $this->_contrib_max_amount != null
199 || count($this->_contrib_dynamic) > 0
200 || count($this->_contributions_types) > 0
201 || count($this->_payments_types) > 0
202 ) {
203 return true;
204 } else {
205 return false;
206 }
207 }
208
209 /**
210 * Reinit default parameters
211 *
212 * @return void
213 */
214 public function reinit()
215 {
216 parent::reinit();
217
218 $this->_creation_date_begin = null;
219 $this->_creation_date_end = null;
220 $this->_modif_date_begin = null;
221 $this->_modif_date_end = null;
222 $this->_due_date_begin = null;
223 $this->_due_date_end = null;
224 $this->_birth_date_begin = null;
225 $this->_birth_date_end = null;
226 $this->_show_public_infos = Members::FILTER_DC_PUBINFOS;
227 $this->_status = array();
228
229 $this->_contrib_creation_date_begin = null;
230 $this->_contrib_creation_date_end = null;
231 $this->_contrib_begin_date_begin = null;
232 $this->_contrib_begin_date_end = null;
233 $this->_contrib_end_date_begin = null;
234 $this->_contrib_begin_date_end = null;
235 $this->_contributions_types = array();
236 $this->_payments_types = array();
237
238 $this->_free_search = array(
239 'empty' => array(
240 'field' => '',
241 'search' => '',
242 'log_op' => self::OP_AND,
243 'qry_op' => self::OP_EQUALS
244 )
245 );
246
247 $this->_contrib_dynamic = array();
248
249 $this->_groups_search = array(
250 'empty' => array(
251 'group' => '',
252 )
253 );
254
255 $this->_groups_search_log_op = self::OP_OR;
256 }
257
258 /**
259 * Global getter method
260 *
261 * @param string $name name of the property we want to retrive
262 *
263 * @return object the called property
264 */
265 public function __get($name)
266 {
267
268 Analog::log(
269 '[AdvancedMembersList] Getting property `' . $name . '`',
270 Analog::DEBUG
271 );
272
273 if (
274 in_array($name, $this->pagination_fields)
275 || in_array($name, $this->memberslist_fields)
276 ) {
277 return parent::__get($name);
278 } else {
279 if (
280 in_array($name, $this->advancedmemberslist_fields)
281 || in_array($name, $this->virtuals_advancedmemberslist_fields)
282 ) {
283 $rname = '_' . $name;
284 switch ($name) {
285 case 'creation_date_begin':
286 case 'creation_date_end':
287 case 'modif_date_begin':
288 case 'modif_date_end':
289 case 'due_date_begin':
290 case 'due_date_end':
291 case 'birth_date_begin':
292 case 'birth_date_end':
293 case 'contrib_creation_date_begin':
294 case 'contrib_creation_date_end':
295 case 'contrib_begin_date_begin':
296 case 'contrib_begin_date_end':
297 case 'contrib_end_date_begin':
298 case 'contrib_end_date_end':
299 try {
300 if ($this->$rname !== null) {
301 $d = new \DateTime($this->$rname);
302 return $d->format(__("Y-m-d"));
303 }
304 } catch (\Exception $e) {
305 //oops, we've got a bad date :/
306 Analog::log(
307 'Bad date (' . $this->$rname . ') | ' .
308 $e->getMessage(),
309 Analog::INFO
310 );
311 return $this->$rname;
312 }
313 break;
314 case 'rcreation_date_begin':
315 case 'rcreation_date_end':
316 case 'rmodif_date_begin':
317 case 'rmodif_date_end':
318 case 'rdue_date_begin':
319 case 'rdue_date_end':
320 case 'rbirth_date_begin':
321 case 'rbirth_date_end':
322 case 'rcontrib_creation_date_begin':
323 case 'rcontrib_creation_date_end':
324 case 'rcontrib_begin_date_begin':
325 case 'rcontrib_begin_date_end':
326 case 'rcontrib_end_date_begin':
327 case 'rcontrib_end_date_end':
328 //same as above, but raw format
329 $rname = '_' . substr($name, 1);
330 return $this->$rname;
331 case 'search_fields':
332 $search_fields = array_merge($this->memberslist_fields, $this->advancedmemberslist_fields);
333 $key = array_search('selected', $search_fields);
334 unset($search_fields[$key]);
335 $key = array_search('unreachable', $search_fields);
336 unset($search_fields[$key]);
337 $key = array_search('query', $search_fields);
338 unset($search_fields[$key]);
339 return $search_fields;
340 }
341 return $this->$rname;
342 } else {
343 Analog::log(
344 '[AdvancedMembersList] Unable to get proprety `' . $name . '`',
345 Analog::WARNING
346 );
347 }
348 }
349 }
350
351 /**
352 * Global setter method
353 *
354 * @param string $name name of the property we want to assign a value to
355 * @param object $value a relevant value for the property
356 *
357 * @return void
358 */
359 public function __set($name, $value)
360 {
361 global $zdb, $preferences, $login;
362
363 if (
364 in_array($name, $this->pagination_fields)
365 || in_array($name, $this->memberslist_fields)
366 ) {
367 parent::__set($name, $value);
368 } else {
369 Analog::log(
370 '[AdvancedMembersList] Setting property `' . $name . '`',
371 Analog::DEBUG
372 );
373
374 $prop = '_' . $name;
375
376 switch ($name) {
377 case 'creation_date_begin':
378 case 'creation_date_end':
379 case 'modif_date_begin':
380 case 'modif_date_end':
381 case 'due_date_begin':
382 case 'due_date_end':
383 case 'birth_date_begin':
384 case 'birth_date_end':
385 case 'contrib_creation_date_begin':
386 case 'contrib_creation_date_end':
387 case 'contrib_begin_date_begin':
388 case 'contrib_begin_date_end':
389 case 'contrib_end_date_begin':
390 case 'contrib_end_date_end':
391 if ($value !== null && trim($value) !== '') {
392 try {
393 $d = \DateTime::createFromFormat(__("Y-m-d"), $value);
394 if ($d === false) {
395 throw new \Exception('Incorrect format');
396 }
397 $this->$prop = $d->format('Y-m-d');
398 } catch (\Exception $e) {
399 Analog::log(
400 'Incorrect date format for ' . $name .
401 '! was: ' . $value,
402 Analog::WARNING
403 );
404 }
405 }
406 break;
407 case 'contrib_min_amount':
408 case 'contrib_max_amount':
409 if (is_float($value)) {
410 $this->$prop = $value;
411 } else {
412 if ($value !== null) {
413 Analog::log(
414 'Incorrect amount for ' . $name . '! ' .
415 'Should be a float (' . gettype($value) . ' given)',
416 Analog::WARNING
417 );
418 }
419 }
420 break;
421 case 'show_public_infos':
422 if (is_numeric($value)) {
423 $this->$prop = $value;
424 } else {
425 Analog::log(
426 '[AdvancedMembersList] Value for property `' . $name .
427 '` should be an integer (' . gettype($value) . ' given)',
428 Analog::WARNING
429 );
430 }
431 break;
432 case 'status':
433 if (!is_array($value)) {
434 $value = array($value);
435 }
436 $this->_status = array();
437 foreach ($value as $v) {
438 if (is_numeric($v)) {
439 //check status existence
440 $s = new Status($zdb);
441 $res = $s->get($v);
442 if ($res !== false) {
443 $this->_status[] = $v;
444 } else {
445 Analog::log(
446 'Status #' . $v . ' does not exists!',
447 Analog::WARNING
448 );
449 }
450 } else {
451 Analog::log(
452 '[AdvancedMembersList] Value for status filter should be an '
453 . 'integer (' . gettype($v) . ' given',
454 Analog::WARNING
455 );
456 }
457 }
458 break;
459 case 'contributions_types':
460 if (!is_array($value)) {
461 $value = array($value);
462 }
463 $this->_contributions_types = array();
464 foreach ($value as $v) {
465 if (is_numeric($v)) {
466 //check type existence
467 $s = new ContributionsTypes($zdb);
468 $res = $s->get($v);
469 if ($res !== false) {
470 $this->_contributions_types[] = $v;
471 } else {
472 Analog::log(
473 'Contribution type #' . $v . ' does not exists!',
474 Analog::WARNING
475 );
476 }
477 } else {
478 Analog::log(
479 '[AdvancedMembersList] Value for contribution type '
480 . 'filter should be an integer (' . gettype($v) .
481 ' given',
482 Analog::WARNING
483 );
484 }
485 }
486 break;
487 case 'payments_types':
488 if (!is_array($value)) {
489 $value = array($value);
490 }
491 $this->_payments_types = array();
492 $ptypes = new PaymentTypes(
493 $zdb,
494 $preferences,
495 $login
496 );
497 $ptlist = $ptypes->getList();
498
499 foreach ($value as $v) {
500 if (is_numeric($v)) {
501 if (isset($ptlist[$v])) {
502 $this->_payments_types[] = $v;
503 } else {
504 Analog::log(
505 'Payment type #' . $v . ' does not exists!',
506 Analog::WARNING
507 );
508 }
509 } else {
510 Analog::log(
511 '[AdvancedMembersList] Value for payment type filter should be an '
512 . 'integer (' . gettype($v) . ' given',
513 Analog::WARNING
514 );
515 }
516 }
517 break;
518 case 'free_search':
519 if (isset($this->_free_search['empty'])) {
520 unset($this->_free_search['empty']);
521 }
522
523 if ($this->isValidFreeSearch($value)) {
524 //should this happen?
525 $values = [$value];
526 } else {
527 $values = $value;
528 }
529
530 foreach ($values as $value) {
531 if ($this->isValidFreeSearch($value)) {
532 $id = $value['idx'];
533
534 //handle value according to type
535 switch ($value['type']) {
536 case DynamicField::DATE:
537 if ($value['search'] !== null && trim($value['search']) !== '') {
538 try {
539 $d = \DateTime::createFromFormat(__("Y-m-d"), $value['search']);
540 if ($d === false) {
541 throw new \Exception('Incorrect format');
542 }
543 $value['search'] = $d->format('Y-m-d');
544 } catch (\Exception $e) {
545 Analog::log(
546 'Incorrect date format for ' . $value['field'] .
547 '! was: ' . $value['search'],
548 Analog::WARNING
549 );
550 }
551 }
552 break;
553 }
554
555 $this->_free_search[$id] = $value;
556 } else {
557 Analog::log(
558 '[AdvancedMembersList] bad construct for free filter',
559 Analog::WARNING
560 );
561 }
562 }
563 break;
564 case 'contrib_dynamic':
565 if (is_array($value)) {
566 $this->_contrib_dynamic = $value;
567 } else {
568 Analog::log(
569 '[AdvancedMembersList] Value for dynamic contribution fields filter should be an '
570 . 'array (' . gettype($value) . ' given',
571 Analog::WARNING
572 );
573 }
574 break;
575 case 'groups_search':
576 if (isset($this->_groups_search['empty'])) {
577 unset($this->_groups_search['empty']);
578 }
579 if (is_array($value)) {
580 if (
581 isset($value['group'])
582 && isset($value['idx'])
583 ) {
584 $id = $value['idx'];
585 unset($value['idx']);
586 $this->_groups_search[$id] = $value;
587 } else {
588 Analog::log(
589 '[AdvancedMembersList] bad construct for group filter',
590 Analog::WARNING
591 );
592 }
593 } else {
594 Analog::log(
595 '[AdvancedMembersList] Value for group filter should be an '
596 . 'array (' . gettype($value) . ' given',
597 Analog::WARNING
598 );
599 }
600 break;
601 case 'groups_search_log_op':
602 if ($value == self::OP_AND || $value == self::OP_OR) {
603 $this->_groups_search_log_op = $value;
604 } else {
605 Analog::log(
606 '[AdvancedMembersList] Value for group filter logical operator should be '
607 . ' in [0,1] (' . gettype($value) . '-> ' . $value . ' given )',
608 Analog::WARNING
609 );
610 }
611 break;
612 default:
613 if (
614 substr($name, 0, 4) === 'cds_'
615 || substr($name, 0, 5) === 'cdsc_'
616 ) {
617 if (is_array($value) || trim($value) !== '') {
618 $id = null;
619 if (substr($name, 0, 5) === 'cdsc_') {
620 $id = substr($name, 5, strlen($name));
621 } else {
622 $id = substr($name, 4, strlen($name));
623 }
624 $this->_contrib_dynamic[$id] = $value;
625 }
626 } else {
627 Analog::log(
628 '[AdvancedMembersList] Unable to set proprety `' .
629 $name . '`',
630 Analog::WARNING
631 );
632 }
633 break;
634 }
635 }
636 }
637
638 /**
639 * Validate free search internal array
640 *
641 * @param array $data Array to validate
642 *
643 * @return boolean
644 */
645 public static function isValidFreeSearch($data)
646 {
647 if (!is_array($data)) {
648 Analog::log(
649 '[AdvancedMembersList] Value for free filter should be an '
650 . 'array (' . gettype($data) . ' given',
651 Analog::WARNING
652 );
653 return false;
654 }
655 return isset($data['field'])
656 && isset($data['search'])
657 && isset($data['log_op'])
658 && isset($data['qry_op'])
659 && isset($data['idx'])
660 && isset($data['type']);
661 }
662 }