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