Completed
Push — master ( 214aa8...a8ef68 )
by Loz
04:54
created

Mailer::sendMessage()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 21
ccs 13
cts 13
cp 1
rs 9.3142
cc 3
eloc 12
nc 4
nop 7
crap 3
1
<?php
2
3
namespace Kinglozzer\SilverStripeMailgunner;
4
5
use Mailer as SilverstripeMailer;
6
use Mailgun\Mailgun;
7
use Mailgun\Messages\MessageBuilder;
8
9
class Mailer extends SilverstripeMailer
10
{
11
    /**
12
     * @var string
13
     * @config
14
     */
15
    private static $api_domain = '';
16
17
    /**
18
     * @var string
19
     * @config
20
     */
21
    private static $api_endpoint = 'api.mailgun.net';
22
23
    /**
24
     * @var string
25
     * @config
26
     */
27
    private static $api_key = '';
28
29
    /**
30
     * @var boolean
31
     * @config
32
     */
33
    private static $api_ssl = true;
34
35
    /**
36
     * @var string
37
     * @config
38
     */
39
    private static $api_version = 'v3';
40
41
    /**
42
     * An array of temporary file handles opened to store attachments
43
     * @var array
44
     */
45
    protected $tempFileHandles = [];
46
47
    /**
48
     * @var Mailgun
49
     */
50
    protected $mailgunClient;
51
52
    /**
53
     * {@inheritdoc}
54
     */
55 10
    public function __construct()
56
    {
57 10
        $config = $this->config();
58 10
        $this->setMailgunClient(new Mailgun(
59 10
            $config->api_key,
60 10
            $config->api_endpoint,
61 10
            $config->api_version,
62 10
            $config->api_ssl
63 10
        ));
64 10
    }
65
66
    /**
67
     * @param Mailgun $client
68
     * @return self
69
     */
70 10
    public function setMailgunClient(Mailgun $client)
71
    {
72 10
        $this->mailgunClient = $client;
73 10
        return $this;
74
    }
75
76
    /**
77
     * @return Mailgun
78
     */
79 1
    public function getMailgunClient()
80
    {
81 1
        return $this->mailgunClient;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 1
    public function sendPlain($to, $from, $subject, $plainContent, $attachments = [], $headers = [])
88
    {
89 1
        $this->sendMessage($to, $from, $subject, $htmlContent = '', $plainContent, $attachments, $headers);
90 1
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95 1
    public function sendHTML($to, $from, $subject, $htmlContent, $attachments = [], $headers = [], $plainContent = '')
96
    {
97 1
        $this->sendMessage($to, $from, $subject, $htmlContent, $plainContent, $attachments, $headers);
98 1
    }
99
100
    /**
101
     * @param string $to
102
     * @param string $from
103
     * @param string $subject
104
     * @param string $content
105
     * @param string $plainContent
106
     * @param array $attachments
107
     * @param array $headers
108
     */
109 2
    protected function sendMessage($to, $from, $subject, $content, $plainContent, $attachments, $headers)
110
    {
111 2
        $client = $this->getMailgunClient();
112 2
        $messageBuilder = $client->MessageBuilder();
113
114 2
        $this->buildMessage($messageBuilder, $to, $from, $subject, $content, $plainContent, $headers);
115
116 2
        if (!empty($attachments)) {
117 2
            $attachments = $this->prepareAttachments($attachments);
118 2
        }
119
120
        try {
121 2
            $client->sendMessage($this->config()->api_domain, $messageBuilder->getMessage(), $attachments);
122 2
        } catch (\Exception $e) {
123
            // Close and remove any temp files created for attachments, then let the exception bubble up
124 1
            $this->closeTempFileHandles();
125 1
            throw $e;
126
        }
127
128 1
        $this->closeTempFileHandles();
129 1
    }
130
131
    /**
132
     * @param MessageBuilder $builder
133
     * @param string $to
134
     * @param string $from
135
     * @param string $subject
136
     * @param string $content
137
     * @param string $plainContent
138
     * @param array $headers
139
     */
140 2
    protected function buildMessage(MessageBuilder $builder, $to, $from, $subject, $content, $plainContent, $headers)
141
    {
142
        // Add base info
143 2
        $builder->addToRecipient($to);
144 2
        $builder->setFromAddress($from);
145 2
        $builder->setSubject($subject);
146
147
        // HTML content (if not empty)
148 2
        if ($content) {
149 2
            $builder->setHtmlBody($content);
150 2
        }
151
152
        // Plain text content (if not empty)
153 2
        if ($plainContent) {
154 2
            $builder->setTextBody($plainContent);
155 2
        }
156
157
        // Parse Cc & Bcc headers out if they're set
158 2
        if (isset($headers['Cc'])) {
159 2
            foreach (explode(', ', $headers['Cc']) as $ccAddress) {
160 2
                $builder->addCcRecipient($ccAddress);
161 2
            }
162 2
            unset($headers['Cc']);
163 2
        }
164
165 2
        if (isset($headers['Bcc'])) {
166 2
            foreach (explode(', ', $headers['Bcc']) as $bccAddress) {
167 2
                $builder->addBccRecipient($bccAddress);
168 2
            }
169 2
            unset($headers['Bcc']);
170 2
        }
171
172
        // Add remaining custom headers
173 2
        foreach ($headers as $name => $data) {
174 2
            $builder->addCustomHeader($name, $data);
175 2
        }
176 2
    }
177
178
    /**
179
     * Prepare attachments for sending. SilverStripe extracts the content and
180
     * passes that to the mailer, so to save encoding it we just write them all
181
     * to individual files and let Mailgun deal with the rest.
182
     * 
183
     * @todo Can we handle this better?
184
     * @param array $attachments
185
     * @return array
186
     */
187 2
    protected function prepareAttachments(array $attachments)
188
    {
189 2
        $prepared = [];
190
            
191 2
        foreach ($attachments as $attachment) {
192 2
            $tempFile = $this->writeToTempFile($attachment['contents']);
193
            
194 2
            $prepared[] = [
195 2
                'filePath' => $tempFile,
196 2
                'remoteName' => $attachment['filename']
197 2
            ];
198 2
        }
199
200 2
        return ['attachment' => $prepared];
201
    }
202
203
    /**
204
     * @param string $contents
205
     * @return string
206
     */
207 2
    protected function writeToTempFile($contents)
208
    {
209 2
        $tempFile = tempnam(sys_get_temp_dir(), 'SS_MG_TMP');
210 2
        $fileHandle = fopen($tempFile, 'r+');
211 2
        fwrite($fileHandle, $contents);
212
213 2
        $this->tempFileHandles[] = [
214 2
            'handle' => $fileHandle,
215
            'path' => $tempFile
216 2
        ];
217
218 2
        return $tempFile;
219
    }
220
221
    /**
222
     * @return void
223
     */
224 1
    protected function closeTempFileHandles()
225
    {
226 1
        foreach ($this->tempFileHandles as $key => $data) {
227 1
            fclose($data['handle']);
228 1
            unlink($data['path']);
229 1
            unset($this->tempFileHandles[$key]);
230 1
        }
231 1
    }
232
}
233