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