Passed
Push — master ( 9e6d2f...c6b62f )
by Zaahid
06:54
created

MessagePartStream   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 60
dl 0
loc 132
ccs 0
cts 62
cp 0
rs 10
c 0
b 0
f 0
wmc 18

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getTransferEncodingDecoratorForStream() 0 22 4
A getCharsetDecoratorForStream() 0 12 2
A writePartContentTo() 0 12 2
A getBoundaryAndChildStreams() 0 18 6
A getStreamsArray() 0 12 2
A __construct() 0 4 1
A createStream() 0 3 1
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\Stream;
8
9
use ZBateson\MailMimeParser\MailMimeParser;
10
use ZBateson\MailMimeParser\Message\Part\MessagePart;
11
use ZBateson\MailMimeParser\Message\Part\MimePart;
12
use ZBateson\MailMimeParser\Message\Part\ParentHeaderPart;
13
use ZBateson\MailMimeParser\Stream\StreamFactory;
14
use Psr\Http\Message\StreamInterface;
15
use GuzzleHttp\Psr7\StreamDecoratorTrait;
16
use GuzzleHttp\Psr7\AppendStream;
17
use GuzzleHttp\Psr7;
18
19
/**
20
 * Writes a MimePart to a resource handle.
21
 * 
22
 * The class is responsible for writing out the headers and content of a
23
 * MimePart to an output stream buffer, taking care of encoding and filtering.
24
 * 
25
 * @author Zaahid Bateson
26
 */
27
class MessagePartStream implements StreamInterface
28
{
29
    use StreamDecoratorTrait;
30
31
    protected $streamFactory;
32
    protected $part;
33
34
    public function __construct(StreamFactory $sdf, MessagePart $part)
35
    {
36
        $this->streamFactory = $sdf;
37
        $this->part = $part;
38
    }
39
40
    /**
41
     * Sets up a mailmimeparser-encode stream filter on the content resource 
42
     * handle of the passed MimePart if applicable and returns a reference to
43
     * the filter.
44
     *
45
     * @param MimePart $part
46
     * @return StreamInterface a reference to the appended stream filter or null
47
     */
48
    private function getCharsetDecoratorForStream(MessagePart $part, StreamInterface $stream)
49
    {
50
        $charset = $part->getCharset();
51
        if (!empty($charset)) {
52
            $decorator = $this->streamFactory->newCharsetStream(
53
                $stream,
54
                $charset,
55
                MailMimeParser::DEFAULT_CHARSET
56
            );
57
            return $decorator;
58
        }
59
        return $stream;
60
    }
61
    
62
    /**
63
     * Appends a stream filter on the passed MimePart's content resource handle
64
     * based on the type of encoding for the passed part.
65
     *
66
     * @param MimePart $part
67
     * @param resource $handle
68
     * @param StreamLeftover $leftovers
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\Stream\StreamLeftover was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
69
     * @return StreamInterface the stream filter
70
     */
71
    private function getTransferEncodingDecoratorForStream(
72
        MessagePart $part,
73
        StreamInterface $stream
74
    ) {
75
        $encoding = $part->getContentTransferEncoding();
76
        $decorator = null;
77
        switch ($encoding) {
78
            case 'quoted-printable':
79
                $decorator = $this->streamFactory->newQuotedPrintableStream($stream);
80
                break;
81
            case 'base64':
82
                $decorator = $this->streamFactory->newBase64Stream(
83
                    $this->streamFactory->newChunkSplitStream($stream));
84
                break;
85
            case 'x-uuencode':
86
                $decorator = $this->streamFactory->newUUStream($stream);
87
                $decorator->setFilename($part->getFilename());
88
                break;
89
            default:
90
                return $stream;
91
        }
92
        return $decorator;
93
    }
94
95
    /**
96
     * Writes out the content portion of the mime part based on the headers that
97
     * are set on the part, taking care of character/content-transfer encoding.
98
     *
99
     * @param MessagePart $part
100
     * @param StreamInterface $stream
101
     */
102
    public function writePartContentTo(MessagePart $part, StreamInterface $stream)
103
    {
104
        $contentStream = $part->getContentStream();
105
        if ($contentStream !== null) {
106
            $copyStream = $this->streamFactory->newNonClosingStream($stream);
107
            $es = $this->getTransferEncodingDecoratorForStream(
108
                $part,
109
                $copyStream
110
            );
111
            $cs = $this->getCharsetDecoratorForStream($part, $es);
112
            Psr7\copy_to_stream($contentStream, $cs);
0 ignored issues
show
Bug introduced by
The function copy_to_stream 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

112
            /** @scrutinizer ignore-call */ 
113
            Psr7\copy_to_stream($contentStream, $cs);
Loading history...
113
            $cs->close();
114
        }
115
    }
116
117
    protected function getBoundaryAndChildStreams(ParentHeaderPart $part)
118
    {
119
        $streams = [];
120
        $boundary = $part->getHeaderParameter('Content-Type', 'boundary');
121
        foreach ($part->getChildParts() as $i => $child) {
122
            if ($boundary !== null) {
123
                if ($i === 0 && !$part->hasContent()) {
124
                    $streams[] = Psr7\stream_for("--$boundary\r\n");
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

124
                    $streams[] = /** @scrutinizer ignore-call */ Psr7\stream_for("--$boundary\r\n");
Loading history...
125
                } else {
126
                    $streams[] = Psr7\stream_for("\r\n--$boundary\r\n");
127
                }
128
            }
129
            $streams[] = $child->getStream();
130
        }
131
        if ($boundary !== null) {
0 ignored issues
show
introduced by
The condition $boundary !== null is always true.
Loading history...
132
            $streams[] = Psr7\stream_for("\r\n--$boundary--\r\n");
133
        }
134
        return $streams;
135
    }
136
137
    protected function getStreamsArray()
138
    {
139
        $content = Psr7\stream_for();
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

139
        $content = /** @scrutinizer ignore-call */ Psr7\stream_for();
Loading history...
140
        $this->writePartContentTo($this->part, $content);
141
        $content->rewind();
142
        $streams = [ new HeaderStream($this->part), $content ];
143
144
        if ($this->part instanceof ParentHeaderPart) {
145
            $streams = array_merge($streams, $this->getBoundaryAndChildStreams($this->part));
146
        }
147
148
        return $streams;
149
    }
150
151
    /**
152
     * Creates the underlying stream lazily when required.
153
     *
154
     * @return StreamInterface
155
     */
156
    protected function createStream()
157
    {
158
        return new AppendStream($this->getStreamsArray());
159
    }
160
}
161