Passed
Push — master ( a0eabd...66d82e )
by Zaahid
03:20
created

Message   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 533
Duplicated Lines 0 %

Test Coverage

Coverage 95.33%

Importance

Changes 0
Metric Value
eloc 118
dl 0
loc 533
ccs 143
cts 150
cp 0.9533
rs 9.0399
c 0
b 0
f 0
wmc 42

31 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 1
A from() 0 4 1
A removeAllTextParts() 0 6 1
A getAllAttachmentParts() 0 13 2
A removeAllHtmlParts() 0 6 1
A getAttachmentPart() 0 7 2
A isMime() 0 5 2
A addAttachmentPart() 0 5 1
A setTextPart() 0 6 1
A getHtmlPartCount() 0 4 1
A addAttachmentPartFromFile() 0 7 2
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 getMessageId() 0 7 2
A setAsMultipartSigned() 0 6 1
A getHtmlResourceHandle() 0 7 2
A setHtmlPart() 0 6 1
A getSignaturePart() 0 6 1
A getSignedMessageAsString() 0 6 1
A getHtmlPart() 0 5 1
A setSignature() 0 4 1
A removeHtmlPart() 0 6 1
A getSignedMessageStream() 0 6 1
A getTextStream() 0 7 2
A getAttachmentCount() 0 3 1
A removeAttachmentPart() 0 4 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 12
    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 12
        parent::__construct(
56 12
            $partStreamFilterManager,
57 12
            $streamFactory,
58 12
            $partFilterFactory,
59 12
            $partBuilder,
60 12
            $stream,
61 12
            $contentStream
62
        );
63 12
        $this->messageHelperService = $messageHelperService;
64 12
    }
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 Message ID of the message.
81
     *
82
     * Parses the value of the Message-ID header, stripping out the surrounding
83
     * '<' and '>' characters, and returning just the ID if set... or null if
84
     * not set or incorrectly formatted.
85
     *
86
     * @return string|null
87
     */
88 1
    public function getMessageId()
89
    {
90 1
        $header = $this->getHeader('Message-ID');
91 1
        if ($header !== null) {
92 1
            return $header->getId();
0 ignored issues
show
Bug introduced by
The method getId() does not exist on ZBateson\MailMimeParser\Header\AbstractHeader. It seems like you code against a sub-type of ZBateson\MailMimeParser\Header\AbstractHeader such as ZBateson\MailMimeParser\Header\IdHeader. ( Ignorable by Annotation )

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

92
            return $header->/** @scrutinizer ignore-call */ getId();
Loading history...
93
        }
94 1
        return null;
95
    }
96
97
    /**
98
     * Returns the text/plain part at the given index (or null if not found.)
99
     *
100
     * @param int $index
101
     * @return \ZBateson\MailMimeParser\Message\Part\MimePart
102
     */
103 1
    public function getTextPart($index = 0)
104
    {
105 1
        return $this->getPart(
106 1
            $index,
107 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/plain')
108
        );
109
    }
110
111
    /**
112
     * Returns the number of text/plain parts in this message.
113
     *
114
     * @return int
115
     */
116 1
    public function getTextPartCount()
117
    {
118 1
        return $this->getPartCount(
119 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/plain')
120
        );
121
    }
122
123
    /**
124
     * Returns the text/html part at the given index (or null if not found.)
125
     *
126
     * @param int $index
127
     * @return \ZBateson\MailMimeParser\Message\Part\MimePart
128
     */
129 1
    public function getHtmlPart($index = 0)
130
    {
131 1
        return $this->getPart(
132 1
            $index,
133 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/html')
134
        );
135
    }
136
137
    /**
138
     * Returns the number of text/html parts in this message.
139
     *
140
     * @return int
141
     */
142 1
    public function getHtmlPartCount()
143
    {
144 1
        return $this->getPartCount(
145 1
            $this->partFilterFactory->newFilterFromInlineContentType('text/html')
146
        );
147
    }
148
149
    /**
150
     * Returns the attachment part at the given 0-based index, or null if none
151
     * is set.
152
     *
153
     * @param int $index
154
     * @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...
155
     */
156 1
    public function getAttachmentPart($index)
157
    {
158 1
        $attachments = $this->getAllAttachmentParts();
159 1
        if (!isset($attachments[$index])) {
160 1
            return null;
161
        }
162 1
        return $attachments[$index];
163
    }
164
165
    /**
166
     * Returns all attachment parts.
167
     *
168
     * "Attachments" are any non-multipart, non-signature and any text or html
169
     * html part witha Content-Disposition set to  'attachment'.
170
     *
171
     * @return MessagePart[]
172
     */
173 1
    public function getAllAttachmentParts()
174
    {
175 1
        $parts = $this->getAllParts(
176 1
            $this->partFilterFactory->newFilterFromArray([
177 1
                'multipart' => PartFilter::FILTER_EXCLUDE
178
            ])
179
        );
180 1
        return array_values(array_filter(
181 1
            $parts,
182 1
            function ($part) {
183
                return !(
184 1
                    $part->isTextPart()
185 1
                    && $part->getContentDisposition() === 'inline'
186
                );
187 1
            }
188
        ));
189
    }
190
191
    /**
192
     * Returns the number of attachments available.
193
     *
194
     * @return int
195
     */
196 1
    public function getAttachmentCount()
197
    {
198 1
        return count($this->getAllAttachmentParts());
199
    }
200
201
    /**
202
     * Returns a Psr7 Stream for the 'inline' text/plain content at the passed
203
     * $index, or null if unavailable.
204
     *
205
     * @param int $index
206
     * @param string $charset
207
     * @return StreamInterface
208
     */
209 1
    public function getTextStream($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
210
    {
211 1
        $textPart = $this->getTextPart($index);
212 1
        if ($textPart !== null) {
213 1
            return $textPart->getContentStream($charset);
214
        }
215 1
        return null;
216
    }
217
218
    /**
219
     * Returns a resource handle for the 'inline' text/plain content at the
220
     * passed $index, or null if unavailable.
221
     *
222
     * @param int $index
223
     * @param string $charset
224
     * @return resource
225
     */
226 1
    public function getTextResourceHandle($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
227
    {
228 1
        $textPart = $this->getTextPart($index);
229 1
        if ($textPart !== null) {
230 1
            return $textPart->getContentResourceHandle($charset);
231
        }
232 1
        return null;
233
    }
234
235
    /**
236
     * Returns the content of the inline text/plain part at the given index.
237
     *
238
     * Reads the entire stream content into a string and returns it.  Returns
239
     * null if the message doesn't have an inline text part.
240
     *
241
     * @param int $index
242
     * @param string $charset
243
     * @return string
244
     */
245 1
    public function getTextContent($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
246
    {
247 1
        $part = $this->getTextPart($index);
248 1
        if ($part !== null) {
249 1
            return $part->getContent($charset);
250
        }
251 1
        return null;
252
    }
253
254
    /**
255
     * Returns a Psr7 Stream for the 'inline' text/html content at the passed
256
     * $index, or null if unavailable.
257
     *
258
     * @param int $index
259
     * @param string $charset
260
     * @return resource
261
     */
262 1
    public function getHtmlStream($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
263
    {
264 1
        $htmlPart = $this->getHtmlPart($index);
265 1
        if ($htmlPart !== null) {
266 1
            return $htmlPart->getContentStream($charset);
267
        }
268 1
        return null;
269
    }
270
271
    /**
272
     * Returns a resource handle for the 'inline' text/html content at the
273
     * passed $index, or null if unavailable.
274
     *
275
     * @param int $index
276
     * @param string $charset
277
     * @return resource
278
     */
279 1
    public function getHtmlResourceHandle($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
280
    {
281 1
        $htmlPart = $this->getHtmlPart($index);
282 1
        if ($htmlPart !== null) {
283 1
            return $htmlPart->getContentResourceHandle($charset);
284
        }
285 1
        return null;
286
    }
287
288
    /**
289
     * Returns the content of the inline text/html part at the given index.
290
     *
291
     * Reads the entire stream content into a string and returns it.  Returns
292
     * null if the message doesn't have an inline html part.
293
     *
294
     * @param int $index
295
     * @param string $charset
296
     * @return string
297
     */
298 1
    public function getHtmlContent($index = 0, $charset = MailMimeParser::DEFAULT_CHARSET)
299
    {
300 1
        $part = $this->getHtmlPart($index);
301 1
        if ($part !== null) {
302 1
            return $part->getContent($charset);
303
        }
304 1
        return null;
305
    }
306
307
    /**
308
     * Returns true if either a Content-Type or Mime-Version header are defined
309
     * in this Message.
310
     *
311
     * @return bool
312
     */
313 3
    public function isMime()
314
    {
315 3
        $contentType = $this->getHeaderValue('Content-Type');
316 3
        $mimeVersion = $this->getHeaderValue('Mime-Version');
317 3
        return ($contentType !== null || $mimeVersion !== null);
318
    }
319
320
    /**
321
     * Sets the text/plain part of the message to the passed $stringOrHandle,
322
     * either creating a new part if one doesn't exist for text/plain, or
323
     * assigning the value of $stringOrHandle to an existing text/plain part.
324
     *
325
     * The optional $charset parameter is the charset for saving to.
326
     * $stringOrHandle is expected to be in UTF-8 regardless of the target
327
     * charset.
328
     *
329
     * @param string|resource|StreamInterface $resource
330
     * @param string $charset
331
     */
332 1
    public function setTextPart($resource, $charset = 'UTF-8')
333
    {
334 1
        $this->messageHelperService
335 1
            ->getMultipartHelper()
336 1
            ->setContentPartForMimeType(
337 1
                $this, 'text/plain', $resource, $charset
338
            );
339 1
    }
340
341
    /**
342
     * Sets the text/html part of the message to the passed $stringOrHandle,
343
     * either creating a new part if one doesn't exist for text/html, or
344
     * assigning the value of $stringOrHandle to an existing text/html part.
345
     *
346
     * The optional $charset parameter is the charset for saving to.
347
     * $stringOrHandle is expected to be in UTF-8 regardless of the target
348
     * charset.
349
     *
350
     * @param string|resource|StreamInterface $resource
351
     * @param string $charset
352
     */
353 1
    public function setHtmlPart($resource, $charset = 'UTF-8')
354
    {
355 1
        $this->messageHelperService
356 1
            ->getMultipartHelper()
357 1
            ->setContentPartForMimeType(
358 1
                $this, 'text/html', $resource, $charset
359
            );
360 1
    }
361
362
    /**
363
     * Removes the text/plain part of the message at the passed index if one
364
     * exists.  Returns true on success.
365
     *
366
     * @param int $index
367
     * @return bool true on success
368
     */
369 1
    public function removeTextPart($index = 0)
370
    {
371 1
        return $this->messageHelperService
372 1
            ->getMultipartHelper()
373 1
            ->removePartByMimeType(
374 1
                $this, 'text/plain', $index
375
            );
376
    }
377
378
    /**
379
     * Removes all text/plain inline parts in this message, optionally keeping
380
     * other inline parts as attachments on the main message (defaults to
381
     * keeping them).
382
     *
383
     * @param bool $keepOtherPartsAsAttachments
384
     * @return bool true on success
385
     */
386 1
    public function removeAllTextParts($keepOtherPartsAsAttachments = true)
387
    {
388 1
        return $this->messageHelperService
389 1
            ->getMultipartHelper()
390 1
            ->removeAllContentPartsByMimeType(
391 1
                $this, 'text/plain', $keepOtherPartsAsAttachments
392
            );
393
    }
394
395
    /**
396
     * Removes the html part of the message if one exists.  Returns true on
397
     * success.
398
     *
399
     * @param int $index
400
     * @return bool true on success
401
     */
402 1
    public function removeHtmlPart($index = 0)
403
    {
404 1
        return $this->messageHelperService
405 1
            ->getMultipartHelper()
406 1
            ->removePartByMimeType(
407 1
                $this, 'text/html', $index
408
            );
409
    }
410
411
    /**
412
     * Removes all text/html inline parts in this message, optionally keeping
413
     * other inline parts as attachments on the main message (defaults to
414
     * keeping them).
415
     *
416
     * @param bool $keepOtherPartsAsAttachments
417
     * @return bool true on success
418
     */
419 1
    public function removeAllHtmlParts($keepOtherPartsAsAttachments = true)
420
    {
421 1
        return $this->messageHelperService
422 1
            ->getMultipartHelper()
423 1
            ->removeAllContentPartsByMimeType(
424 1
                $this, 'text/html', $keepOtherPartsAsAttachments
425
            );
426
    }
427
428
    /**
429
     * Adds an attachment part for the passed raw data string or handle and
430
     * given parameters.
431
     *
432
     * @param string|resource|StreamInterface $resource
433
     * @param string $mimeType
434
     * @param string $filename
435
     * @param string $disposition
436
     */
437 1
    public function addAttachmentPart($resource, $mimeType, $filename = null, $disposition = 'attachment')
438
    {
439 1
        $this->messageHelperService
440 1
            ->getMultipartHelper()
441 1
            ->createAndAddPartForAttachment($this, $resource, $mimeType, $disposition, $filename);
442 1
    }
443
444
    /**
445
     * Adds an attachment part using the passed file.
446
     *
447
     * Essentially creates a file stream and uses it.
448
     *
449
     * @param string $filePath
450
     * @param string $mimeType
451
     * @param string $filename
452
     * @param string $disposition
453
     */
454 1
    public function addAttachmentPartFromFile($filePath, $mimeType, $filename = null, $disposition = 'attachment')
455
    {
456 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

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