PostmarkTransport   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 6
dl 0
loc 255
ccs 90
cts 90
cp 1
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubject() 0 4 2
A getTag() 0 8 2
A __construct() 0 11 2
A send() 0 15 1
A getDisplayname() 0 8 2
A getMessageId() 0 7 1
A getBody() 0 4 2
A getAttachments() 0 16 1
A getContacts() 0 9 2
A getHtmlAndTextBody() 0 18 1
A getMimePart() 0 11 1
A payload() 0 27 1
1
<?php
2
3
namespace Coconuts\Mail;
4
5
use Swift_MimePart;
6
use Swift_Attachment;
7
use Swift_Mime_SimpleMessage;
8
use GuzzleHttp\ClientInterface;
9
use Illuminate\Mail\Transport\Transport;
10
use Coconuts\Mail\Exceptions\PostmarkException;
11
12
class PostmarkTransport extends Transport
13
{
14
    /**
15
     * Guzzle client instance.
16
     *
17
     * @var \GuzzleHttp\ClientInterface
18
     */
19
    protected $client;
20
21
    /**
22
     * The Postmark API key.
23
     *
24
     * @var string
25
     */
26
    protected $key;
27
28
    /**
29
     * The Postmark API end-point.
30
     *
31
     * @var string
32
     */
33
    protected $url = 'https://api.postmarkapp.com/email';
34
35
    /**
36
     * Create a new Postmark transport instance.
37
     *
38
     * @param \GuzzleHttp\ClientInterface $client
39
     * @param string $key
40
     *
41
     * @return void
42
     * @throws \Coconuts\Mail\Exceptions\PostmarkException
43
     */
44 30
    public function __construct(ClientInterface $client, $key)
45
    {
46 30
        if (empty(trim($key))) {
47 1
            throw new PostmarkException(
48 1
                'The Postmark secret is not set. Make sure that the `postmark.secret` config key is set.'
49
            );
50
        }
51
52 30
        $this->key = $key;
53 30
        $this->client = $client;
54 30
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59 1
    public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
60
    {
61 1
        $this->beforeSendPerformed($message);
62
63 1
        $response = $this->client->post($this->url, $this->payload($message));
64
65 1
        $message->getHeaders()->addTextHeader(
66 1
            'X-PM-Message-Id',
67 1
            $this->getMessageId($response)
68
        );
69
70 1
        $this->sendPerformed($message);
71
72 1
        return $this->numberOfRecipients($message);
73
    }
74
75
    /**
76
     * Get all attachments for the given message.
77
     *
78
     * @param \Swift_Mime_SimpleMessage $message
79
     *
80
     * @return array
81
     */
82 19
    protected function getAttachments(Swift_Mime_SimpleMessage $message)
83
    {
84 19
        return collect($message->getChildren())
85 19
            ->filter(function ($child) {
86 16
                return $child instanceof Swift_Attachment;
87 19
            })
88 19
            ->map(function ($child) {
89
                return [
90 15
                    'Name' => $child->getHeaders()->get('content-type')->getParameter('name'),
91 15
                    'Content' => base64_encode($child->getBody()),
92 15
                    'ContentType' => $child->getContentType(),
93
                ];
94 19
            })
95 19
            ->values()
96 19
            ->toArray();
97
    }
98
99
    /**
100
     * Format the display name.
101
     *
102
     * @param  string
103
     * @return string
104
     */
105 7
    protected function getDisplayname($value)
106
    {
107 7
        if (strpos($value, ',') !== false) {
108 1
            return '"'.$value.'"';
109
        }
110
111 6
        return $value;
112
    }
113
114
    /**
115
     * Format the contacts for the API request.
116
     *
117
     * @param string|array $contacts
118
     *
119
     * @return string
120
     */
121 19
    protected function getContacts($contacts)
122
    {
123 19
        return collect($contacts)
124 19
            ->map(function ($display, $address) {
125 14
                return $display ? $this->getDisplayname($display)." <{$address}>" : $address;
126 19
            })
127 19
            ->values()
128 19
            ->implode(',');
129
    }
130
131
    /**
132
     * Get the message ID from the response.
133
     *
134
     * @param \GuzzleHttp\Psr7\Response $response
135
     *
136
     * @return string
137
     */
138 1
    protected function getMessageId($response)
139
    {
140 1
        return object_get(
141 1
            json_decode($response->getBody()->getContents()),
142 1
            'MessageID'
143
        );
144
    }
145
146
    /**
147
     * Get the body for the given message.
148
     *
149
     * @param \Swift_Mime_SimpleMessage $message
150
     *
151
     * @return string
152
     */
153 20
    protected function getBody(Swift_Mime_SimpleMessage $message)
154
    {
155 20
        return $message->getBody() ?: '';
156
    }
157
158
    /**
159
     * Get the text and html fields for the given message.
160
     *
161
     * @param \Swift_Mime_SimpleMessage $message
162
     *
163
     * @return array
164
     */
165 18
    protected function getHtmlAndTextBody(Swift_Mime_SimpleMessage $message)
166
    {
167 18
        $key = collect([
168 18
            'text/html' => 'HtmlBody',
169
            'multipart/mixed' => 'HtmlBody',
170
            'multipart/related' => 'HtmlBody',
171
            'multipart/alternative' => 'HtmlBody',
172
        ])
173 18
        ->get($message->getContentType(), 'TextBody');
174
175 18
        return collect([
176 18
            $key => $this->getBody($message),
177 1
        ])->when($this->getMimePart($message, 'text/plain'), function ($collection, $value) {
0 ignored issues
show
Documentation introduced by
$this->getMimePart($message, 'text/plain') is of type object<Swift_MimePart>|null, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
178 1
            return $collection->put('TextBody', $value->getBody());
179
        })->when($this->getMimePart($message, 'text/html'), function ($collection, $value) {
180 13
            return $collection->put('HtmlBody', $value->getBody());
181 18
        })->all();
182
    }
183
184
    /**
185
     * Get a mime part from the given message.
186
     *
187
     * @param \Swift_Mime_SimpleMessage $message
188
     * @param string $mimeType
189
     *
190
     * @return \Swift_MimePart|null
191
     */
192 19
    protected function getMimePart(Swift_Mime_SimpleMessage $message, $mimeType)
193
    {
194 19
        return collect($message->getChildren())
195 19
            ->filter(function ($child) {
196 16
                return $child instanceof Swift_MimePart;
197 19
            })
198 19
            ->filter(function ($child) use ($mimeType) {
199 15
                return strpos($child->getContentType(), $mimeType) === 0;
200 19
            })
201 19
            ->first();
202
    }
203
204
    /**
205
     * Get the subject for the given message.
206
     *
207
     * @param \Swift_Mime_SimpleMessage $message
208
     *
209
     * @return string
210
     */
211 20
    protected function getSubject(Swift_Mime_SimpleMessage $message)
212
    {
213 20
        return $message->getSubject() ?: '';
214
    }
215
216
    /**
217
     * Get the tag for the given message.
218
     *
219
     * @param \Swift_Mime_SimpleMessage $message
220
     *
221
     * @return string
222
     */
223 21
    protected function getTag(Swift_Mime_SimpleMessage $message)
224
    {
225 21
        return optional(
226 21
            collect($message->getHeaders()->getAll('tag'))
227 21
            ->last()
228
        )
229 21
        ->getFieldBody() ?: '';
230
    }
231
232
    /**
233
     * Get the HTTP payload for sending the Postmark message.
234
     *
235
     * @param \Swift_Mime_SimpleMessage $message
236
     *
237
     * @return array
238
     */
239 18
    protected function payload(Swift_Mime_SimpleMessage $message)
240
    {
241 18
        return collect([
242
            'headers' => [
243 18
                'Accept' => 'application/json',
244 18
                'Content-Type' => 'application/json',
245 18
                'X-Postmark-Server-Token' => $this->key,
246
            ],
247
        ])
248 18
        ->merge([
249 18
            'json' => collect([
250 18
                'Cc' => $this->getContacts($message->getCc()),
251 18
                'Bcc' => $this->getContacts($message->getBcc()),
252 18
                'Tag' => $this->getTag($message),
253 18
                'Subject' => $this->getSubject($message),
254 18
                'ReplyTo' => $this->getContacts($message->getReplyTo()),
255 18
                'Attachments' => $this->getAttachments($message),
256
            ])
257 18
            ->reject(function ($item) {
258 18
                return empty($item);
259 18
            })
260 18
            ->put('From', $this->getContacts($message->getFrom()))
261 18
            ->put('To', $this->getContacts($message->getTo()))
262 18
            ->merge($this->getHtmlAndTextBody($message)),
263
        ])
264 18
        ->toArray();
265
    }
266
}
267