Passed
Push — master ( 7ee1dd...fe1f98 )
by Zaahid
03:17
created

Message   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 515
Duplicated Lines 0 %

Test Coverage

Coverage 95.17%

Importance

Changes 0
Metric Value
wmc 40
eloc 114
dl 0
loc 515
ccs 138
cts 145
cp 0.9517
rs 9.2
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A removeAllHtmlParts() 0 6 1
A addAttachmentPart() 0 5 1
A addAttachmentPartFromFile() 0 7 2
A setAsMultipartSigned() 0 6 1
A getSignaturePart() 0 6 1
A getSignedMessageAsString() 0 6 1
A setSignature() 0 4 1
A removeHtmlPart() 0 6 1
A getSignedMessageStream() 0 6 1
A removeAttachmentPart() 0 4 1
A removeAllTextParts() 0 6 1
A getAllAttachmentParts() 0 13 2
A getAttachmentPart() 0 7 2
A isMime() 0 5 2
A setTextPart() 0 6 1
A getHtmlPartCount() 0 4 1
A __construct() 0 18 1
A getTextPartCount() 0 4 1
A getHtmlStream() 0 7 2
A getTextPart() 0 5 1
A getTextResourceHandle() 0 7 2
A getHtmlContent() 0 7 2
A removeTextPart() 0 6 1
A getHtmlResourceHandle() 0 7 2
A setHtmlPart() 0 6 1
A getHtmlPart() 0 5 1
A from() 0 4 1
A getTextStream() 0 7 2
A getAttachmentCount() 0 3 1
A getTextContent() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Message often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Message, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\MailMimeParser;
8
9
use GuzzleHttp\Psr7;
10
use Psr\Http\Message\StreamInterface;
11
use ZBateson\MailMimeParser\Message\Helper\MessageHelperService;
12
use ZBateson\MailMimeParser\Message\Part\MimePart;
13
use ZBateson\MailMimeParser\Message\Part\PartBuilder;
14
use ZBateson\MailMimeParser\Message\Part\PartStreamFilterManager;
15
use ZBateson\MailMimeParser\Message\PartFilter;
16
use ZBateson\MailMimeParser\Message\PartFilterFactory;
17
use ZBateson\MailMimeParser\Stream\StreamFactory;
18
19
/**
20
 * A parsed mime message with optional mime parts depending on its type.
21
 *
22
 * A mime message may have any number of mime parts, and each part may have any
23
 * number of sub-parts, etc...
24
 *
25
 * @author Zaahid Bateson
26
 */
27
class Message extends MimePart
28
{
29
    /**
30
     * @var MessageHelperService helper class with various message manipulation
31
     *      routines.
32
     */
33
    protected $messageHelperService;
34
35
    /**
36
     * Constructor
37
     *
38
     * @param PartStreamFilterManager $partStreamFilterManager
39
     * @param StreamFactory $streamFactory
40
     * @param PartFilterFactory $partFilterFactory
41
     * @param PartBuilder $partBuilder
42
     * @param MessageHelperService $messageHelperService
43
     * @param StreamInterface $stream
44
     * @param StreamInterface $contentStream
45
     */
46 11
    public function __construct(
47
        PartStreamFilterManager $partStreamFilterManager,
48
        StreamFactory $streamFactory,
49
        PartFilterFactory $partFilterFactory,
50
        PartBuilder $partBuilder,
51
        MessageHelperService $messageHelperService,
52
        StreamInterface $stream = null,
53
        StreamInterface $contentStream = null
54
    ) {
55 11
        parent::__construct(
56 11
            $partStreamFilterManager,
57 11
            $streamFactory,
58 11
            $partFilterFactory,
59 11
            $partBuilder,
60 11
            $stream,
61 11
            $contentStream
62
        );
63 11
        $this->messageHelperService = $messageHelperService;
64 11
    }
65
66
    /**
67
     * Convenience method to parse a handle or string into a Message without
68
     * requiring including MailMimeParser, instantiating it, and calling parse.
69
     *
70
     * @param resource|string $handleOrString the resource handle to the input
71
     *        stream of the mime message, or a string containing a mime message
72
     */
73
    public static function from($handleOrString)
74
    {
75
        $mmp = new MailMimeParser();
76
        return $mmp->parse($handleOrString);
77
    }
78
79
    /**
80
     * Returns the text/plain part at the given index (or null if not found.)
81
     *
82
     * @param int $index
83
     * @return \ZBateson\MailMimeParser\Message\Part\MimePart
84
     */
85 1
    public function getTextPart($index = 0)
86
    {
87 1
        return $this->getPart(
88 1
            $index,
89 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/plain')
90
        );
91
    }
92
93
    /**
94
     * Returns the number of text/plain parts in this message.
95
     *
96
     * @return int
97
     */
98 1
    public function getTextPartCount()
99
    {
100 1
        return $this->getPartCount(
101 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/plain')
102
        );
103
    }
104
105
    /**
106
     * Returns the text/html part at the given index (or null if not found.)
107
     *
108
     * @param int $index
109
     * @return \ZBateson\MailMimeParser\Message\Part\MimePart
110
     */
111 1
    public function getHtmlPart($index = 0)
112
    {
113 1
        return $this->getPart(
114 1
            $index,
115 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/html')
116
        );
117
    }
118
119
    /**
120
     * Returns the number of text/html parts in this message.
121
     *
122
     * @return int
123
     */
124 1
    public function getHtmlPartCount()
125
    {
126 1
        return $this->getPartCount(
127 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/html')
128
        );
129
    }
130
131
    /**
132
     * Returns the attachment part at the given 0-based index, or null if none
133
     * is set.
134
     *
135
     * @param int $index
136
     * @return ZBateson\MailMimeParser\Message\Part\MessagePart
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\...essage\Part\MessagePart was not found. Did you mean ZBateson\MailMimeParser\Message\Part\MessagePart? If so, make sure to prefix the type with \.
Loading history...
137
     */
138 1
    public function getAttachmentPart($index)
139
    {
140 1
        $attachments = $this->getAllAttachmentParts();
141 1
        if (!isset($attachments[$index])) {
142 1
            return null;
143
        }
144 1
        return $attachments[$index];
145
    }
146
147
    /**
148
     * Returns all attachment parts.
149
     *
150
     * "Attachments" are any non-multipart, non-signature and any text or html
151
     * html part witha Content-Disposition set to  'attachment'.
152
     *
153
     * @return MessagePart[]
154
     */
155 1
    public function getAllAttachmentParts()
156
    {
157 1
        $parts = $this->getAllParts(
158 1
            $this->partFilterFactory->newFilterFromArray([
159 1
                'multipart' => PartFilter::FILTER_EXCLUDE
160
            ])
161
        );
162 1
        return array_values(array_filter(
163 1
            $parts,
164 1
            function ($part) {
165
                return !(
166 1
                    $part->isTextPart()
167 1
                    && $part->getContentDisposition() === 'inline'
168
                );
169 1
            }
170
        ));
171
    }
172
173
    /**
174
     * Returns the number of attachments available.
175
     *
176
     * @return int
177
     */
178 1
    public function getAttachmentCount()
179
    {
180 1
        return count($this->getAllAttachmentParts());
181
    }
182
183
    /**
184
     * Returns a Psr7 Stream for the 'inline' text/plain content at the passed
185
     * $index, or null if unavailable.
186
     *
187
     * @param int $index
188
     * @param string $charset
189
     * @return StreamInterface
190
     */
191 1
    public function getTextStream($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
192
    {
193 1
        $textPart = $this->getTextPart($index);
194 1
        if ($textPart !== null) {
195 1
            return $textPart->getContentStream($charset);
196
        }
197 1
        return null;
198
    }
199
200
    /**
201
     * Returns a resource handle for the 'inline' text/plain content at the
202
     * passed $index, or null if unavailable.
203
     *
204
     * @param int $index
205
     * @param string $charset
206
     * @return resource
207
     */
208 1
    public function getTextResourceHandle($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
209
    {
210 1
        $textPart = $this->getTextPart($index);
211 1
        if ($textPart !== null) {
212 1
            return $textPart->getContentResourceHandle($charset);
213
        }
214 1
        return null;
215
    }
216
217
    /**
218
     * Returns the content of the inline text/plain part at the given index.
219
     *
220
     * Reads the entire stream content into a string and returns it.  Returns
221
     * null if the message doesn't have an inline text part.
222
     *
223
     * @param int $index
224
     * @param string $charset
225
     * @return string
226
     */
227 1
    public function getTextContent($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
228
    {
229 1
        $part = $this->getTextPart($index);
230 1
        if ($part !== null) {
231 1
            return $part->getContent($charset);
232
        }
233 1
        return null;
234
    }
235
236
    /**
237
     * Returns a Psr7 Stream for the 'inline' text/html content at the passed
238
     * $index, or null if unavailable.
239
     *
240
     * @param int $index
241
     * @param string $charset
242
     * @return resource
243
     */
244 1
    public function getHtmlStream($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
245
    {
246 1
        $htmlPart = $this->getHtmlPart($index);
247 1
        if ($htmlPart !== null) {
248 1
            return $htmlPart->getContentStream($charset);
249
        }
250 1
        return null;
251
    }
252
253
    /**
254
     * Returns a resource handle for the 'inline' text/html content at the
255
     * passed $index, or null if unavailable.
256
     *
257
     * @param int $index
258
     * @param string $charset
259
     * @return resource
260
     */
261 1
    public function getHtmlResourceHandle($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
262
    {
263 1
        $htmlPart = $this->getHtmlPart($index);
264 1
        if ($htmlPart !== null) {
265 1
            return $htmlPart->getContentResourceHandle($charset);
266
        }
267 1
        return null;
268
    }
269
270
    /**
271
     * Returns the content of the inline text/html part at the given index.
272
     *
273
     * Reads the entire stream content into a string and returns it.  Returns
274
     * null if the message doesn't have an inline html part.
275
     *
276
     * @param int $index
277
     * @param string $charset
278
     * @return string
279
     */
280 1
    public function getHtmlContent($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
281
    {
282 1
        $part = $this->getHtmlPart($index);
283 1
        if ($part !== null) {
284 1
            return $part->getContent($charset);
285
        }
286 1
        return null;
287
    }
288
289
    /**
290
     * Returns true if either a Content-Type or Mime-Version header are defined
291
     * in this Message.
292
     *
293
     * @return bool
294
     */
295 3
    public function isMime()
296
    {
297 3
        $contentType = $this->getHeaderValue('Content-Type');
298 3
        $mimeVersion = $this->getHeaderValue('Mime-Version');
299 3
        return ($contentType !== null || $mimeVersion !== null);
300
    }
301
302
    /**
303
     * Sets the text/plain part of the message to the passed $stringOrHandle,
304
     * either creating a new part if one doesn't exist for text/plain, or
305
     * assigning the value of $stringOrHandle to an existing text/plain part.
306
     *
307
     * The optional $charset parameter is the charset for saving to.
308
     * $stringOrHandle is expected to be in UTF-8 regardless of the target
309
     * charset.
310
     *
311
     * @param string|resource|StreamInterface $resource
312
     * @param string $charset
313
     */
314 1
    public function setTextPart($resource, $charset = 'UTF-8')
315
    {
316 1
        $this->messageHelperService
317 1
            ->getMultipartHelper()
318 1
            ->setContentPartForMimeType(
319 1
                $this, 'text/plain', $resource, $charset
320
            );
321 1
    }
322
323
    /**
324
     * Sets the text/html part of the message to the passed $stringOrHandle,
325
     * either creating a new part if one doesn't exist for text/html, or
326
     * assigning the value of $stringOrHandle to an existing text/html part.
327
     *
328
     * The optional $charset parameter is the charset for saving to.
329
     * $stringOrHandle is expected to be in UTF-8 regardless of the target
330
     * charset.
331
     *
332
     * @param string|resource|StreamInterface $resource
333
     * @param string $charset
334
     */
335 1
    public function setHtmlPart($resource, $charset = 'UTF-8')
336
    {
337 1
        $this->messageHelperService
338 1
            ->getMultipartHelper()
339 1
            ->setContentPartForMimeType(
340 1
                $this, 'text/html', $resource, $charset
341
            );
342 1
    }
343
344
    /**
345
     * Removes the text/plain part of the message at the passed index if one
346
     * exists.  Returns true on success.
347
     *
348
     * @param int $index
349
     * @return bool true on success
350
     */
351 1
    public function removeTextPart($index = 0)
352
    {
353 1
        return $this->messageHelperService
354 1
            ->getMultipartHelper()
355 1
            ->removePartByMimeType(
356 1
                $this, 'text/plain', $index
357
            );
358
    }
359
360
    /**
361
     * Removes all text/plain inline parts in this message, optionally keeping
362
     * other inline parts as attachments on the main message (defaults to
363
     * keeping them).
364
     *
365
     * @param bool $keepOtherPartsAsAttachments
366
     * @return bool true on success
367
     */
368 1
    public function removeAllTextParts($keepOtherPartsAsAttachments = true)
369
    {
370 1
        return $this->messageHelperService
371 1
            ->getMultipartHelper()
372 1
            ->removeAllContentPartsByMimeType(
373 1
                $this, 'text/plain', $keepOtherPartsAsAttachments
374
            );
375
    }
376
377
    /**
378
     * Removes the html part of the message if one exists.  Returns true on
379
     * success.
380
     *
381
     * @param int $index
382
     * @return bool true on success
383
     */
384 1
    public function removeHtmlPart($index = 0)
385
    {
386 1
        return $this->messageHelperService
387 1
            ->getMultipartHelper()
388 1
            ->removePartByMimeType(
389 1
                $this, 'text/html', $index
390
            );
391
    }
392
393
    /**
394
     * Removes all text/html inline parts in this message, optionally keeping
395
     * other inline parts as attachments on the main message (defaults to
396
     * keeping them).
397
     *
398
     * @param bool $keepOtherPartsAsAttachments
399
     * @return bool true on success
400
     */
401 1
    public function removeAllHtmlParts($keepOtherPartsAsAttachments = true)
402
    {
403 1
        return $this->messageHelperService
404 1
            ->getMultipartHelper()
405 1
            ->removeAllContentPartsByMimeType(
406 1
                $this, 'text/html', $keepOtherPartsAsAttachments
407
            );
408
    }
409
410
    /**
411
     * Adds an attachment part for the passed raw data string or handle and
412
     * given parameters.
413
     *
414
     * @param string|resource|StreamInterface $resource
415
     * @param string $mimeType
416
     * @param string $filename
417
     * @param string $disposition
418
     */
419 1
    public function addAttachmentPart($resource, $mimeType, $filename = null, $disposition = 'attachment')
420
    {
421 1
        $this->messageHelperService
422 1
            ->getMultipartHelper()
423 1
            ->createAndAddPartForAttachment($this, $resource, $mimeType, $disposition, $filename);
424 1
    }
425
426
    /**
427
     * Adds an attachment part using the passed file.
428
     *
429
     * Essentially creates a file stream and uses it.
430
     *
431
     * @param string $filePath
432
     * @param string $mimeType
433
     * @param string $filename
434
     * @param string $disposition
435
     */
436 1
    public function addAttachmentPartFromFile($filePath, $mimeType, $filename = null, $disposition = 'attachment')
437
    {
438 1
        $handle = Psr7\stream_for(fopen($filePath, 'r'));
0 ignored issues
show
Bug introduced by
The function stream_for was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

438
        $handle = /** @scrutinizer ignore-call */ Psr7\stream_for(fopen($filePath, 'r'));
Loading history...
439 1
        if ($filename === null) {
440 1
            $filename = basename($filePath);
441
        }
442 1
        $this->addAttachmentPart($handle, $mimeType, $filename, $disposition);
443 1
    }
444
445
    /**
446
     * Removes the attachment with the given index
447
     *
448
     * @param int $index
449
     */
450 1
    public function removeAttachmentPart($index)
451
    {
452 1
        $part = $this->getAttachmentPart($index);
453 1
        $this->removePart($part);
454 1
    }
455
456
    /**
457
     * Returns a stream that can be used to read the content part of a signed
458
     * message, which can be used to sign an email or verify a signature.
459
     *
460
     * The method simply returns the stream for the first child.  No
461
     * verification of whether the message is in fact a signed message is
462
     * performed.
463
     *
464
     * Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
465
     * replace new lines.
466
     *
467
     * @return StreamInterface or null if the message doesn't have any children
468
     */
469 1
    public function getSignedMessageStream()
470
    {
471
        return $this
472 1
            ->messageHelperService
473 1
            ->getPrivacyHelper()
474 1
            ->getSignedMessageStream($this);
475
    }
476
477
    /**
478
     * Returns a string containing the entire body of a signed message for
479
     * verification or calculating a signature.
480
     *
481
     * Non-CRLF new lines are replaced to always be CRLF.
482
     *
483
     * @return string or null if the message doesn't have any children
484
     */
485 1
    public function getSignedMessageAsString()
486
    {
487
        return $this
488 1
            ->messageHelperService
489 1
            ->getPrivacyHelper()
490 1
            ->getSignedMessageAsString($this);
491
    }
492
493
    /**
494
     * Returns the signature part of a multipart/signed message or null.
495
     *
496
     * The signature part is determined to always be the 2nd child of a
497
     * multipart/signed message, the first being the 'body'.
498
     *
499
     * Using the 'protocol' parameter of the Content-Type header is unreliable
500
     * in some instances (for instance a difference of x-pgp-signature versus
501
     * pgp-signature).
502
     *
503
     * @return MimePart
504
     */
505
    public function getSignaturePart()
506
    {
507
        return $this
508
            ->messageHelperService
509
            ->getPrivacyHelper()
510
            ->getSignaturePart($this);
511
    }
512
513
    /**
514
     * Turns the message into a multipart/signed message, moving the actual
515
     * message into a child part, sets the content-type of the main message to
516
     * multipart/signed and adds an empty signature part as well.
517
     *
518
     * After calling setAsMultipartSigned, call getSignedMessageAsString to
519
     * return a
520
     *
521
     * @param string $micalg The Message Integrity Check algorithm being used
522
     * @param string $protocol The mime-type of the signature body
523
     */
524 1
    public function setAsMultipartSigned($micalg, $protocol)
525
    {
526
        $this
527 1
            ->messageHelperService
528 1
            ->getPrivacyHelper()
529 1
            ->setMessageAsMultipartSigned($this, $micalg, $protocol);
530 1
    }
531
532
    /**
533
     * Sets the signature body of the message to the passed $body for a
534
     * multipart/signed message.
535
     *
536
     * @param string $body
537
     */
538 1
    public function setSignature($body)
539
    {
540 1
        $this->messageHelperService->getPrivacyHelper()
541 1
            ->setSignature($this, $body);
542 1
    }
543
}
544