Completed
Pull Request — master (#33)
by
unknown
09:04 queued 06:09
created

Composer::getType()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 29
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 29
ccs 0
cts 0
cp 0
rs 5.3846
cc 8
eloc 26
nc 8
nop 1
crap 72
1
<?php
2
/**
3
 * MtMail - e-mail module for Zend Framework 2
4
 *
5
 * @link      http://github.com/mtymek/MtMail
6
 * @copyright Copyright (c) 2013-2014 Mateusz Tymek
7
 * @license   BSD 2-Clause
8
 */
9
10
namespace MtMail\Service;
11
12
use MtMail\Event\ComposerEvent;
13
use MtMail\Exception\InvalidArgumentException;
14
use MtMail\Renderer\RendererInterface;
15
use MtMail\Template\HtmlTemplateInterface;
16
use MtMail\Template\TemplateInterface;
17
use MtMail\Template\TextTemplateInterface;
18
use Zend\EventManager\EventManager;
19
use Zend\EventManager\EventManagerAwareInterface;
20
use Zend\EventManager\EventManagerInterface;
21
use Zend\Mail\Message;
22
use Zend\View\Model\ModelInterface;
23
use Zend\Mime\Message as MimeMessage;
24
use Zend\Mime\Part as MimePart;
25
use Zend\View\Model\ViewModel;
26
27
class Composer implements EventManagerAwareInterface
28
{
29
    /**
30
     * @var RendererInterface
31
     */
32
    protected $renderer;
33
34
    /**
35
     * @var EventManagerInterface
36
     */
37
    protected $eventManager;
38
39
    /**
40
     * Class constructor
41
     *
42
     * @param RendererInterface $renderer
43
     */
44 10
    public function __construct(RendererInterface $renderer)
45
    {
46 10
        $this->renderer = $renderer;
47 10
    }
48
49
    /**
50
     * Inject an EventManager instance
51
     *
52
     * @param  EventManagerInterface $eventManager
53
     * @return self
54
     */
55 3
    public function setEventManager(EventManagerInterface $eventManager)
56
    {
57 3
        $this->eventManager = $eventManager;
58
59 3
        return $this;
60
    }
61
62
    /**
63
     * Retrieve the event manager
64
     *
65
     * Lazy-loads an EventManager instance if none registered.
66
     *
67
     * @return EventManagerInterface
68
     */
69 8
    public function getEventManager()
70
    {
71 8
        if (null === $this->eventManager) {
72 6
            $this->eventManager = new EventManager();
73 6
        }
74
75 8
        return $this->eventManager;
76
    }
77
78
    /**
79
     * @param  \MtMail\Renderer\RendererInterface $renderer
80
     * @return self
81
     */
82 1
    public function setRenderer($renderer)
83
    {
84 1
        $this->renderer = $renderer;
85
86 1
        return $this;
87
    }
88
89
    /**
90
     * @return \MtMail\Renderer\RendererInterface
91
     */
92 3
    public function getRenderer()
93
    {
94 3
        return $this->renderer;
95
    }
96
97
    /**
98
     * Create and return event used by compose and send methods
99
     *
100
     * @return ComposerEvent
101
     */
102 5
    protected function getEvent()
103
    {
104 5
        $event = new ComposerEvent();
105 5
        $event->setTarget($this);
106
107 5
        return $event;
108
    }
109
110
    /**
111
     * Build e-mail message
112
     *
113
     * @param  TemplateInterface        $template
114
     * @param  array                    $headers
115
     * @param  ModelInterface           $viewModel
116
     * @throws InvalidArgumentException if template is not string nor TemplateInterface
117
     * @return Message
118
     */
119 5
    public function compose(array $headers, TemplateInterface $template, ModelInterface $viewModel = null)
120
    {
121 5
        if (null == $viewModel) {
122
            $viewModel = new ViewModel();
123
        }
124
125 5
        $event = $this->getEvent();
126 5
        $event->setTemplate($template);
127 5
        $em = $this->getEventManager();
128
129
        // 1. Trigger pre event
130 5
        $event->setName(ComposerEvent::EVENT_COMPOSE_PRE);
131 5
        $em->triggerEvent($event);
132
133
        // 2. inject headers
134 5
        $event->setName(ComposerEvent::EVENT_HEADERS_PRE);
135 5
        $em->triggerEvent($event);
136 5
        foreach ($headers as $name => $value) {
137 1
            switch ($name) {
138 5
                case "to":
139 5
                    $value = explode(",", $value);
140 5
                    if (!is_array($value)) {
141
                        $tmp = $value;
142
                        $value = [];
143 5
                        $value[] = $tmp;
144
                    }
145
                    foreach ($value as $item) {
146 5
                        $event->getMessage()->addTo($item);
147 2
                    }
148 2
                    break;
149 2
                case "from":
150
                    $value = explode(",", $value);
151 2
                    if (!is_array($value)) {
152 2
                        $tmp = $value;
153
                        $value = [];
154 2
                        $value[] = $tmp;
155 2
                    }
156 2
                    foreach ($value as $item) {
157 2
                        $event->getMessage()->addFrom($item);
158
                    }
159 2
                    break;
160 2
                case "bcc" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
161 2
                    $value = explode(",", $value);
162
                    if (!is_array($value)) {
163
                        $tmp = $value;
164 5
                        $value = [];
165 3
                        $value[] = $tmp;
166 3
                    }
167 3
                    foreach ($value as $item) {
168
                        $event->getMessage()->addBcc($item);
169 3
                    }
170 3
                    break;
171
                case "cc" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
172 3
                    $value = explode(",", $value);
173 3
                    if (!is_array($value)) {
174 3
                        $tmp = $value;
175 3
                        $value = [];
176
                        $value[] = $tmp;
177 3
                    }
178 3
                    foreach ($value as $item) {
179 3
                        $event->getMessage()->addCc($item);
180
                    }
181
                    break;
182 5
                default:
183 5
                    $event->getMessage()->getHeaders()->addHeaderLine($name, $value);
184
            }
185
        }
186 5
        $event->setName(ComposerEvent::EVENT_HEADERS_POST);
187
        $em->triggerEvent($event);
188
189
        // prepare placeholder for message body
190
        $body = new MimeMessage();
191 5
192 5
        // 3. Render plain text template
193
        if ($template instanceof TextTemplateInterface) {
194 5
            $textViewModel = clone $viewModel;
195
            $textViewModel->setTemplate($template->getTextTemplateName());
196
            $event->setViewModel($textViewModel);
197
198
            $event->setName(ComposerEvent::EVENT_TEXT_BODY_PRE);
199
            $em->triggerEvent($event);
200
201
            $text = new MimePart($this->renderer->render($event->getViewModel()));
202
            $text->type = 'text/plain';
203
            $text->charset = $event->getMessage()->getHeaders()->getEncoding();
204
            $body->addPart($text);
205
206
            $event->setName(ComposerEvent::EVENT_TEXT_BODY_POST);
207
            $em->triggerEvent($event);
208
        }
209
210
        // 4. Render HTML template
211
        if ($template instanceof HtmlTemplateInterface) {
212
            $htmlViewModel = clone $viewModel;
213
            $htmlViewModel->setTemplate($template->getHtmlTemplateName());
214
            $event->setViewModel($htmlViewModel);
215
216
            $event->setName(ComposerEvent::EVENT_HTML_BODY_PRE);
217
            $em->triggerEvent($event);
218
219
            $html = new MimePart($this->renderer->render($event->getViewModel()));
220
            $html->type = 'text/html';
221
            $html->charset = $event->getMessage()->getHeaders()->getEncoding();
222
            $body->addPart($html);
223
224
            $event->setName(ComposerEvent::EVENT_HTML_BODY_POST);
225
            $em->triggerEvent($event);
226
        }
227
228
        // 5. inject body into message
229
        $event->setBody($body);
230
        $event->getMessage()->setBody($body);
231
232
        // 6. set multipart/alternative when both versions are available
233
        if ($template instanceof TextTemplateInterface && $template instanceof HtmlTemplateInterface) {
234
            $event->getMessage()->getHeaders()->get('content-type')->setType('multipart/alternative')
235
                ->addParameter('boundary', $body->getMime()->boundary());
236
        }
237
238
        $event->setName(ComposerEvent::EVENT_COMPOSE_POST);
239
        $em->triggerEvent($event);
240
241
        return $event->getMessage();
242
    }
243
    
244
245
    public function attachments(Message $message, array $attachments)
246
    {
247
        if (sizeof($attachments) > 0) {
248
            $type = $message->getHeaders()->get('content-type')->getType();
249
            if ($type != 'multipart/related') {
250
                $parts = $message->getBody()->getParts();
251
                $htmlPart = null;
252
                $textPart = null;
253
254
                // locate HTML body
255
                foreach ($parts as $part) {
256
                    foreach ($part->getHeadersArray() as $header) {
257
                        if ($header[0] == 'Content-Type' && strpos($header[1], 'text/html') === 0) {
258
                            $htmlPart = $part;
259
                        } elseif ($header[0] == 'Content-Type' && strpos($header[1], 'text/plain') === 0) {
260
                            $textPart = $part;
261
                        }
262
                    }
263
                }
264
265
                if (!empty($textPart) && !empty($htmlPart)) {
266
                    $content = new MimeMessage();
267
                    $content->addPart($textPart);
268
                    $content->addPart($htmlPart);
269
                    $contentPart = new MimePart($content->generateMessage());
270
                    $contentPart->type = "multipart/alternative;\n boundary=\"" .
271
                        $content->getMime()->boundary() . '"';
272
                    $message->getBody()->setParts([$contentPart]);
273
                } else {
274
                    if (empty($textPart)) {
275
                        $message->getBody()->setParts([$htmlPart]);
276
                    } else {
277
                        $message->getBody()->setParts([$textPart]);
278
                    }
279
                }
280
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
281
            }
282
283
            foreach ($attachments as $attachment) {
284
                if (is_readable($attachment)) {
285
                    $pathParts          = pathinfo($attachment);
286
                    $at = new MimePart(file_get_contents($attachment));
287
                    $at->type           = $this->getType($pathParts['extension']);
288
                    $at->filename       = $pathParts['filename'];
289
                    $at->disposition    = Mime::DISPOSITION_ATTACHMENT;
290
291
                    $message->getBody()->addPart($at);
292
                }
293
            }
294
295
            // force multipart/alternative content type
296
            if ($type != 'multipart/related') {
297
                $message->getHeaders()->get('content-type')->setType('multipart/related')
298
                    ->addParameter('boundary', $event->getBody()->getMime()->boundary());
0 ignored issues
show
Bug introduced by
The variable $event does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
299
            }
300
        }
301
        return $message;
302
    }
303
304
    private function getType($ext) {
305
        switch (strtolower($ext)) {
306
            case "pdf":
307
                $type = 'application/pdf';
308
                break;
309
            case "doc":
310
                $type = "application/msword";
311
                break;
312
            case "docx":
313
                $type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
314
                break;
315
            case "odt":
316
                $type =  "application/vnd.oasis.opendocument.text";
317
                break;
318
            case "gzip":
319
                $type =  'application/gzip';
320
                break;
321
            case "txt":
322
                $type= 'application/text';
323
                break;
324
            case "zip":
325
                $type = 'application/zip';
326
                break;
327
            default:
328
                $type = Mime::TYPE_OCTETSTREAM;
329
        }
330
331
        return $type;
332
    }
333
}
334