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