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