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