Passed
Push — master ( 805eaf...6e2293 )
by Zaahid
07:32
created

getTransferEncodingDecoratorForStream()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 17
nc 4
nop 1
dl 0
loc 20
ccs 17
cts 17
cp 1
crap 4
rs 9.7
c 0
b 0
f 0
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 GuzzleHttp\Psr7;
10
use GuzzleHttp\Psr7\AppendStream;
11
use GuzzleHttp\Psr7\StreamDecoratorTrait;
12
use Psr\Http\Message\StreamInterface;
13
use ZBateson\MailMimeParser\MailMimeParser;
14
use ZBateson\MailMimeParser\Message\Part\MessagePart;
15
use ZBateson\MailMimeParser\Message\Part\ParentHeaderPart;
16
use ZBateson\MailMimeParser\Stream\StreamFactory;
17
18
/**
19
 * Provides a readable stream for a MessagePart.
20
 *
21
 * @author Zaahid Bateson
22
 */
23
class MessagePartStream implements StreamInterface
24
{
25
    use StreamDecoratorTrait;
26
27
    /**
28
     * @var StreamFactory For creating needed stream decorators.
29
     */
30
    protected $streamFactory;
31
32
    /**
33
     * @var MessagePart The part to read from.
34
     */
35
    protected $part;
36
37
    /**
38
     * Constructor
39
     * 
40
     * @param StreamFactory $sdf
41
     * @param MessagePart $part
42
     */
43 4
    public function __construct(StreamFactory $sdf, MessagePart $part)
44
    {
45 4
        $this->streamFactory = $sdf;
46 4
        $this->part = $part;
47 4
    }
48
49
    /**
50
     * Attaches and returns a CharsetStream decorator to the passed $stream.
51
     *
52
     * If the current attached MessagePart doesn't specify a charset, $stream is
53
     * returned as-is.
54
     *
55
     * @param StreamInterface $stream
56
     * @return StreamInterface
57
     */
58 4
    private function getCharsetDecoratorForStream(StreamInterface $stream)
59
    {
60 4
        $charset = $this->part->getCharset();
61 4
        if (!empty($charset)) {
62 1
            $stream = $this->streamFactory->newCharsetStream(
63 1
                $stream,
64 1
                $charset,
65 1
                MailMimeParser::DEFAULT_CHARSET
66
            );
67
        }
68 4
        return $stream;
69
    }
70
    
71
    /**
72
     * Attaches and returns a transfer encoding stream decorator to the passed
73
     * $stream.
74
     *
75
     * The attached stream decorator is based on the attached part's returned
76
     * value from MessagePart::getContentTransferEncoding, using one of the
77
     * following stream decorators as appropriate:
78
     *
79
     * o QuotedPrintableStream
80
     * o Base64Stream
81
     * o UUStream
82
     *
83
     * @param StreamInterface $stream
84
     * @return StreamInterface
85
     */
86 4
    private function getTransferEncodingDecoratorForStream(StreamInterface $stream)
87
    {
88 4
        $encoding = $this->part->getContentTransferEncoding();
89 4
        $decorator = null;
90 4
        switch ($encoding) {
91 4
            case 'quoted-printable':
92 1
                $decorator = $this->streamFactory->newQuotedPrintableStream($stream);
93 1
                break;
94 3
            case 'base64':
95 1
                $decorator = $this->streamFactory->newBase64Stream(
96 1
                    $this->streamFactory->newChunkSplitStream($stream));
97 1
                break;
98 2
            case 'x-uuencode':
99 1
                $decorator = $this->streamFactory->newUUStream($stream);
100 1
                $decorator->setFilename($this->part->getFilename());
101 1
                break;
102
            default:
103 1
                return $stream;
104
        }
105 3
        return $decorator;
106
    }
107
108
    /**
109
     * Writes out the content portion of the attached mime part to the passed
110
     * $stream.
111
     *
112
     * @param StreamInterface $stream
113
     */
114 4
    private function writePartContentTo(StreamInterface $stream)
115
    {
116 4
        $contentStream = $this->part->getContentStream();
117 4
        if ($contentStream !== null) {
118 4
            $copyStream = $this->streamFactory->newNonClosingStream($stream);
119 4
            $es = $this->getTransferEncodingDecoratorForStream($copyStream);
120 4
            $cs = $this->getCharsetDecoratorForStream($es);
121 4
            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

121
            /** @scrutinizer ignore-call */ 
122
            Psr7\copy_to_stream($contentStream, $cs);
Loading history...
122 4
            $cs->close();
123
        }
124 4
    }
125
126
    /**
127
     * Creates an array of streams based on the attached part's mime boundary
128
     * and child streams.
129
     *
130
     * @param ParentHeaderPart $part passed in because $this->part is declared
131
     *        as MessagePart
132
     * @return StreamInterface[]
133
     */
134 2
    protected function getBoundaryAndChildStreams(ParentHeaderPart $part)
135
    {
136 2
        $boundary = $part->getHeaderParameter('Content-Type', 'boundary');
137 2
        if ($boundary === null) {
0 ignored issues
show
introduced by
The condition $boundary === null is always false.
Loading history...
138 1
            return array_map(
139 1
                function ($child) {
140 1
                    return $child->getStream();
141 1
                },
142 1
                $part->getChildParts()
143
            );
144
        }
145 1
        $streams = [];
146 1
        foreach ($part->getChildParts() as $i => $child) {
147 1
            if ($i !== 0 || $part->hasContent()) {
148 1
                $streams[] = Psr7\stream_for("\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

148
                $streams[] = /** @scrutinizer ignore-call */ Psr7\stream_for("\r\n");
Loading history...
149
            }
150 1
            $streams[] = Psr7\stream_for("--$boundary\r\n");
151 1
            $streams[] = $child->getStream();
152
        }
153 1
        $streams[] = Psr7\stream_for("\r\n--$boundary--\r\n");
154
        
155 1
        return $streams;
156
    }
157
158
    /**
159
     * Returns an array of Psr7 Streams representing the attached part and it's
160
     * direct children.
161
     *
162
     * @return StreamInterface[]
163
     */
164 4
    protected function getStreamsArray()
165
    {
166 4
        $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

166
        $content = /** @scrutinizer ignore-call */ Psr7\stream_for();
Loading history...
167 4
        $this->writePartContentTo($content);
168 4
        $content->rewind();
169 4
        $streams = [ $this->streamFactory->newHeaderStream($this->part), $content ];
170
171
        /**
172
         * @var ParentHeaderPart
173
         */
174 4
        $part = $this->part;
175 4
        if ($part instanceof ParentHeaderPart && $part->getChildCount()) {
176 2
            $streams = array_merge($streams, $this->getBoundaryAndChildStreams($part));
177
        }
178
179 4
        return $streams;
180
    }
181
182
    /**
183
     * Creates the underlying stream lazily when required.
184
     *
185
     * @return StreamInterface
186
     */
187 4
    protected function createStream()
188
    {
189 4
        return new AppendStream($this->getStreamsArray());
190
    }
191
}
192