1 | <?php |
||
2 | /** |
||
3 | * Message.php |
||
4 | * |
||
5 | * PHP version 5.6+ |
||
6 | * |
||
7 | * @author Manuel Avelar <[email protected]> |
||
8 | * @copyright 2024 Manuel Avelar |
||
9 | * @license http://www.pixelcreart.com/license license |
||
10 | * @version 1.0.0 |
||
11 | * @link http://www.pixelcreart.com |
||
12 | * @package pixelcreart\sendgrid |
||
13 | */ |
||
14 | |||
15 | namespace pixelcreart\sendgrid; |
||
16 | |||
17 | use Yii; |
||
18 | use yii\base\InvalidConfigException; |
||
19 | use yii\base\InvalidArgumentException; |
||
20 | use yii\mail\BaseMessage; |
||
21 | use yii\mail\MailerInterface; |
||
22 | |||
23 | /** |
||
24 | * This component allow user to send an email |
||
25 | * |
||
26 | * @author Manuel Avelar <[email protected]> |
||
27 | * @copyright 2024 Manuel Avelar |
||
28 | * @license http://www.pixelcreart.com/license license |
||
29 | * @version 1.0.0 |
||
30 | * @link http://www.pixelcreart.com |
||
31 | * @package pixelcreart\sendgrid |
||
32 | * @since 1.0.0 |
||
33 | */ |
||
34 | class Message extends BaseMessage |
||
35 | { |
||
36 | /** |
||
37 | * @var string|array from |
||
38 | */ |
||
39 | protected $from; |
||
40 | |||
41 | /** |
||
42 | * @var array |
||
43 | */ |
||
44 | protected $to = []; |
||
45 | |||
46 | /** |
||
47 | * @var string|array reply to |
||
48 | */ |
||
49 | protected $replyTo; |
||
50 | |||
51 | /** |
||
52 | * @var array |
||
53 | */ |
||
54 | protected $cc = []; |
||
55 | |||
56 | /** |
||
57 | * @var array |
||
58 | */ |
||
59 | protected $bcc = []; |
||
60 | |||
61 | /** |
||
62 | * @var string |
||
63 | */ |
||
64 | protected $subject; |
||
65 | |||
66 | /** |
||
67 | * @var string |
||
68 | */ |
||
69 | protected $textBody; |
||
70 | |||
71 | /** |
||
72 | * @var string |
||
73 | */ |
||
74 | protected $htmlBody; |
||
75 | |||
76 | /** |
||
77 | * @var array |
||
78 | */ |
||
79 | protected $attachments = []; |
||
80 | |||
81 | /** |
||
82 | * @var string temporary attachment directory |
||
83 | */ |
||
84 | protected $attachmentsTmdDir; |
||
85 | |||
86 | /** |
||
87 | * @var array |
||
88 | */ |
||
89 | protected $uniqueArguments = []; |
||
90 | |||
91 | /** |
||
92 | * @var array |
||
93 | */ |
||
94 | protected $headers = []; |
||
95 | |||
96 | /** |
||
97 | * @var string |
||
98 | */ |
||
99 | protected $templateId; |
||
100 | |||
101 | /** |
||
102 | * @var array |
||
103 | */ |
||
104 | protected $templateModel; |
||
105 | |||
106 | /** |
||
107 | * @var array substitution pairs used to mark expandable vars in template mode https://github.com/sendgrid/sendgrid-php#setsubstitutions |
||
108 | */ |
||
109 | public $substitutionsPairs = ['{', '}']; |
||
110 | |||
111 | /** |
||
112 | * @inheritdoc |
||
113 | */ |
||
114 | public function getCharset() |
||
115 | { |
||
116 | return true; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * @inheritdoc |
||
121 | */ |
||
122 | public function setCharset($charset) |
||
123 | { |
||
124 | return true; |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @inheritdoc |
||
129 | */ |
||
130 | public function getFrom() |
||
131 | { |
||
132 | $fromMail = null; |
||
133 | reset($this->from); |
||
134 | foreach($this->from as $email => $name) { |
||
135 | if (is_numeric($email) === true) { |
||
136 | $fromMail = $name; |
||
137 | } else { |
||
138 | $fromMail = $email; |
||
139 | } |
||
140 | } |
||
141 | |||
142 | return $fromMail; |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * @return string|null extract and return the name associated with from |
||
147 | * @since 1.0.0 |
||
148 | */ |
||
149 | public function getFromName() |
||
150 | { |
||
151 | reset($this->from); |
||
152 | foreach($this->from as $email => $name) { |
||
153 | if (is_numeric($email) === false) { |
||
154 | return $name; |
||
155 | } else { |
||
156 | return null; |
||
157 | } |
||
158 | } |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * @inheritdoc |
||
163 | */ |
||
164 | public function setFrom($from) |
||
165 | { |
||
166 | if (is_string($from) === true) { |
||
167 | $from = [$from]; |
||
168 | } |
||
169 | $this->from = $from; |
||
170 | return $this; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @inheritdoc |
||
175 | */ |
||
176 | public function getTo() |
||
177 | { |
||
178 | return self::normalizeEmails($this->to); |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * @inheritdoc |
||
183 | */ |
||
184 | public function setTo($to) |
||
185 | { |
||
186 | $this->to = $to; |
||
187 | return $this; |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * @inheritdoc |
||
192 | */ |
||
193 | public function getReplyTo() |
||
194 | { |
||
195 | $replyTo = null; |
||
196 | if (is_array($this->replyTo) === true) { |
||
197 | reset($this->replyTo); |
||
198 | foreach($this->replyTo as $email => $name) { |
||
199 | if (is_numeric($email) === true) { |
||
200 | $replyTo = $name; |
||
201 | } else { |
||
202 | $replyTo = $email; |
||
203 | } |
||
204 | } |
||
205 | } |
||
206 | return $replyTo; |
||
207 | } |
||
208 | |||
209 | /** |
||
210 | * @inheritdoc |
||
211 | */ |
||
212 | public function setReplyTo($replyTo) |
||
213 | { |
||
214 | if (is_string($replyTo) === true) { |
||
215 | $replyTo = [$replyTo]; |
||
216 | } |
||
217 | $this->replyTo = $replyTo; |
||
218 | return $this; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * @inheritdoc |
||
223 | */ |
||
224 | public function getCc() |
||
225 | { |
||
226 | return $this->cc; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * @inheritdoc |
||
231 | */ |
||
232 | public function setCc($cc) |
||
233 | { |
||
234 | $this->cc = self::normalizeEmails($cc); |
||
235 | return $this; |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * @inheritdoc |
||
240 | */ |
||
241 | public function getBcc() |
||
242 | { |
||
243 | return $this->bcc; |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * @inheritdoc |
||
248 | */ |
||
249 | public function setBcc($bcc) |
||
250 | { |
||
251 | $this->bcc = self::normalizeEmails($bcc); |
||
252 | return $this; |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * @inheritdoc |
||
257 | */ |
||
258 | public function getSubject() |
||
259 | { |
||
260 | return $this->subject; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * @inheritdoc |
||
265 | */ |
||
266 | public function setSubject($subject) |
||
267 | { |
||
268 | $this->subject = $subject; |
||
269 | return $this; |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * @return string|null text body of the message |
||
274 | * @since 1.0.0 |
||
275 | */ |
||
276 | public function getTextBody() |
||
277 | { |
||
278 | return $this->textBody; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * @inheritdoc |
||
283 | */ |
||
284 | public function setTextBody($text) |
||
285 | { |
||
286 | $this->textBody = $text; |
||
287 | return $this; |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * @return string|null html body of the message |
||
292 | * @since 1.0.0 |
||
293 | */ |
||
294 | public function getHtmlBody() |
||
295 | { |
||
296 | return $this->htmlBody; |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * @inheritdoc |
||
301 | */ |
||
302 | public function setHtmlBody($html) |
||
303 | { |
||
304 | $this->htmlBody = $html; |
||
305 | return $this; |
||
306 | } |
||
307 | |||
308 | /** |
||
309 | * @return array list of unique arguments attached to the email |
||
310 | * @since 1.0.0 |
||
311 | */ |
||
312 | public function getUniqueArguments() |
||
313 | { |
||
314 | return $this->uniqueArguments; |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * @param string $key key of the unique argument |
||
319 | * @param string $value value of the unique argument which will be added to the mail |
||
320 | * @return $this |
||
321 | * @since 1.0.0 |
||
322 | */ |
||
323 | public function addUniqueArgument($key, $value) |
||
324 | { |
||
325 | $this->uniqueArguments[$key] = $value; |
||
326 | return $this; |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * @param string $templateId template Id used. in this case, Subject / HtmlBody / TextBody are discarded |
||
331 | * @return $this |
||
332 | * @since 1.0.0 |
||
333 | */ |
||
334 | public function setTemplateId($templateId) |
||
335 | { |
||
336 | $this->templateId = $templateId; |
||
337 | return $this; |
||
338 | } |
||
339 | |||
340 | /** |
||
341 | * @return string|null current templateId |
||
342 | * @since 1.0.0 |
||
343 | */ |
||
344 | public function getTemplateId() |
||
345 | { |
||
346 | return $this->templateId; |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * @param array $templateModel model associated with the template |
||
351 | * @return $this |
||
352 | * @since 1.0.0 |
||
353 | */ |
||
354 | public function setTemplateModel($templateModel) |
||
355 | { |
||
356 | $this->templateModel = $templateModel; |
||
357 | return $this; |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * @return array current template model |
||
362 | * @since 1.0.0 |
||
363 | */ |
||
364 | public function getTemplateModel() |
||
365 | { |
||
366 | return !empty($this->templateModel) ? $this->templateModel : []; |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * @param array $header add custom header to the mail |
||
371 | * @since 1.0.0 |
||
372 | */ |
||
373 | public function addHeader($header) |
||
374 | { |
||
375 | $this->headers[] = $header; |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * @return array|null headers which should be added to the mail |
||
380 | * @since 1.0.0 |
||
381 | */ |
||
382 | public function getHeaders() |
||
383 | { |
||
384 | return empty($this->headers) ? [] : $this->headers; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * @return array|null list of attachments |
||
389 | * @since 1.0.0 |
||
390 | */ |
||
391 | public function getAttachments() |
||
392 | { |
||
393 | return empty($this->attachments) ? [] : $this->attachments; |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * @inheritdoc |
||
398 | */ |
||
399 | public function attach($fileName, array $options = []) |
||
400 | { |
||
401 | $attachment = [ |
||
402 | 'File' => $fileName |
||
403 | ]; |
||
404 | if (!empty($options['fileName'])) { |
||
405 | $attachment['Name'] = $options['fileName']; |
||
406 | } else { |
||
407 | $attachment['Name'] = pathinfo($fileName, PATHINFO_BASENAME); |
||
408 | } |
||
409 | $this->attachments[] = $attachment; |
||
410 | return $this; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * @return string temporary directory to store contents |
||
415 | * @since 1.0.0 |
||
416 | * @throws InvalidConfigException |
||
417 | */ |
||
418 | protected function getTempDir() |
||
419 | { |
||
420 | if ($this->attachmentsTmdDir === null) { |
||
421 | $uid = uniqid(); |
||
422 | $this->attachmentsTmdDir = Yii::getAlias('@app/runtime/'.$uid.'/'); |
||
0 ignored issues
–
show
|
|||
423 | $status = true; |
||
424 | if (file_exists($this->attachmentsTmdDir) === false) { |
||
425 | $status = mkdir($this->attachmentsTmdDir, 0755, true); |
||
426 | } |
||
427 | if ($status === false) { |
||
428 | throw new InvalidConfigException('Directory \''.$this->attachmentsTmdDir.'\' cannot be created'); |
||
429 | } |
||
430 | } |
||
431 | return $this->attachmentsTmdDir; |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * @inheritdoc |
||
436 | */ |
||
437 | public function attachContent($content, array $options = []) |
||
438 | { |
||
439 | if (!isset($options['fileName']) || empty($options['fileName'])) { |
||
440 | throw new InvalidArgumentException('Filename is missing'); |
||
441 | } |
||
442 | $filePath = $this->getTempDir().'/'.$options['fileName']; |
||
443 | if (file_put_contents($filePath, $content) === false) { |
||
444 | throw new InvalidConfigException('Cannot write file \''.$filePath.'\''); |
||
445 | } |
||
446 | $this->attach($filePath, $options); |
||
447 | return $this; |
||
448 | } |
||
449 | |||
450 | /** |
||
451 | * @inheritdoc |
||
452 | */ |
||
453 | public function embed($fileName, array $options = []) |
||
454 | { |
||
455 | $embed = [ |
||
456 | 'File' => $fileName |
||
457 | ]; |
||
458 | if (!empty($options['fileName'])) { |
||
459 | $embed['Name'] = $options['fileName']; |
||
460 | } else { |
||
461 | $embed['Name'] = pathinfo($fileName, PATHINFO_BASENAME); |
||
462 | } |
||
463 | $embed['ContentID'] = 'cid:' . uniqid(); |
||
464 | $this->attachments[] = $embed; |
||
465 | return $embed['ContentID']; |
||
466 | } |
||
467 | |||
468 | /** |
||
469 | * @inheritdoc |
||
470 | */ |
||
471 | public function embedContent($content, array $options = []) |
||
472 | { |
||
473 | if (isset($options['fileName']) === false || empty($options['fileName'])) { |
||
474 | throw new InvalidArgumentException('fileName is missing'); |
||
475 | } |
||
476 | $filePath = $this->getTempDir().'/'.$options['fileName']; |
||
477 | if (file_put_contents($filePath, $content) === false) { |
||
478 | throw new InvalidConfigException('Cannot write file \''.$filePath.'\''); |
||
479 | } |
||
480 | $cid = $this->embed($filePath, $options); |
||
481 | return $cid; |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * @inheritdoc |
||
486 | * @todo make real serialization to make message compliant with PostmarkAPI |
||
487 | */ |
||
488 | public function toString() |
||
489 | { |
||
490 | return serialize($this); |
||
491 | } |
||
492 | |||
493 | |||
494 | /** |
||
495 | * @param array|string $emailsData email can be defined as string. In this case no transformation is done |
||
496 | * or as an array ['[email protected]', '[email protected]' => 'Email 2'] |
||
497 | * @return string|null |
||
498 | * @since 1.0.0 |
||
499 | */ |
||
500 | public static function stringifyEmails($emailsData) |
||
501 | { |
||
502 | $emails = null; |
||
503 | if (empty($emailsData) === false) { |
||
504 | if (is_array($emailsData) === true) { |
||
505 | foreach ($emailsData as $key => $email) { |
||
506 | if (is_int($key) === true) { |
||
507 | $emails[] = $email; |
||
508 | } else { |
||
509 | if (preg_match('/[.,:]/', $email) > 0) { |
||
510 | $email = '"'. $email .'"'; |
||
511 | } |
||
512 | $emails[] = $email . ' ' . '<' . $key . '>'; |
||
513 | } |
||
514 | } |
||
515 | $emails = implode(', ', $emails); |
||
516 | } elseif (is_string($emailsData) === true) { |
||
517 | $emails = $emailsData; |
||
518 | } |
||
519 | } |
||
520 | return $emails; |
||
521 | } |
||
522 | |||
523 | public static function normalizeEmails($emailsData) |
||
524 | { |
||
525 | $emails = null; |
||
526 | if (empty($emailsData) === false) { |
||
527 | if (is_array($emailsData) === true) { |
||
528 | foreach ($emailsData as $key => $email) { |
||
529 | if (is_int($key) === true) { |
||
530 | $emails[$email] = null; |
||
531 | } else { |
||
532 | $emails[$key] = $email; |
||
533 | } |
||
534 | } |
||
535 | } elseif (is_string($emailsData) === true) { |
||
536 | $emails[$emailsData] = null; |
||
537 | } |
||
538 | } |
||
539 | return $emails; |
||
540 | } |
||
541 | |||
542 | public function send(MailerInterface $mailer = null) |
||
543 | { |
||
544 | $result = parent::send($mailer); |
||
545 | if ($this->attachmentsTmdDir !== null) { |
||
546 | //TODO: clean up tmpdir after ourselves |
||
547 | } |
||
548 | return $result; |
||
549 | } |
||
550 | |||
551 | |||
552 | } |
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
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.