1 | <?php |
||||
2 | |||||
3 | namespace SilverStripe\Control\Email; |
||||
4 | |||||
5 | use SilverStripe\Control\Director; |
||||
6 | use SilverStripe\Control\HTTP; |
||||
7 | use SilverStripe\Core\Convert; |
||||
8 | use SilverStripe\Core\Environment; |
||||
9 | use SilverStripe\Core\Injector\Injector; |
||||
10 | use SilverStripe\ORM\FieldType\DBDatetime; |
||||
11 | use SilverStripe\ORM\FieldType\DBField; |
||||
12 | use SilverStripe\ORM\FieldType\DBHTMLText; |
||||
13 | use SilverStripe\View\Requirements; |
||||
14 | use SilverStripe\View\SSViewer; |
||||
15 | use SilverStripe\View\ThemeResourceLoader; |
||||
16 | use SilverStripe\View\ViewableData; |
||||
17 | use Swift_Message; |
||||
18 | use Swift_MimePart; |
||||
19 | |||||
20 | /** |
||||
21 | * Class to support sending emails. |
||||
22 | */ |
||||
23 | class Email extends ViewableData |
||||
24 | { |
||||
25 | |||||
26 | /** |
||||
27 | * @var array |
||||
28 | * @config |
||||
29 | */ |
||||
30 | private static $send_all_emails_to = array(); |
||||
31 | |||||
32 | /** |
||||
33 | * @var array |
||||
34 | * @config |
||||
35 | */ |
||||
36 | private static $cc_all_emails_to = array(); |
||||
37 | |||||
38 | /** |
||||
39 | * @var array |
||||
40 | * @config |
||||
41 | */ |
||||
42 | private static $bcc_all_emails_to = array(); |
||||
43 | |||||
44 | /** |
||||
45 | * @var array |
||||
46 | * @config |
||||
47 | */ |
||||
48 | private static $send_all_emails_from = array(); |
||||
49 | |||||
50 | /** |
||||
51 | * This will be set in the config on a site-by-site basis |
||||
52 | * |
||||
53 | * @config |
||||
54 | * @var string The default administrator email address. |
||||
55 | */ |
||||
56 | private static $admin_email = null; |
||||
57 | |||||
58 | /** |
||||
59 | * @var Swift_Message |
||||
60 | */ |
||||
61 | private $swiftMessage; |
||||
62 | |||||
63 | /** |
||||
64 | * @var string The name of the HTML template to render the email with (without *.ss extension) |
||||
65 | */ |
||||
66 | private $HTMLTemplate = null; |
||||
67 | |||||
68 | /** |
||||
69 | * @var string The name of the plain text template to render the plain part of the email with |
||||
70 | */ |
||||
71 | private $plainTemplate = null; |
||||
72 | |||||
73 | /** |
||||
74 | * @var Swift_MimePart |
||||
75 | */ |
||||
76 | private $plainPart; |
||||
77 | |||||
78 | /** |
||||
79 | * @var array|ViewableData Additional data available in a template. |
||||
80 | * Used in the same way than {@link ViewableData->customize()}. |
||||
81 | */ |
||||
82 | private $data = array(); |
||||
83 | |||||
84 | /** |
||||
85 | * @var array |
||||
86 | */ |
||||
87 | private $failedRecipients = array(); |
||||
88 | |||||
89 | /** |
||||
90 | * Checks for RFC822-valid email format. |
||||
91 | * |
||||
92 | * @param string $address |
||||
93 | * @return boolean |
||||
94 | * |
||||
95 | * @copyright Cal Henderson <[email protected]> |
||||
96 | * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License |
||||
97 | * http://creativecommons.org/licenses/by-sa/2.5/ |
||||
98 | */ |
||||
99 | public static function is_valid_address($address) |
||||
100 | { |
||||
101 | return \Swift_Validate::email($address); |
||||
102 | } |
||||
103 | |||||
104 | /** |
||||
105 | * Get send_all_emails_to |
||||
106 | * |
||||
107 | * @return array Keys are addresses, values are names |
||||
108 | */ |
||||
109 | public static function getSendAllEmailsTo() |
||||
110 | { |
||||
111 | return static::mergeConfiguredEmails('send_all_emails_to', 'SS_SEND_ALL_EMAILS_TO'); |
||||
112 | } |
||||
113 | |||||
114 | /** |
||||
115 | * Get cc_all_emails_to |
||||
116 | * |
||||
117 | * @return array |
||||
118 | */ |
||||
119 | public static function getCCAllEmailsTo() |
||||
120 | { |
||||
121 | return static::mergeConfiguredEmails('cc_all_emails_to', 'SS_CC_ALL_EMAILS_TO'); |
||||
122 | } |
||||
123 | |||||
124 | /** |
||||
125 | * Get bcc_all_emails_to |
||||
126 | * |
||||
127 | * @return array |
||||
128 | */ |
||||
129 | public static function getBCCAllEmailsTo() |
||||
130 | { |
||||
131 | return static::mergeConfiguredEmails('bcc_all_emails_to', 'SS_BCC_ALL_EMAILS_TO'); |
||||
132 | } |
||||
133 | |||||
134 | /** |
||||
135 | * Get send_all_emails_from |
||||
136 | * |
||||
137 | * @return array |
||||
138 | */ |
||||
139 | public static function getSendAllEmailsFrom() |
||||
140 | { |
||||
141 | return static::mergeConfiguredEmails('send_all_emails_from', 'SS_SEND_ALL_EMAILS_FROM'); |
||||
142 | } |
||||
143 | |||||
144 | /** |
||||
145 | * Normalise email list from config merged with env vars |
||||
146 | * |
||||
147 | * @param string $config Config key |
||||
148 | * @param string $env Env variable key |
||||
149 | * @return array Array of email addresses |
||||
150 | */ |
||||
151 | protected static function mergeConfiguredEmails($config, $env) |
||||
152 | { |
||||
153 | // Normalise config list |
||||
154 | $normalised = []; |
||||
155 | $source = (array)static::config()->get($config); |
||||
156 | foreach ($source as $address => $name) { |
||||
157 | if ($address && !is_numeric($address)) { |
||||
158 | $normalised[$address] = $name; |
||||
159 | } elseif ($name) { |
||||
160 | $normalised[$name] = null; |
||||
161 | } |
||||
162 | } |
||||
163 | $extra = Environment::getEnv($env); |
||||
164 | if ($extra) { |
||||
165 | $normalised[$extra] = null; |
||||
166 | } |
||||
167 | return $normalised; |
||||
168 | } |
||||
169 | |||||
170 | /** |
||||
171 | * Encode an email-address to protect it from spambots. |
||||
172 | * At the moment only simple string substitutions, |
||||
173 | * which are not 100% safe from email harvesting. |
||||
174 | * |
||||
175 | * @param string $email Email-address |
||||
176 | * @param string $method Method for obfuscating/encoding the address |
||||
177 | * - 'direction': Reverse the text and then use CSS to put the text direction back to normal |
||||
178 | * - 'visible': Simple string substitution ('@' to '[at]', '.' to '[dot], '-' to [dash]) |
||||
179 | * - 'hex': Hexadecimal URL-Encoding - useful for mailto: links |
||||
180 | * @return string |
||||
181 | */ |
||||
182 | public static function obfuscate($email, $method = 'visible') |
||||
183 | { |
||||
184 | switch ($method) { |
||||
185 | case 'direction': |
||||
186 | Requirements::customCSS('span.codedirection { unicode-bidi: bidi-override; direction: rtl; }', 'codedirectionCSS'); |
||||
187 | |||||
188 | return '<span class="codedirection">' . strrev($email) . '</span>'; |
||||
189 | case 'visible': |
||||
190 | $obfuscated = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '); |
||||
191 | |||||
192 | return strtr($email, $obfuscated); |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
The call to
strtr() has too few arguments starting with to .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||
193 | case 'hex': |
||||
194 | $encoded = ''; |
||||
195 | for ($x = 0; $x < strlen($email); $x++) { |
||||
196 | $encoded .= '&#x' . bin2hex($email{$x}) . ';'; |
||||
197 | } |
||||
198 | |||||
199 | return $encoded; |
||||
200 | default: |
||||
201 | user_error('Email::obfuscate(): Unknown obfuscation method', E_USER_NOTICE); |
||||
202 | |||||
203 | return $email; |
||||
204 | } |
||||
205 | } |
||||
206 | |||||
207 | /** |
||||
208 | * Email constructor. |
||||
209 | * @param string|array|null $from |
||||
210 | * @param string|array|null $to |
||||
211 | * @param string|null $subject |
||||
212 | * @param string|null $body |
||||
213 | * @param string|array|null $cc |
||||
214 | * @param string|array|null $bcc |
||||
215 | * @param string|null $returnPath |
||||
216 | */ |
||||
217 | public function __construct( |
||||
218 | $from = null, |
||||
219 | $to = null, |
||||
220 | $subject = null, |
||||
221 | $body = null, |
||||
222 | $cc = null, |
||||
223 | $bcc = null, |
||||
224 | $returnPath = null |
||||
225 | ) { |
||||
226 | if ($from) { |
||||
227 | $this->setFrom($from); |
||||
228 | } |
||||
229 | if ($to) { |
||||
230 | $this->setTo($to); |
||||
231 | } |
||||
232 | if ($subject) { |
||||
0 ignored issues
–
show
The expression
$subject of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
233 | $this->setSubject($subject); |
||||
234 | } |
||||
235 | if ($body) { |
||||
0 ignored issues
–
show
The expression
$body of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
236 | $this->setBody($body); |
||||
237 | } |
||||
238 | if ($cc) { |
||||
239 | $this->setCC($cc); |
||||
240 | } |
||||
241 | if ($bcc) { |
||||
242 | $this->setBCC($bcc); |
||||
243 | } |
||||
244 | if ($returnPath) { |
||||
0 ignored issues
–
show
The expression
$returnPath of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
245 | $this->setReturnPath($returnPath); |
||||
246 | } |
||||
247 | |||||
248 | parent::__construct(); |
||||
249 | } |
||||
250 | |||||
251 | /** |
||||
252 | * @return Swift_Message |
||||
253 | */ |
||||
254 | public function getSwiftMessage() |
||||
255 | { |
||||
256 | if (!$this->swiftMessage) { |
||||
257 | $this->setSwiftMessage(new Swift_Message(null, null, 'text/html', 'utf-8')); |
||||
258 | } |
||||
259 | |||||
260 | return $this->swiftMessage; |
||||
261 | } |
||||
262 | |||||
263 | /** |
||||
264 | * @param Swift_Message $swiftMessage |
||||
265 | * |
||||
266 | * @return $this |
||||
267 | */ |
||||
268 | public function setSwiftMessage($swiftMessage) |
||||
269 | { |
||||
270 | $swiftMessage->setDate(DBDatetime::now()->getTimestamp()); |
||||
271 | if (!$swiftMessage->getFrom() && ($defaultFrom = $this->config()->get('admin_email'))) { |
||||
272 | $swiftMessage->setFrom($defaultFrom); |
||||
273 | } |
||||
274 | $this->swiftMessage = $swiftMessage; |
||||
275 | |||||
276 | return $this; |
||||
277 | } |
||||
278 | |||||
279 | /** |
||||
280 | * @return string[] |
||||
281 | */ |
||||
282 | public function getFrom() |
||||
283 | { |
||||
284 | return $this->getSwiftMessage()->getFrom(); |
||||
285 | } |
||||
286 | |||||
287 | /** |
||||
288 | * @param string|array $address |
||||
289 | * @param string|null $name |
||||
290 | * @return $this |
||||
291 | */ |
||||
292 | public function setFrom($address, $name = null) |
||||
293 | { |
||||
294 | $this->getSwiftMessage()->setFrom($address, $name); |
||||
295 | |||||
296 | return $this; |
||||
297 | } |
||||
298 | |||||
299 | /** |
||||
300 | * @param string|array $address |
||||
301 | * @param string|null $name |
||||
302 | * @return $this |
||||
303 | */ |
||||
304 | public function addFrom($address, $name = null) |
||||
305 | { |
||||
306 | $this->getSwiftMessage()->addFrom($address, $name); |
||||
0 ignored issues
–
show
It seems like
$address can also be of type array ; however, parameter $address of Swift_Mime_SimpleMessage::addFrom() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
307 | |||||
308 | return $this; |
||||
309 | } |
||||
310 | |||||
311 | /** |
||||
312 | * @return string |
||||
313 | */ |
||||
314 | public function getSender() |
||||
315 | { |
||||
316 | return $this->getSwiftMessage()->getSender(); |
||||
317 | } |
||||
318 | |||||
319 | /** |
||||
320 | * @param string $address |
||||
321 | * @param string|null $name |
||||
322 | * @return $this |
||||
323 | */ |
||||
324 | public function setSender($address, $name = null) |
||||
325 | { |
||||
326 | $this->getSwiftMessage()->setSender($address, $name); |
||||
327 | |||||
328 | return $this; |
||||
329 | } |
||||
330 | |||||
331 | /** |
||||
332 | * @return string |
||||
333 | */ |
||||
334 | public function getReturnPath() |
||||
335 | { |
||||
336 | return $this->getSwiftMessage()->getReturnPath(); |
||||
337 | } |
||||
338 | |||||
339 | /** |
||||
340 | * The bounce handler address |
||||
341 | * |
||||
342 | * @param string $address Email address where bounce notifications should be sent |
||||
343 | * @return $this |
||||
344 | */ |
||||
345 | public function setReturnPath($address) |
||||
346 | { |
||||
347 | $this->getSwiftMessage()->setReturnPath($address); |
||||
348 | return $this; |
||||
349 | } |
||||
350 | |||||
351 | /** |
||||
352 | * @return array |
||||
353 | */ |
||||
354 | public function getTo() |
||||
355 | { |
||||
356 | return $this->getSwiftMessage()->getTo(); |
||||
357 | } |
||||
358 | |||||
359 | /** |
||||
360 | * Set recipient(s) of the email |
||||
361 | * |
||||
362 | * To send to many, pass an array: |
||||
363 | * array('[email protected]' => 'My Name', '[email protected]'); |
||||
364 | * |
||||
365 | * @param string|array $address The message recipient(s) - if sending to multiple, use an array of address => name |
||||
366 | * @param string|null $name The name of the recipient (if one) |
||||
367 | * @return $this |
||||
368 | */ |
||||
369 | public function setTo($address, $name = null) |
||||
370 | { |
||||
371 | $this->getSwiftMessage()->setTo($address, $name); |
||||
372 | |||||
373 | return $this; |
||||
374 | } |
||||
375 | |||||
376 | /** |
||||
377 | * @param string|array $address |
||||
378 | * @param string|null $name |
||||
379 | * @return $this |
||||
380 | */ |
||||
381 | public function addTo($address, $name = null) |
||||
382 | { |
||||
383 | $this->getSwiftMessage()->addTo($address, $name); |
||||
0 ignored issues
–
show
It seems like
$address can also be of type array ; however, parameter $address of Swift_Mime_SimpleMessage::addTo() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
384 | |||||
385 | return $this; |
||||
386 | } |
||||
387 | |||||
388 | /** |
||||
389 | * @return array |
||||
390 | */ |
||||
391 | public function getCC() |
||||
392 | { |
||||
393 | return $this->getSwiftMessage()->getCc(); |
||||
394 | } |
||||
395 | |||||
396 | /** |
||||
397 | * @param string|array $address |
||||
398 | * @param string|null $name |
||||
399 | * @return $this |
||||
400 | */ |
||||
401 | public function setCC($address, $name = null) |
||||
402 | { |
||||
403 | $this->getSwiftMessage()->setCc($address, $name); |
||||
404 | |||||
405 | return $this; |
||||
406 | } |
||||
407 | |||||
408 | /** |
||||
409 | * @param string|array $address |
||||
410 | * @param string|null $name |
||||
411 | * @return $this |
||||
412 | */ |
||||
413 | public function addCC($address, $name = null) |
||||
414 | { |
||||
415 | $this->getSwiftMessage()->addCc($address, $name); |
||||
0 ignored issues
–
show
It seems like
$address can also be of type array ; however, parameter $address of Swift_Mime_SimpleMessage::addCc() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
416 | |||||
417 | return $this; |
||||
418 | } |
||||
419 | |||||
420 | /** |
||||
421 | * @return array |
||||
422 | */ |
||||
423 | public function getBCC() |
||||
424 | { |
||||
425 | return $this->getSwiftMessage()->getBcc(); |
||||
426 | } |
||||
427 | |||||
428 | /** |
||||
429 | * @param string|array $address |
||||
430 | * @param string|null $name |
||||
431 | * @return $this |
||||
432 | */ |
||||
433 | public function setBCC($address, $name = null) |
||||
434 | { |
||||
435 | $this->getSwiftMessage()->setBcc($address, $name); |
||||
436 | |||||
437 | return $this; |
||||
438 | } |
||||
439 | |||||
440 | /** |
||||
441 | * @param string|array $address |
||||
442 | * @param string|null $name |
||||
443 | * @return $this |
||||
444 | */ |
||||
445 | public function addBCC($address, $name = null) |
||||
446 | { |
||||
447 | $this->getSwiftMessage()->addBcc($address, $name); |
||||
0 ignored issues
–
show
It seems like
$address can also be of type array ; however, parameter $address of Swift_Mime_SimpleMessage::addBcc() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
448 | |||||
449 | return $this; |
||||
450 | } |
||||
451 | |||||
452 | public function getReplyTo() |
||||
453 | { |
||||
454 | return $this->getSwiftMessage()->getReplyTo(); |
||||
455 | } |
||||
456 | |||||
457 | /** |
||||
458 | * @param string|array $address |
||||
459 | * @param string|null $name |
||||
460 | * @return $this |
||||
461 | */ |
||||
462 | public function setReplyTo($address, $name = null) |
||||
463 | { |
||||
464 | $this->getSwiftMessage()->setReplyTo($address, $name); |
||||
465 | |||||
466 | return $this; |
||||
467 | } |
||||
468 | |||||
469 | /** |
||||
470 | * @param string|array $address |
||||
471 | * @param string|null $name |
||||
472 | * @return $this |
||||
473 | */ |
||||
474 | public function addReplyTo($address, $name = null) |
||||
475 | { |
||||
476 | $this->getSwiftMessage()->addReplyTo($address, $name); |
||||
0 ignored issues
–
show
It seems like
$address can also be of type array ; however, parameter $address of Swift_Mime_SimpleMessage::addReplyTo() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
477 | |||||
478 | return $this; |
||||
479 | } |
||||
480 | |||||
481 | /** |
||||
482 | * @return string |
||||
483 | */ |
||||
484 | public function getSubject() |
||||
485 | { |
||||
486 | return $this->getSwiftMessage()->getSubject(); |
||||
487 | } |
||||
488 | |||||
489 | /** |
||||
490 | * @param string $subject The Subject line for the email |
||||
491 | * @return $this |
||||
492 | */ |
||||
493 | public function setSubject($subject) |
||||
494 | { |
||||
495 | $this->getSwiftMessage()->setSubject($subject); |
||||
496 | |||||
497 | return $this; |
||||
498 | } |
||||
499 | |||||
500 | /** |
||||
501 | * @return int |
||||
502 | */ |
||||
503 | public function getPriority() |
||||
504 | { |
||||
505 | return $this->getSwiftMessage()->getPriority(); |
||||
506 | } |
||||
507 | |||||
508 | /** |
||||
509 | * @param int $priority |
||||
510 | * @return $this |
||||
511 | */ |
||||
512 | public function setPriority($priority) |
||||
513 | { |
||||
514 | $this->getSwiftMessage()->setPriority($priority); |
||||
515 | |||||
516 | return $this; |
||||
517 | } |
||||
518 | |||||
519 | /** |
||||
520 | * @param string $path Path to file |
||||
521 | * @param string $alias An override for the name of the file |
||||
522 | * @param string $mime The mime type for the attachment |
||||
523 | * @return $this |
||||
524 | */ |
||||
525 | public function addAttachment($path, $alias = null, $mime = null) |
||||
526 | { |
||||
527 | $attachment = \Swift_Attachment::fromPath($path); |
||||
528 | if ($alias) { |
||||
0 ignored issues
–
show
The expression
$alias of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
529 | $attachment->setFilename($alias); |
||||
530 | } |
||||
531 | if ($mime) { |
||||
0 ignored issues
–
show
The expression
$mime of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
532 | $attachment->setContentType($mime); |
||||
533 | } |
||||
534 | $this->getSwiftMessage()->attach($attachment); |
||||
535 | |||||
536 | return $this; |
||||
537 | } |
||||
538 | |||||
539 | /** |
||||
540 | * @param string $data |
||||
541 | * @param string $name |
||||
542 | * @param string $mime |
||||
543 | * @return $this |
||||
544 | */ |
||||
545 | public function addAttachmentFromData($data, $name, $mime = null) |
||||
546 | { |
||||
547 | $attachment = new \Swift_Attachment($data, $name); |
||||
548 | if ($mime) { |
||||
0 ignored issues
–
show
The expression
$mime of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
549 | $attachment->setContentType($mime); |
||||
550 | } |
||||
551 | $this->getSwiftMessage()->attach($attachment); |
||||
552 | |||||
553 | return $this; |
||||
554 | } |
||||
555 | |||||
556 | /** |
||||
557 | * @return array|ViewableData The template data |
||||
558 | */ |
||||
559 | public function getData() |
||||
560 | { |
||||
561 | return $this->data; |
||||
562 | } |
||||
563 | |||||
564 | /** |
||||
565 | * @param array|ViewableData $data The template data to set |
||||
566 | * @return $this |
||||
567 | */ |
||||
568 | public function setData($data) |
||||
569 | { |
||||
570 | $this->data = $data; |
||||
571 | |||||
572 | return $this; |
||||
573 | } |
||||
574 | |||||
575 | /** |
||||
576 | * @param string|array $name The data name to add or array to names => value |
||||
577 | * @param string|null $value The value of the data to add |
||||
578 | * @return $this |
||||
579 | */ |
||||
580 | public function addData($name, $value = null) |
||||
581 | { |
||||
582 | if (is_array($name)) { |
||||
583 | $this->data = array_merge($this->data, $name); |
||||
0 ignored issues
–
show
It seems like
$this->data can also be of type SilverStripe\View\ViewableData ; however, parameter $array1 of array_merge() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
584 | } elseif (is_array($this->data)) { |
||||
585 | $this->data[$name] = $value; |
||||
586 | } else { |
||||
587 | $this->data->$name = $value; |
||||
588 | } |
||||
589 | |||||
590 | return $this; |
||||
591 | } |
||||
592 | |||||
593 | /** |
||||
594 | * Remove a datum from the message |
||||
595 | * |
||||
596 | * @param string $name |
||||
597 | * @return $this |
||||
598 | */ |
||||
599 | public function removeData($name) |
||||
600 | { |
||||
601 | if (is_array($this->data)) { |
||||
602 | unset($this->data[$name]); |
||||
603 | } else { |
||||
604 | $this->data->$name = null; |
||||
605 | } |
||||
606 | |||||
607 | return $this; |
||||
608 | } |
||||
609 | |||||
610 | /** |
||||
611 | * @return string |
||||
612 | */ |
||||
613 | public function getBody() |
||||
614 | { |
||||
615 | return $this->getSwiftMessage()->getBody(); |
||||
616 | } |
||||
617 | |||||
618 | /** |
||||
619 | * @param string $body The email body |
||||
620 | * @return $this |
||||
621 | */ |
||||
622 | public function setBody($body) |
||||
623 | { |
||||
624 | $plainPart = $this->findPlainPart(); |
||||
625 | if ($plainPart) { |
||||
626 | $this->getSwiftMessage()->detach($plainPart); |
||||
627 | } |
||||
628 | unset($plainPart); |
||||
629 | |||||
630 | $body = HTTP::absoluteURLs($body); |
||||
631 | $this->getSwiftMessage()->setBody($body); |
||||
632 | |||||
633 | return $this; |
||||
634 | } |
||||
635 | |||||
636 | /** |
||||
637 | * @return string The base URL for the email |
||||
638 | */ |
||||
639 | public function BaseURL() |
||||
640 | { |
||||
641 | return Director::absoluteBaseURL(); |
||||
642 | } |
||||
643 | |||||
644 | /** |
||||
645 | * Debugging help |
||||
646 | * |
||||
647 | * @return string Debug info |
||||
648 | */ |
||||
649 | public function debug() |
||||
650 | { |
||||
651 | $this->render(); |
||||
652 | |||||
653 | $class = static::class; |
||||
654 | return "<h2>Email template {$class}:</h2>\n" . '<pre>' . $this->getSwiftMessage()->toString() . '</pre>'; |
||||
655 | } |
||||
656 | |||||
657 | /** |
||||
658 | * @return string |
||||
659 | */ |
||||
660 | public function getHTMLTemplate() |
||||
661 | { |
||||
662 | if ($this->HTMLTemplate) { |
||||
663 | return $this->HTMLTemplate; |
||||
664 | } |
||||
665 | |||||
666 | return ThemeResourceLoader::inst()->findTemplate( |
||||
667 | SSViewer::get_templates_by_class(static::class, '', self::class), |
||||
668 | SSViewer::get_themes() |
||||
669 | ); |
||||
670 | } |
||||
671 | |||||
672 | /** |
||||
673 | * Set the template to render the email with |
||||
674 | * |
||||
675 | * @param string $template |
||||
676 | * @return $this |
||||
677 | */ |
||||
678 | public function setHTMLTemplate($template) |
||||
679 | { |
||||
680 | if (substr($template, -3) == '.ss') { |
||||
681 | $template = substr($template, 0, -3); |
||||
682 | } |
||||
683 | $this->HTMLTemplate = $template; |
||||
0 ignored issues
–
show
It seems like
$template can also be of type false . However, the property $HTMLTemplate is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||||
684 | |||||
685 | return $this; |
||||
686 | } |
||||
687 | |||||
688 | /** |
||||
689 | * Get the template to render the plain part with |
||||
690 | * |
||||
691 | * @return string |
||||
692 | */ |
||||
693 | public function getPlainTemplate() |
||||
694 | { |
||||
695 | return $this->plainTemplate; |
||||
696 | } |
||||
697 | |||||
698 | /** |
||||
699 | * Set the template to render the plain part with |
||||
700 | * |
||||
701 | * @param string $template |
||||
702 | * @return $this |
||||
703 | */ |
||||
704 | public function setPlainTemplate($template) |
||||
705 | { |
||||
706 | if (substr($template, -3) == '.ss') { |
||||
707 | $template = substr($template, 0, -3); |
||||
708 | } |
||||
709 | $this->plainTemplate = $template; |
||||
0 ignored issues
–
show
It seems like
$template can also be of type false . However, the property $plainTemplate is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||||
710 | |||||
711 | return $this; |
||||
712 | } |
||||
713 | |||||
714 | /** |
||||
715 | * @param array $recipients |
||||
716 | * @return $this |
||||
717 | */ |
||||
718 | public function setFailedRecipients($recipients) |
||||
719 | { |
||||
720 | $this->failedRecipients = $recipients; |
||||
721 | |||||
722 | return $this; |
||||
723 | } |
||||
724 | |||||
725 | /** |
||||
726 | * @return array |
||||
727 | */ |
||||
728 | public function getFailedRecipients() |
||||
729 | { |
||||
730 | return $this->failedRecipients; |
||||
731 | } |
||||
732 | |||||
733 | /** |
||||
734 | * Used by {@link SSViewer} templates to detect if we're rendering an email template rather than a page template |
||||
735 | * |
||||
736 | * @return bool |
||||
737 | */ |
||||
738 | public function IsEmail() |
||||
739 | { |
||||
740 | return true; |
||||
741 | } |
||||
742 | |||||
743 | /** |
||||
744 | * Send the message to the recipients |
||||
745 | * |
||||
746 | * @return bool true if successful or array of failed recipients |
||||
747 | */ |
||||
748 | public function send() |
||||
749 | { |
||||
750 | if (!$this->getBody()) { |
||||
751 | $this->render(); |
||||
752 | } |
||||
753 | if (!$this->hasPlainPart()) { |
||||
754 | $this->generatePlainPartFromBody(); |
||||
755 | } |
||||
756 | return Injector::inst()->get(Mailer::class)->send($this); |
||||
757 | } |
||||
758 | |||||
759 | /** |
||||
760 | * @return array|bool |
||||
761 | */ |
||||
762 | public function sendPlain() |
||||
763 | { |
||||
764 | if (!$this->hasPlainPart()) { |
||||
765 | $this->render(true); |
||||
766 | } |
||||
767 | return Injector::inst()->get(Mailer::class)->send($this); |
||||
768 | } |
||||
769 | |||||
770 | /** |
||||
771 | * Render the email |
||||
772 | * @param bool $plainOnly Only render the message as plain text |
||||
773 | * @return $this |
||||
774 | */ |
||||
775 | public function render($plainOnly = false) |
||||
776 | { |
||||
777 | if ($existingPlainPart = $this->findPlainPart()) { |
||||
778 | $this->getSwiftMessage()->detach($existingPlainPart); |
||||
779 | } |
||||
780 | unset($existingPlainPart); |
||||
781 | |||||
782 | // Respect explicitly set body |
||||
783 | $htmlPart = $plainOnly ? null : $this->getBody(); |
||||
784 | $plainPart = $plainOnly ? $this->getBody() : null; |
||||
785 | |||||
786 | // Ensure we can at least render something |
||||
787 | $htmlTemplate = $this->getHTMLTemplate(); |
||||
788 | $plainTemplate = $this->getPlainTemplate(); |
||||
789 | if (!$htmlTemplate && !$plainTemplate && !$plainPart && !$htmlPart) { |
||||
0 ignored issues
–
show
The expression
$plainPart of type null|string is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
The expression
$htmlPart of type null|string is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
790 | return $this; |
||||
791 | } |
||||
792 | |||||
793 | // Render plain part |
||||
794 | if ($plainTemplate && !$plainPart) { |
||||
0 ignored issues
–
show
The expression
$plainPart of type null|string is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
795 | $plainPart = $this->renderWith($plainTemplate, $this->getData()); |
||||
0 ignored issues
–
show
It seems like
$this->getData() can also be of type SilverStripe\View\ViewableData ; however, parameter $customFields of SilverStripe\View\ViewableData::renderWith() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
796 | } |
||||
797 | |||||
798 | // Render HTML part, either if sending html email, or a plain part is lacking |
||||
799 | if (!$htmlPart && $htmlTemplate && (!$plainOnly || empty($plainPart))) { |
||||
0 ignored issues
–
show
The expression
$htmlPart of type null|string is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
800 | $htmlPart = $this->renderWith($htmlTemplate, $this->getData()); |
||||
801 | } |
||||
802 | |||||
803 | // Plain part fails over to generated from html |
||||
804 | if (!$plainPart && $htmlPart) { |
||||
805 | /** @var DBHTMLText $htmlPartObject */ |
||||
806 | $htmlPartObject = DBField::create_field('HTMLFragment', $htmlPart); |
||||
807 | $plainPart = $htmlPartObject->Plain(); |
||||
808 | } |
||||
809 | |||||
810 | // Fail if no email to send |
||||
811 | if (!$plainPart && !$htmlPart) { |
||||
812 | return $this; |
||||
813 | } |
||||
814 | |||||
815 | // Build HTML / Plain components |
||||
816 | if ($htmlPart && !$plainOnly) { |
||||
817 | $this->setBody($htmlPart); |
||||
818 | $this->getSwiftMessage()->setContentType('text/html'); |
||||
819 | $this->getSwiftMessage()->setCharset('utf-8'); |
||||
820 | if ($plainPart) { |
||||
821 | $this->getSwiftMessage()->addPart($plainPart, 'text/plain', 'utf-8'); |
||||
822 | } |
||||
823 | } else { |
||||
824 | if ($plainPart) { |
||||
825 | $this->setBody($plainPart); |
||||
826 | } |
||||
827 | $this->getSwiftMessage()->setContentType('text/plain'); |
||||
828 | $this->getSwiftMessage()->setCharset('utf-8'); |
||||
829 | } |
||||
830 | |||||
831 | return $this; |
||||
832 | } |
||||
833 | |||||
834 | /** |
||||
835 | * @return Swift_MimePart|false |
||||
836 | */ |
||||
837 | public function findPlainPart() |
||||
838 | { |
||||
839 | foreach ($this->getSwiftMessage()->getChildren() as $child) { |
||||
840 | if ($child instanceof Swift_MimePart && $child->getContentType() == 'text/plain') { |
||||
841 | return $child; |
||||
842 | } |
||||
843 | } |
||||
844 | return false; |
||||
845 | } |
||||
846 | |||||
847 | /** |
||||
848 | * @return bool |
||||
849 | */ |
||||
850 | public function hasPlainPart() |
||||
851 | { |
||||
852 | if ($this->getSwiftMessage()->getContentType() === 'text/plain') { |
||||
853 | return true; |
||||
854 | } |
||||
855 | return (bool) $this->findPlainPart(); |
||||
856 | } |
||||
857 | |||||
858 | /** |
||||
859 | * Automatically adds a plain part to the email generated from the current Body |
||||
860 | * |
||||
861 | * @return $this |
||||
862 | */ |
||||
863 | public function generatePlainPartFromBody() |
||||
864 | { |
||||
865 | $plainPart = $this->findPlainPart(); |
||||
866 | if ($plainPart) { |
||||
867 | $this->getSwiftMessage()->detach($plainPart); |
||||
868 | } |
||||
869 | unset($plainPart); |
||||
870 | |||||
871 | $this->getSwiftMessage()->addPart( |
||||
872 | Convert::xml2raw($this->getBody()), |
||||
873 | 'text/plain', |
||||
874 | 'utf-8' |
||||
875 | ); |
||||
876 | |||||
877 | return $this; |
||||
878 | } |
||||
879 | } |
||||
880 |