1
|
|
|
<?php |
2
|
|
|
namespace Sichikawa\LaravelSendgridDriver\Transport; |
3
|
|
|
|
4
|
|
|
use GuzzleHttp\ClientInterface; |
5
|
|
|
use Illuminate\Mail\Transport\Transport; |
6
|
|
|
use Swift_Attachment; |
7
|
|
|
use Swift_Image; |
8
|
|
|
use Swift_Mime_Message; |
9
|
|
|
use Swift_MimePart; |
10
|
|
|
|
11
|
|
|
class SendgridV3Transport extends Transport |
12
|
|
|
{ |
13
|
|
|
const MAXIMUM_FILE_SIZE = 7340032; |
14
|
|
|
const SMTP_API_NAME = 'sendgrid/x-smtpapi'; |
15
|
|
|
const BASE_URL = 'https://api.sendgrid.com/v3/mail/send'; |
16
|
|
|
|
17
|
|
|
private $client; |
18
|
|
|
private $options; |
19
|
|
|
private $pretend; |
20
|
|
|
|
21
|
|
|
public function __construct(ClientInterface $client, $api_key, $pretend = false) |
22
|
|
|
{ |
23
|
|
|
$this->client = $client; |
24
|
|
|
$this->options = [ |
25
|
|
|
'headers' => [ |
26
|
|
|
'Authorization' => 'Bearer ' . $api_key, |
27
|
|
|
'Content-Type' => 'application/json', |
28
|
|
|
], |
29
|
|
|
]; |
30
|
|
|
$this->pretend = $pretend; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* {@inheritdoc} |
35
|
|
|
*/ |
36
|
|
|
public function send(Swift_Mime_Message $message, &$failedRecipients = null) |
37
|
|
|
{ |
38
|
|
|
$payload = $this->options; |
39
|
|
|
|
40
|
|
|
$data = [ |
41
|
|
|
'personalizations' => $this->getPersonalizations($message), |
42
|
|
|
'from' => $this->getFrom($message), |
43
|
|
|
'reply_to' => $this->getReplyTo($message), |
44
|
|
|
'subject' => $message->getSubject(), |
45
|
|
|
'content' => $this->getContents($message), |
46
|
|
|
]; |
47
|
|
|
|
48
|
|
|
$attachments = $this->getAttachments($message); |
49
|
|
|
if (count($attachments) > 0) { |
50
|
|
|
$data['attachments'] = $attachments; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
$data = $this->setParameters($message, $data); |
54
|
|
|
|
55
|
|
|
$payload['json'] = $data; |
56
|
|
|
|
57
|
|
|
if ($this->pretend) { |
58
|
|
|
return [self::BASE_URL, $payload]; |
|
|
|
|
59
|
|
|
} |
60
|
|
|
return $this->client->post('https://api.sendgrid.com/v3/mail/send', $payload); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @param Swift_Mime_Message $message |
65
|
|
|
* @return array |
66
|
|
|
*/ |
67
|
|
|
private function getPersonalizations(Swift_Mime_Message $message) |
68
|
|
|
{ |
69
|
|
|
$setter = function (array $addresses) { |
70
|
|
|
$recipients = []; |
71
|
|
|
foreach ($addresses as $email => $name) { |
72
|
|
|
$address = []; |
73
|
|
|
$address['email'] = $email; |
74
|
|
|
if ($name) { |
75
|
|
|
$address['name'] = $name; |
76
|
|
|
} |
77
|
|
|
$recipients[] = $address; |
78
|
|
|
} |
79
|
|
|
return $recipients; |
80
|
|
|
}; |
81
|
|
|
|
82
|
|
|
$personalizatioin['to'] = $setter($message->getTo()); |
|
|
|
|
83
|
|
|
|
84
|
|
|
if ($cc = $message->getCc()) { |
85
|
|
|
$personalizatioin['cc'] = $setter($cc); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
if ($bcc = $message->getBcc()) { |
89
|
|
|
$personalizatioin['bcc'] = $setter($bcc); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
return [$personalizatioin]; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Get From Addresses. |
97
|
|
|
* |
98
|
|
|
* @param Swift_Mime_Message $message |
99
|
|
|
* @return array |
100
|
|
|
*/ |
101
|
|
|
private function getFrom(Swift_Mime_Message $message) |
102
|
|
|
{ |
103
|
|
|
if ($message->getFrom()) { |
104
|
|
|
foreach ($message->getFrom() as $email => $name) { |
105
|
|
|
return ['email' => $email, 'name' => $name]; |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
return []; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Get ReplyTo Addresses. |
113
|
|
|
* |
114
|
|
|
* @param Swift_Mime_Message $message |
115
|
|
|
* @return array |
116
|
|
|
*/ |
117
|
|
|
private function getReplyTo(Swift_Mime_Message $message) |
118
|
|
|
{ |
119
|
|
|
if ($message->getReplyTo()) { |
120
|
|
|
foreach ($message->getReplyTo() as $email => $name) { |
121
|
|
|
return ['email' => $email, 'name' => $name]; |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
return []; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Get contents. |
129
|
|
|
* |
130
|
|
|
* @param Swift_Mime_Message $message |
131
|
|
|
* @return array |
132
|
|
|
*/ |
133
|
|
|
private function getContents(Swift_Mime_Message $message) |
134
|
|
|
{ |
135
|
|
|
$content = []; |
136
|
|
|
foreach ($message->getChildren() as $attachment) { |
137
|
|
|
if ($attachment instanceof Swift_MimePart) { |
138
|
|
|
$content[] = [ |
139
|
|
|
'type' => 'text/plain', |
140
|
|
|
'value' => $attachment->getBody(), |
141
|
|
|
]; |
142
|
|
|
break; |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
if (empty($content) || strpos($message->getContentType(), 'multipart') !== false) { |
147
|
|
|
$content[] = [ |
148
|
|
|
'type' => 'text/html', |
149
|
|
|
'value' => $message->getBody(), |
150
|
|
|
]; |
151
|
|
|
} |
152
|
|
|
return $content; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* @param Swift_Mime_Message $message |
157
|
|
|
* @return array |
158
|
|
|
*/ |
159
|
|
|
private function getAttachments(Swift_Mime_Message $message) |
160
|
|
|
{ |
161
|
|
|
$attachments = []; |
162
|
|
|
foreach ($message->getChildren() as $attachment) { |
163
|
|
|
if (!$attachment instanceof Swift_Attachment || !strlen($attachment->getBody()) > self::MAXIMUM_FILE_SIZE) { |
164
|
|
|
continue; |
165
|
|
|
} |
166
|
|
|
$attachments[] = [ |
167
|
|
|
'content' => base64_encode($attachment->getBody()), |
168
|
|
|
'filename' => $attachment->getFilename(), |
169
|
|
|
'type' => $attachment->getContentType(), |
170
|
|
|
'disposition' => $attachment->getDisposition(), |
171
|
|
|
'content_id' => $attachment->getId(), |
172
|
|
|
]; |
173
|
|
|
} |
174
|
|
|
return $attachments; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Set Request Body Parameters |
179
|
|
|
* |
180
|
|
|
* @param Swift_Mime_Message $message |
181
|
|
|
* @param array $data |
182
|
|
|
* @return array |
183
|
|
|
*/ |
184
|
|
|
protected function setParameters(Swift_Mime_Message $message, $data) |
185
|
|
|
{ |
186
|
|
|
$smtp_api = []; |
187
|
|
View Code Duplication |
foreach ($message->getChildren() as $attachment) { |
|
|
|
|
188
|
|
|
if (!$attachment instanceof Swift_Image |
189
|
|
|
|| !in_array(self::SMTP_API_NAME, [$attachment->getFilename(), $attachment->getContentType()]) |
190
|
|
|
) { |
191
|
|
|
continue; |
192
|
|
|
} |
193
|
|
|
$smtp_api = $attachment->getBody(); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
if (!is_array($smtp_api)) { |
197
|
|
|
return $data; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
foreach ($smtp_api as $key => $val) { |
201
|
|
|
if ($key === 'personalizations') { |
202
|
|
|
$this->setPersonalizations($data, $val); |
203
|
|
|
continue; |
204
|
|
|
} |
205
|
|
|
array_set($data, $key, $val); |
206
|
|
|
} |
207
|
|
|
return $data; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
private function setPersonalizations(&$data, $personalizations) |
211
|
|
|
{ |
212
|
|
|
foreach ($personalizations as $params) { |
213
|
|
|
foreach ($params as $key => $val) { |
214
|
|
|
array_set($data, 'personalizations.0.' . $key, $val); |
215
|
|
|
} |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.