]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Features/Replacements.php
Modify tests: contributions, reminders, membership
[galette.git] / galette / lib / Galette / Features / Replacements.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Replacements feature
7 *
8 * PHP version 5
9 *
10 * Copyright © 2020-2021 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 Features
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2020-2021 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.eu
34 * @since 2020-12-20
35 */
36
37 namespace Galette\Features;
38
39 use Galette\Core\Db;
40 use Galette\Core\Login;
41 use Galette\Core\Logo;
42 use Galette\Core\Preferences;
43 use Galette\DynamicFields\Choice;
44 use Galette\DynamicFields\Separator;
45 use Galette\Entity\Adherent;
46 use Galette\Entity\Contribution;
47 use Galette\Entity\PdfModel;
48 use Galette\Entity\Texts;
49 use Galette\Repository\DynamicFieldsSet;
50 use Galette\DynamicFields\DynamicField;
51 use Analog\Analog;
52 use NumberFormatter;
53 use Slim\Router;
54
55 /**
56 * Replacements feature
57 *
58 * @category Features
59 * @name Replacements
60 * @package Galette
61 * @author Johan Cwiklinski <johan@x-tnd.be>
62 * @copyright 2020-2021 The Galette Team
63 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
64 * @link http://galette.eu
65 * @since 2020-12-20
66 */
67
68 trait Replacements
69 {
70 private $patterns = [];
71 private $replaces = [];
72 private $dynamic_patterns = [];
73
74 /**
75 * @Inject("zdb")
76 * @var Db
77 */
78 protected $zdb;
79
80 /**
81 * @Inject("login")
82 * @var Login
83 */
84 protected $login;
85
86 /**
87 * @Inject("preferences")
88 * @var Preferences
89 */
90 protected $preferences;
91
92 /**
93 * @var Router
94 */
95 protected $router;
96
97 /**
98 * Get dynamic patterns
99 *
100 * @param string $form_name Dynamic form name
101 * @param boolean $legacy Whether to load legacy patterns
102 *
103 * @return array
104 */
105 public function getDynamicPatterns(string $form_name, bool $legacy = true): array
106 {
107 $fields = new DynamicFieldsSet($this->zdb, $this->login);
108 $dynamic_fields = $fields->getList($form_name);
109
110 $dynamic_patterns = [];
111 foreach ($dynamic_fields as $dynamic_field) {
112 //no pattern for separators
113 if ($dynamic_field instanceof Separator) {
114 continue;
115 }
116 $key = strtoupper('DYNFIELD_' . $dynamic_field->getId() . '_' . $form_name);
117 $capabilities = [
118 'LABEL',
119 ''
120 ];
121 if (!($this instanceof Texts) && ($legacy === true || $dynamic_field instanceof Choice)) {
122 $capabilities[] = 'INPUT';
123 }
124 foreach ($capabilities as $capability) {
125 $skey = sprintf('%s_%s', $capability, $key);
126 switch ($capability) {
127 case 'LABEL':
128 $title = _T('Label for dynamic field "%s"');
129 break;
130 case 'INPUT':
131 $title = _T('Form entry for dynamic field "%s"');
132 break;
133 case '':
134 case 'VALUE':
135 $skey = $key;
136 $title = _T('Value for dynamic field "%s"');
137 break;
138 }
139 $dynamic_patterns[strtolower($skey)] = [
140 'title' => sprintf(
141 $title,
142 $dynamic_field->getName()
143 ),
144 'pattern' => sprintf('/{%s}/', $skey)
145 ];
146 }
147 }
148
149 $this->dynamic_patterns[$form_name] = $dynamic_patterns;
150 return $this->dynamic_patterns[$form_name];
151 }
152
153 /**
154 * Set patterns
155 *
156 * @param array $patterns Patterns to add
157 *
158 * @return $this
159 */
160 protected function setPatterns(array $patterns): self
161 {
162 $toset = [];
163 foreach ($patterns as $key => $info) {
164 if (is_array($info)) {
165 $toset[$key] = $info['pattern'];
166 } else {
167 $toset[$key] = $info;
168 }
169 }
170
171 $this->patterns = array_merge(
172 $this->patterns,
173 $toset
174 );
175
176 return $this;
177 }
178
179 /**
180 * Set replacements
181 *
182 * @param array $replaces Replacements to add
183 *
184 * @return void
185 */
186 public function setReplacements(array $replaces): void
187 {
188 $this->replaces = array_merge(
189 $this->replaces,
190 $replaces
191 );
192 }
193
194 /**
195 * Get main patterns
196 *
197 * @return array
198 */
199 protected function getMainPatterns(): array
200 {
201 return [
202 'asso_name' => [
203 'title' => _T('Your organisation name'),
204 'pattern' => '/{ASSO_NAME}/'
205 ],
206 'asso_slogan' => [
207 'title' => _T('Your organisation slogan'),
208 'pattern' => '/{ASSO_SLOGAN}/'
209 ],
210 'asso_address' => [
211 'title' => _T('Your organisation address'),
212 'pattern' => '/{ASSO_ADDRESS}/',
213 ],
214 'asso_address_multi' => [
215 'title' => sprintf('%s (%s)', _T('Your organisation address'), _T('with break lines')),
216 'pattern' => '/{ASSO_ADDRESS_MULTI}/',
217 ],
218 'asso_website' => [
219 'title' => _T('Your organisation website'),
220 'pattern' => '/{ASSO_WEBSITE}/',
221 ],
222 'asso_logo' => [
223 'title' => _T('Your organisation logo'),
224 'pattern' => '/{ASSO_LOGO}/',
225 ],
226 'date_now' => [
227 'title' => _T('Current date (Y-m-d)'),
228 'pattern' => '/{DATE_NOW}/'
229 ],
230 'login_uri' => [
231 'title' => _T("Galette's login URI"),
232 'pattern' => '/{LOGIN_URI}/'
233 ]
234 ];
235 }
236
237 /**
238 * Get patterns for a member
239 *
240 * @param boolean $legacy Whether to load legacy patterns
241 *
242 * @return array
243 */
244 protected function getMemberPatterns(bool $legacy = true): array
245 {
246 $dynamic_patterns = $this->getDynamicPatterns('adh', $legacy);
247 $m_patterns = [
248 'adh_title' => [
249 'title' => _('Title'),
250 'pattern' => '/{TITLE_ADH}/',
251 ],
252 'adh_id' => [
253 'title' => _T("Member's ID"),
254 'pattern' => '/{ID_ADH}/',
255 ],
256 'adh_num' => [
257 'title' => _T("Member number"),
258 'pattern' => '/{NUM_ADH}/',
259 ],
260 'adh_name' => [
261 'title' => _T("Name"),
262 'pattern' => '/{NAME_ADH}/',
263 ],
264 'adh_last_name' => [
265 'title' => _T('Last name'),
266 'pattern' => '/{LAST_NAME_ADH}/',
267 ],
268 'adh_first_name' => [
269 'title' => _T('First name'),
270 'pattern' => '/{FIRST_NAME_ADH}/',
271 ],
272 'adh_nickname' => [
273 'title' => _T('Nickname'),
274 'pattern' => '/{NICKNAME_ADH}/',
275 ],
276 'adh_gender' => [
277 'title' => _T('Gender'),
278 'pattern' => '/{GENDER_ADH}/',
279 ],
280 'adh_birth_date' => [
281 'title' => _T('Birth date'),
282 'pattern' => '/{ADH_BIRTH_DATE}/',
283 ],
284 'adh_birth_place' => [
285 'title' => _T('Birth place'),
286 'pattern' => '/{ADH_BIRTH_PLACE}/',
287 ],
288 'adh_profession' => [
289 'title' => _T('Profession'),
290 'pattern' => '/{PROFESSION_ADH}/',
291 ],
292 'adh_company' => [
293 'title' => _T("Company name"),
294 'pattern' => '/{COMPANY_ADH}/',
295 ],
296 'adh_address' => [
297 'title' => _T("Address"),
298 'pattern' => '/{ADDRESS_ADH}/',
299 ],
300 'adh_address_multi' => [
301 'title' => sprintf('%s (%s)', _T('Address'), _T('with break lines')),
302 'pattern' => '/{ADDRESS_ADH_MULTI}/',
303 ],
304 'adh_zip' => [
305 'title' => _T("Zipcode"),
306 'pattern' => '/{ZIP_ADH}/',
307 ],
308 'adh_town' => [
309 'title' => _T("Town"),
310 'pattern' => '/{TOWN_ADH}/',
311 ],
312 'adh_country' => [
313 'title' => _T('Country'),
314 'pattern' => '/{COUNTRY_ADH}/',
315 ],
316 'adh_phone' => [
317 'title' => _T('Phone'),
318 'pattern' => '/{PHONE_ADH}/',
319 ],
320 'adh_mobile' => [
321 'title' => _T('GSM'),
322 'pattern' => '/{MOBILE_ADH}/',
323 ],
324 'adh_email' => [
325 'title' => _T('Email'),
326 'pattern' => '/{EMAIL_ADH}/',
327 ],
328 'adh_login' => [
329 'title' => _T('Login'),
330 'pattern' => '/{LOGIN_ADH}/',
331 ],
332 'adh_main_group' => [
333 'title' => _T("Member's main group"),
334 'pattern' => '/{GROUP_ADH}/',
335 ],
336 'adh_groups' => [
337 'title' => _T("Member's groups (as list)"),
338 'pattern' => '/{GROUPS_ADH}/'
339 ],
340 'adh_dues' => [
341 'title' => _T('Member state of dues'),
342 'pattern' => '/{ADH_DUES}/'
343 ],
344 'days_remaining' => [
345 'title' => _T('Membership remaining days'),
346 'pattern' => '/{DAYS_REMAINING}/',
347 ],
348 'days_expired' => [
349 'title' => _T('Membership expired since'),
350 'pattern' => '/{DAYS_EXPIRED}/',
351 ]
352 ];
353
354 if ($legacy === true) {
355 $m_patterns += [
356 '_adh_company' => [
357 'title' => _T("Company name"),
358 'pattern' => '/{COMPANY_NAME_ADH}/',
359 ],
360 '_adh_last_name' => [
361 'title' => _T('Last name'),
362 'pattern' => '/{LASTNAME_ADH}/',
363 ],
364 '_adh_first_name' => [
365 'title' => _T('First name'),
366 'pattern' => '/{FIRSTNAME_ADH}/',
367 ],
368 '_adh_login' => [
369 'title' => _T('Login'),
370 'pattern' => '/{LOGIN}/',
371 ],
372 '_adh_email' => [
373 'title' => _T('Email'),
374 'pattern' => '/{MAIL_ADH}/',
375 ],
376 ];
377 }
378
379 return $m_patterns + $dynamic_patterns;
380 }
381
382 /**
383 * Get patterns for a contribution
384 *
385 * @param boolean $legacy Whether to load legacy patterns
386 *
387 * @return array
388 */
389 protected function getContributionPatterns($legacy = true): array
390 {
391 $dynamic_patterns = $this->getDynamicPatterns('contrib', $legacy);
392
393 $c_patterns = [
394 'contrib_label' => [
395 'title' => _T('Contribution label'),
396 'pattern' => '/{CONTRIB_LABEL}/',
397 ],
398 'contrib_amount' => [
399 'title' => _T('Amount'),
400 'pattern' => '/{CONTRIB_AMOUNT}/',
401 ],
402 'contrib_amount_letters' => [
403 'title' => _T('Amount (in letters)'),
404 'pattern' => '/{CONTRIB_AMOUNT_LETTERS}/',
405 ],
406 'contrib_date' => [
407 'title' => _T('Full date'),
408 'pattern' => '/{CONTRIB_DATE}/',
409 ],
410 'contrib_year' => [
411 'title' => _T('Contribution year'),
412 'pattern' => '/{CONTRIB_YEAR}/',
413 ],
414 'contrib_comment' => [
415 'title' => _T('Comment'),
416 'pattern' => '/{CONTRIB_COMMENT}/',
417 ],
418 'contrib_bdate' => [
419 'title' => _T('Begin date'),
420 'pattern' => '/{CONTRIB_BEGIN_DATE}/',
421 ],
422 'contrib_edate' => [
423 'title' => _T('End date'),
424 'pattern' => '/{CONTRIB_END_DATE}/',
425 ],
426 'contrib_id' => [
427 'title' => _T('Contribution id'),
428 'pattern' => '/{CONTRIB_ID}/',
429 ],
430 'contrib_payment' => [
431 'title' => _T('Payment type'),
432 'pattern' => '/{CONTRIB_PAYMENT_TYPE}/'
433 ],
434 'contrib_info' => [
435 'title' => _T('Contribution information'),
436 'pattern' => '/{CONTRIB_INFO}/'
437 ]
438 ];
439
440 if ($legacy === true) {
441 foreach ($c_patterns as $key => $pattern) {
442 $nkey = '_' . $key;
443 $pattern['pattern'] = str_replace(
444 'CONTRIB_',
445 'CONTRIBUTION_',
446 $pattern['pattern']
447 );
448 $c_patterns[$nkey] = $pattern;
449 }
450
451 $c_patterns['__contrib_label'] = [
452 'title' => $c_patterns['contrib_label']['title'],
453 'pattern' => '/{CONTRIB_TYPE}/'
454 ];
455 }
456
457 //handle DEADLINE alias
458 $c_patterns['deadline'] = [
459 'title' => $c_patterns['contrib_edate']['title'],
460 'pattern' => '/{DEADLINE}/'
461 ];
462
463 return $c_patterns + $dynamic_patterns;
464 }
465
466 /**
467 * Set main replacements
468 *
469 * @return $this
470 */
471 public function setMain(): self
472 {
473 $address = $this->preferences->getPostalAddress();
474 $address_multi = preg_replace("/\n/", "<br>", $address);
475
476 $website = '';
477 if ($this->preferences->pref_website !== '') {
478 $website = '<a href="' . $this->preferences->pref_website . '">' .
479 $this->preferences->pref_website . '</a>';
480 }
481
482 $logo = new Logo();
483 $logo_elt = '<img' .
484 ' src="' . $this->preferences->getURL() . $this->router->pathFor('logo') . '"' .
485 ' width="' . $logo->getOptimalWidth() . '"' .
486 ' height="' . $logo->getOptimalHeight() . '"' .
487 '/>';
488
489 $this->setReplacements(
490 array(
491 'asso_name' => $this->preferences->pref_nom,
492 'asso_slogan' => $this->preferences->pref_slogan,
493 'asso_address' => $address,
494 'asso_address_multi' => $address_multi,
495 'asso_website' => $website,
496 'asso_logo' => $logo_elt,
497 'date_now' => date(_T('Y-m-d')),
498 'login_uri' => $this->preferences->getURL() . $this->router->pathFor('login'),
499 )
500 );
501
502 return $this;
503 }
504
505 /**
506 * Set contribution and proceed related replacements
507 *
508 * @return $this
509 */
510 public function setNoContribution(): self
511 {
512 global $login;
513
514 $c_replacements = [
515 'contrib_label' => null,
516 'contrib_amount' => null,
517 'contrib_amount_letters' => null,
518 'contrib_date' => null,
519 'contrib_year' => null,
520 'contrib_comment' => null,
521 'contrib_bdate' => null,
522 'contrib_edate' => null,
523 'contrib_id' => null,
524 'contrib_payment' => null,
525 'contrib_info' => null
526 ];
527
528 foreach ($c_replacements as $key => $replacement) {
529 $nkey = '_' . $key;
530 $c_replacements[$nkey] = $replacement;
531 }
532 $c_replacements['__contrib_label'] = $c_replacements['contrib_label'];
533
534 //handle DEADLINE alias
535 $c_replacements['deadline'] = null;
536
537 $this->setReplacements($c_replacements);
538
539 /** the list of all dynamic fields */
540 $fields = new DynamicFieldsSet($this->zdb, $login);
541 $dynamic_fields = $fields->getList('contrib');
542 $this->setDynamicFields('contrib', $dynamic_fields, null);
543
544 return $this;
545 }
546
547 /**
548 * Set contribution and proceed related replacements
549 *
550 * @param Contribution $contrib Contribution
551 *
552 * @return PdfModel
553 */
554 public function setContribution(Contribution $contrib): self
555 {
556 global $login, $i18n;
557
558 $formatter = new NumberFormatter($i18n->getID(), NumberFormatter::SPELLOUT);
559
560 $c_replacements = [
561 'contrib_label' => $contrib->type->libelle,
562 'contrib_amount' => $contrib->amount,
563 'contrib_amount_letters' => $formatter->format($contrib->amount),
564 'contrib_date' => $contrib->date,
565 'contrib_year' => $contrib->raw_date->format('Y'),
566 'contrib_comment' => $contrib->info,
567 'contrib_bdate' => $contrib->begin_date,
568 'contrib_edate' => $contrib->end_date,
569 'contrib_id' => $contrib->id,
570 'contrib_payment' => $contrib->spayment_type,
571 'contrib_info' => $contrib->info
572 ];
573
574 foreach ($c_replacements as $key => $replacement) {
575 $nkey = '_' . $key;
576 $c_replacements[$nkey] = $replacement;
577 }
578 $c_replacements['__contrib_label'] = $c_replacements['contrib_label'];
579
580 //handle DEADLINE alias
581 $c_replacements['deadline'] = $c_replacements['contrib_edate'];
582
583 $this->setReplacements($c_replacements);
584
585 /** the list of all dynamic fields */
586 $fields = new DynamicFieldsSet($this->zdb, $login);
587 $dynamic_fields = $fields->getList('contrib');
588 $this->setDynamicFields('contrib', $dynamic_fields, $contrib);
589
590 return $this;
591 }
592
593 /**
594 * Set member and proceed related replacements
595 *
596 * @param Adherent $member Member
597 *
598 * @return PdfModel
599 */
600 public function setMember(Adherent $member): self
601 {
602 global $login;
603
604 $address = $member->getAddress();
605 $address_multi = preg_replace("/\n/", "<br>", $address);
606
607 if ($member->isMan()) {
608 $gender = _T("Man");
609 } elseif ($member->isWoman()) {
610 $gender = _T("Woman");
611 } else {
612 $gender = _T("Unspecified");
613 }
614
615 $member_groups = $member->groups;
616 $main_group = _T("None");
617 $group_list = _T("None");
618 if (is_array($member_groups) && count($member_groups) > 0) {
619 $main_group = $member_groups[0]->getName();
620 $group_list = '<ul>';
621 foreach ($member_groups as $group) {
622 $group_list .= '<li>' . $group->getName() . '</li>';
623 }
624 $group_list .= '</ul>';
625 }
626
627 $this->setReplacements(
628 array(
629 'adh_title' => $member->stitle,
630 'adh_id' => $member->id,
631 'adh_num' => $member->number,
632 'adh_name' => $member->sfullname,
633 'adh_last_name' => $member->name,
634 'adh_first_name' => $member->surname,
635 'adh_nickname' => $member->nickname,
636 'adh_gender' => $gender,
637 'adh_birth_date' => $member->birthdate,
638 'adh_birth_place' => $member->birth_place,
639 'adh_profession' => $member->job,
640 'adh_company' => $member->company_name,
641 'adh_address' => $address,
642 'adh_address_multi' => $address_multi,
643 'adh_zip' => $member->getZipcode(),
644 'adh_town' => $member->getTown(),
645 'adh_country' => $member->getCountry(),
646 'adh_phone' => $member->phone,
647 'adh_mobile' => $member->gsm,
648 //always take current member email, to be sure.
649 'adh_email' => $member->email,
650 'adh_login' => $member->login,
651 'adh_main_group' => $main_group,
652 'adh_groups' => $group_list,
653 'adh_dues' => $member->getDues(),
654 'days_remaining' => $member->days_remaining,
655 'days_expired' => $member->days_remaining + 1,
656 //Handle COMPANY_NAME_ADH... https://bugs.galette.eu/issues/1530
657 '_adh_company' => $member->company_name,
658 //Handle old names for variables ... https://bugs.galette.eu/issues/1393
659 '_adh_last_name' => $member->name,
660 '_adh_first_name' => $member->surname,
661 '_adh_login' => $member->login,
662 '_adh_email' => $member->email
663 )
664 );
665
666 /** the list of all dynamic fields */
667 $fields = new DynamicFieldsSet($this->zdb, $login);
668 $dynamic_fields = $fields->getList('adh');
669 $this->setDynamicFields('adh', $dynamic_fields, $member);
670
671 return $this;
672 }
673
674 /**
675 * Set dynamic fields and proceed related replacements
676 *
677 * @param string $form_name Form name
678 * @param array $dynamic_fields Dynamic fields
679 * @param mixed $object Related object (Adherent, Contribution, ...)
680 *
681 * @return PdfModel
682 */
683 public function setDynamicFields(string $form_name, array $dynamic_fields, $object): self
684 {
685 $uform_name = strtoupper($form_name);
686
687 $dynamic_patterns = $this->getDynamicPatterns($form_name);
688 foreach ($dynamic_patterns as $dynamic_pattern) {
689 $pattern = trim($dynamic_pattern['pattern'], '/');
690 $key = strtolower(rtrim(ltrim($pattern, '{'), '}'));
691 $value = '';
692
693 if (preg_match("/^{LABEL_DYNFIELD_([0-9]+)_$uform_name}$/", $pattern, $match)) {
694 /** dynamic field label */
695 $field_id = $match[1];
696 $value = $dynamic_fields[$field_id]->getName();
697 }
698 if (preg_match("/^{(INPUT_|VALUE_)?DYNFIELD_([0-9]+)_$uform_name}$/", $pattern, $match)) {
699 /** dynamic field value */
700 $capacity = trim($match[1], '_');
701 $field_id = $match[2];
702 $field_name = $dynamic_fields[$field_id]->getName();
703 $field_type = $dynamic_fields[$field_id]->getType();
704 $field_values = [];
705 if ($object !== null) {
706 $all_values = $object->getDynamicFields()->getValues($field_id);
707 foreach ($all_values as $field_value) {
708 $field_values[$field_value['field_val']] = $field_value['text_val'] ?? $field_value['field_val'];
709 }
710 } else {
711 $field_values = [];
712 }
713
714 switch ($field_type) {
715 case DynamicField::CHOICE:
716 $choice_values = $dynamic_fields[$field_id]->getValues();
717 if ($capacity == 'INPUT') {
718 foreach ($choice_values as $choice_idx => $choice_value) {
719 $value .= '<input type="radio" class="box" name="' . $field_name . '" value="' . $field_id . '"';
720 if (isset($field_values[$choice_idx])) {
721 $value .= ' checked="checked"';
722 }
723 $value .= ' disabled="disabled">' . $choice_value . '&nbsp;';
724 }
725 } else {
726 foreach ($field_values as $field_value) {
727 $value .= $field_value;
728 }
729 }
730 break;
731 case DynamicField::BOOLEAN:
732 foreach ($field_values as $field_value) {
733 $value .= ($field_value ? _T("Yes") : _T("No"));
734 }
735 break;
736 case DynamicField::FILE:
737 $pos = 0;
738 foreach ($field_values as $field_value) {
739 if (empty($field_value)) {
740 continue;
741 }
742 $spattern = (($this instanceof Texts) ?
743 '%3$s (%1$s%2$s)' :
744 '<a href="%1$s%2$s">%3$s</a>'
745 );
746 $value .= sprintf(
747 $spattern,
748 $this->preferences->getURL(),
749 $this->router->pathFor(
750 'getDynamicFile',
751 [
752 'id' => $object->id,
753 'fid' => $field_id,
754 'pos' => ++$pos,
755 'name' => $field_value
756 ]
757 ),
758 $field_value
759 );
760 }
761 break;
762 case DynamicField::TEXT:
763 case DynamicField::LINE:
764 case DynamicField::DATE:
765 $value .= implode('<br/>', $field_values);
766 break;
767 }
768 }
769
770 $this->setReplacements(array($key => $value));
771 Analog::log("adding dynamic replacement $key => $value", Analog::DEBUG);
772 }
773
774 return $this;
775 }
776
777 /**
778 * Build legend array
779 *
780 * @return array
781 */
782 public function getLegend(): array
783 {
784 $legend = [];
785
786 $legend['main'] = [
787 'title' => _T('Main information'),
788 'patterns' => $this->getMainPatterns()
789 ];
790
791 $legend['member'] = [
792 'title' => _T('Member information'),
793 'patterns' => $this->getMemberPatterns(false)
794 ];
795
796 return $legend;
797 }
798
799 /**
800 * Get configured replacements
801 *
802 * @return array
803 */
804 public function getReplacements(): array
805 {
806 return $this->replaces;
807 }
808
809 /**
810 * Set Db dependency
811 *
812 * @param Db $db Db instance
813 *
814 * @return $this
815 */
816 public function setDb(Db $db): self
817 {
818 $this->zdb = $db;
819 return $this;
820 }
821
822 /**
823 * Set Login dependency
824 *
825 * @param Login $login Login instance
826 *
827 * @return $this
828 */
829 public function setLogin(Login $login): self
830 {
831 $this->login = $login;
832 return $this;
833 }
834
835 /**
836 * Set Preferences dependency
837 *
838 * @param Preferences $preferences Preferences instance
839 *
840 * @return $this
841 */
842 public function setPreferences(Preferences $preferences): self
843 {
844 $this->preferences = $preferences;
845 return $this;
846 }
847
848 /**
849 * Set Router dependency
850 *
851 * @param Router $router Router instance
852 *
853 * @return $this
854 */
855 public function setRouter(Router $router): self
856 {
857 $this->router = $router;
858 return $this;
859 }
860
861 /**
862 * Proceed replacement on given entry
863 *
864 * @param string $source Source string
865 *
866 * @return string
867 */
868 protected function proceedReplacements(string $source): string
869 {
870 $replaced = $source;
871
872 //handle translations
873 $callback = static function ($matches) {
874 return _T($matches[1]);
875 };
876 $replaced = preg_replace_callback(
877 '/_T\("([^\"]+)"\)/',
878 $callback,
879 $source
880 );
881
882 //order matters
883 ksort($this->patterns, SORT_NATURAL);
884 ksort($this->replaces, SORT_NATURAL);
885
886 if (array_keys($this->patterns) !== array_keys($this->replaces)) {
887 throw new \RuntimeException('Patterns and replacements does not match!');
888 }
889
890 //handle replacements
891 $replaced = preg_replace(
892 $this->patterns,
893 $this->replaces,
894 $replaced
895 );
896
897 //handle translations with replacements
898 $repl_callback = static function ($matches) {
899 return str_replace(
900 $matches[1],
901 $matches[2],
902 $matches[3]
903 );
904 };
905 $replaced = preg_replace_callback(
906 '/str_replace\(\'([^,]+)\', ?\'([^,]+)\', ?\'(.*)\'\)/',
907 $repl_callback,
908 $replaced
909 );
910
911 return $replaced;
912 }
913
914 /**
915 * Get patterns
916 *
917 * @return array
918 */
919 public function getPatterns(): array
920 {
921 return $this->patterns;
922 }
923 }