Merge pull request #17736 from civicrm/5.27
[civicrm-core.git] / ext / flexmailer / src / Listener / RequiredTokens.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11 namespace Civi\FlexMailer\Listener;
12
13 use CRM_Flexmailer_ExtensionUtil as E;
14 use Civi\FlexMailer\Event\CheckSendableEvent;
15
16 /**
17 * Class RequiredTokens
18 * @package Civi\FlexMailer\Listener
19 *
20 * The RequiredTokens listener checks draft mailings for traditional
21 * CiviMail tokens like `{action.unsubscribeUrl}`, which are often required
22 * to comply with anti-spam regulations.
23 */
24 class RequiredTokens extends BaseListener {
25
26 /**
27 * @var array
28 * Ex: array('domain.address' => ts('The organizational postal address'))
29 */
30 private $requiredTokens;
31
32 /**
33 * @var array
34 *
35 * List of template-types for which we are capable of enforcing token
36 * requirements.
37 */
38 private $templateTypes;
39
40 /**
41 * RequiredTokens constructor.
42 *
43 * @param array $templateTypes
44 * Ex: array('traditional').
45 * @param array $requiredTokens
46 * Ex: array('domain.address' => ts('The organizational postal address'))
47 */
48 public function __construct($templateTypes, $requiredTokens) {
49 $this->templateTypes = $templateTypes;
50 $this->requiredTokens = $requiredTokens;
51 }
52
53 /**
54 * Check for required fields.
55 *
56 * @param \Civi\FlexMailer\Event\CheckSendableEvent $e
57 */
58 public function onCheckSendable(CheckSendableEvent $e) {
59 if (!$this->isActive()) {
60 return;
61 }
62 if (\Civi::settings()->get('disable_mandatory_tokens_check')) {
63 return;
64 }
65 if (!in_array($e->getMailing()->template_type, $this->getTemplateTypes())) {
66 return;
67 }
68
69 foreach (array('body_html', 'body_text') as $field) {
70 $str = $e->getFullBody($field);
71 if (empty($str)) {
72 continue;
73 }
74 foreach ($this->findMissingTokens($str) as $token => $desc) {
75 $e->setError("{$field}:{$token}", E::ts('This message is missing a required token - {%1}: %2',
76 array(1 => $token, 2 => $desc)
77 ));
78 }
79 }
80 }
81
82 public function findMissingTokens($str) {
83 $missing = array();
84 foreach ($this->getRequiredTokens() as $token => $value) {
85 if (!is_array($value)) {
86 if (!preg_match('/(^|[^\{])' . preg_quote('{' . $token . '}') . '/', $str)) {
87 $missing[$token] = $value;
88 }
89 }
90 else {
91 $present = FALSE;
92 $desc = NULL;
93 foreach ($value as $t => $d) {
94 $desc = $d;
95 if (preg_match('/(^|[^\{])' . preg_quote('{' . $t . '}') . '/', $str)) {
96 $present = TRUE;
97 }
98 }
99 if (!$present) {
100 $missing[$token] = $desc;
101 }
102 }
103 }
104 return $missing;
105 }
106
107 /**
108 * @return array
109 * Ex: array('domain.address' => ts('The organizational postal address'))
110 */
111 public function getRequiredTokens() {
112 return $this->requiredTokens;
113 }
114
115 /**
116 * @param array $requiredTokens
117 * Ex: array('domain.address' => ts('The organizational postal address'))
118 * @return RequiredTokens
119 */
120 public function setRequiredTokens($requiredTokens) {
121 $this->requiredTokens = $requiredTokens;
122 return $this;
123 }
124
125 /**
126 * @return array
127 * Ex: array('traditional').
128 */
129 public function getTemplateTypes() {
130 return $this->templateTypes;
131 }
132
133 /**
134 * Set the list of template-types for which we check tokens.
135 *
136 * @param array $templateTypes
137 * Ex: array('traditional').
138 * @return RequiredTokens
139 */
140 public function setTemplateTypes($templateTypes) {
141 $this->templateTypes = $templateTypes;
142 return $this;
143 }
144
145 /**
146 * Add to the list of template-types for which we check tokens.
147 *
148 * @param array $templateTypes
149 * Ex: array('traditional').
150 * @return RequiredTokens
151 */
152 public function addTemplateTypes($templateTypes) {
153 $this->templateTypes = array_unique(array_merge($this->templateTypes, $templateTypes));
154 return $this;
155 }
156
157 }