Test Failed
Push — 1.0.0 ( dd1332...30b11b )
by Zaahid
02:32
created

MessagePart::attachContentStream()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 9
nc 8
nop 2
dl 0
loc 13
rs 9.2222
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 42
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\Message\Part;
8
9
use Psr\Http\Message\StreamInterface;
10
use GuzzleHttp\Psr7\StreamWrapper;
11
use ZBateson\MailMimeParser\MailMimeParser;
12
use ZBateson\MailMimeParser\Stream\StreamFactory;
13
14
/**
15
 * Represents a single part of a message.
16
 *
17
 * A MessagePart object may have any number of child parts, or may be a child
18
 * itself with its own parent or parents.
19
 *
20
 * @author Zaahid Bateson
21
 */
22
abstract class MessagePart
23
{
24
    /**
25
     * @var PartStreamFilterManager manages attached filters to $contentHandle
26
     */
27
    protected $partStreamFilterManager;
28
29
    /**
30
     * @var StreamFactory for creating MessagePartStream objects
31
     */
32
    protected $streamFactory;
33
34
    /**
35
     * @var ParentPart parent part
36
     */
37
    protected $parent;
38
39
    /**
40
     * @var StreamInterface a Psr7 stream containing this part's headers,
41
     *      content and children
42
     */
43
    protected $stream;
44
45
    /**
46
     * @var StreamInterface a Psr7 stream containing this part's content
47
     */
48
    protected $contentStream;
49
    
50
    /**
51
     * @var string can be used to set an override for content's charset in cases
52
     *      where a user wants to set a default other than ISO-8859-1.
53
     */
54
    protected $charsetOverride;
55
56
    /**
57 5
     * @var boolean set to true when a user attaches a stream manually, it's
58
     *      assumed to already be decoded or to have relevant transfer encoding
59
     *      decorators attached already.
60
     */
61
    protected $ignoreTransferEncoding;
62 5
63 5
    /**
64 5
     * @param PartStreamFilterManager $partStreamFilterManager
65 3
     * @param StreamFactory $streamFactory
66 3
     * @param StreamInterface $stream
67
     * @param StreamInterface $contentStream
68
     */
69 5
    public function __construct(
70 5
        PartStreamFilterManager $partStreamFilterManager,
71
        StreamFactory $streamFactory,
72
        StreamInterface $stream,
73
        StreamInterface $contentStream = null
74
    ) {
75
        $this->partStreamFilterManager = $partStreamFilterManager;
76
        $this->streamFactory = $streamFactory;
77 5
78
        $this->stream = $stream;
79 5
        $this->contentStream = $contentStream;
80
        if ($contentStream !== null) {
81
            $partStreamFilterManager->setStream(
82
                $contentStream
83
            );
84
        }
85
    }
86
87
    /**
88
     * Called when operations change the content of the MessagePart.
89
     *
90
     * The function causes calls to getStream() to return a dynamic
91
     * MessagePartStream instead of the read stream for this MessagePart and all
92
     * parent MessageParts.
93
     */
94
    protected function onChange()
95
    {
96
        $this->stream = null;
97
        if ($this->parent !== null) {
98
            $this->parent->onChange();
99
        }
100
    }
101
102
    /**
103
     * Returns true if there's a content stream associated with the part.
104
     *
105
     * @return boolean
106
     */
107
    public function hasContent()
108
    {
109
        return ($this->contentStream !== null);
110
    }
111
112
    /**
113
     * Returns true if this part's mime type is text/plain, text/html or has a
114
     * text/* and has a defined 'charset' attribute.
115
     * 
116
     * @return bool
117
     */
118
    public abstract function isTextPart();
119
    
120
    /**
121
     * Returns the mime type of the content.
122
     * 
123
     * @return string
124
     */
125
    public abstract function getContentType();
126
    
127
    /**
128
     * Returns the charset of the content, or null if not applicable/defined.
129
     * 
130
     * @return string
131
     */
132
    public abstract function getCharset();
133
    
134
    /**
135
     * Returns the content's disposition.
136
     * 
137
     * @return string
138
     */
139
    public abstract function getContentDisposition();
140
    
141
    /**
142
     * Returns the content-transfer-encoding used for this part.
143
     * 
144
     * @return string
145
     */
146
    public abstract function getContentTransferEncoding();
147
    
148
    /**
149 2
     * Returns a filename for the part if one is defined, or null otherwise.
150
     * 
151 2
     * @return string
152 2
     */
153 2
    public function getFilename()
154
    {
155
        return null;
156
    }
157
    
158
    /**
159
     * Returns true if the current part is a mime part.
160
     * 
161
     * @return bool
162
     */
163
    public abstract function isMime();
164
    
165
    /**
166
     * Rewrite me
167
     * 
168
     * @return resource the resource handle
169
     */
170
    public function getHandle()
171
    {
172
        return StreamWrapper::getResource($this->getStream());
173
    }
174
175 1
    /**
176
     * Write me
177 1
     *
178
     * @return StreamInterface the resource handle
179
     */
180 1
    public function getStream()
181
    {
182
        if ($this->stream === null) {
183
            return $this->streamFactory->newMessagePartStream($this);
184
        }
185
        return $this->stream;
186
    }
187
188
    /**
189
     * Overrides the default character set used for reading content from content
190
     * streams in cases where a user knows the source charset is not what is
191
     * specified.
192
     * 
193
     * If set, the returned value from MessagePart::getCharset is ignored.
194
     * 
195
     * Note that setting an override on a Message and calling getTextStream,
196
     * getTextContent, getHtmlStream or getHtmlContent will not be applied to
197
     * those sub-parts, unless the text/html part is the Message itself.
198
     * Instead, Message:getTextPart() should be called, and setCharsetOverride
199
     * called on the returned MessagePart.
200
     * 
201 4
     * @param string $charsetOverride
202
     * @param boolean $onlyIfNoCharset if true, $charsetOverride is used only if
203 4
     *        getCharset returns null.
204 4
     */
205 2
    public function setCharsetOverride($charsetOverride, $onlyIfNoCharset = false)
206
    {
207 2
        if (!$onlyIfNoCharset || $this->getCharset() === null) {
208
            $this->charsetOverride = $charsetOverride;
209
        }
210
    }
211
212
    /**
213
     * Returns a new resource stream handle for the part's content or null if
214
     * the part doesn't have a content section.
215
     *
216
     * The returned resource handle is a resource stream with decoding filters
217
     * appended to it.  The attached filters are determined by looking at the
218
     * part's Content-Transfer-Encoding and Content-Type headers unless a
219
     * charset override is set.  The following transfer encodings are supported:
220
     *
221
     * - quoted-printable
222
     * - base64
223
     * - x-uuencode
224
     *
225 5
     * In addition, the charset of the underlying stream is converted to the
226
     * passed $charset if the content is known to be text.
227 5
     *
228 3
     * @param string $charset
229 3
     * @return resource
230 3
     */
231 3
    public function getContentResourceHandle($charset = MailMimeParser::DEFAULT_CHARSET)
232 3
    {
233 3
        $stream = $this->getContentStream($charset);
234
        if ($stream !== null) {
235
            return StreamWrapper::getResource($stream);
236 2
        }
237
        return null;
238
    }
239
240
    /**
241
     * Returns the StreamInterface for the part's content or null if the part
242
     * doesn't have a content section.
243
     *
244
     * Because the returned stream may be a shared object if called multiple
245
     * times, the function isn't exposed publicly.  If called multiple times
246
     * with the same $charset, and the value of the part's
247
     * Content-Transfer-Encoding header not having changed, the returned stream
248 2
     * is the same instance and may need to be rewound.
249
     *
250 2
     * Note that PartStreamFilterManager rewinds the stream before returning it.
251 2
     *
252 1
     * @param string $charset
253
     * @return StreamInterface
254 1
     */
255
    public function getContentStream($charset = MailMimeParser::DEFAULT_CHARSET)
256
    {
257
        if ($this->hasContent()) {
258
            $tr = ($this->ignoreTransferEncoding) ? '' : $this->getContentTransferEncoding();
259
            $ch = ($this->charsetOverride !== null) ? $this->charsetOverride : $this->getCharset();
260
            return $this->partStreamFilterManager->getContentStream(
261
                $tr,
262 1
                $ch,
263
                $charset
264 1
            );
265
        }
266
        return null;
267
    }
268
269
    /**
270
     * Shortcut to reading stream content and assigning it to a string.  Returns
271
     * null if the part doesn't have a content stream.
272
     * 
273
     * The returned string is encoded to the passed $charset character encoding,
274
     * defaulting to UTF-8.
275
     *
276
     * @return string
277
     */
278
    public function getContent($charset = MailMimeParser::DEFAULT_CHARSET)
279
    {
280
        $stream = $this->getContentStream($charset);
281
        if ($stream !== null) {
282
            return $stream->getContents();
283
        }
284
        return null;
285
    }
286
287
    /**
288
     * Returns this part's parent.
289
     *
290
     * @return \ZBateson\MailMimeParser\Message\Part\MimePart
291
     */
292
    public function getParent()
293
    {
294
        return $this->parent;
295
    }
296
297
    /**
298
     * Attaches the stream or resource handle for the part's content.  The
299
     * stream is closed when another stream is attached, or the MimePart is
300
     * destroyed.
301
     *
302
     * @param Stream|resource $stream
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\Message\Part\Stream 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...
303
     * @param string $streamCharset
304
     */
305
    public function attachContentStream($stream, $streamCharset = MailMimeParser::DEFAULT_CHARSET)
306
    {
307
        if ($this->contentStream !== null && $this->contentStream !== $stream) {
308
            $this->contentStream->close();
309
        }
310
        $this->contentStream = Psr7\stream_for($stream);
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

310
        $this->contentStream = /** @scrutinizer ignore-call */ Psr7\stream_for($stream);
Loading history...
311
        $ch = ($this->charsetOverride !== null) ? $this->charsetOverride : $this->getCharset();
312
        if ($ch !== null && $streamCharset !== $ch) {
313
            $this->charsetOverride = $streamCharset;
314
        }
315
        $this->ignoreTransferEncoding = true;
316
        $this->partStreamFilterManager->setStream($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type resource; however, parameter $stream of ZBateson\MailMimeParser\...terManager::setStream() does only seem to accept null|Psr\Http\Message\StreamInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

316
        $this->partStreamFilterManager->setStream(/** @scrutinizer ignore-type */ $stream);
Loading history...
317
        $this->onChange();
318
    }
319
320
    /**
321
     * Detaches and closes the content stream.
322
     */
323
    protected function detachContentStream()
324
    {
325
        $this->contentStream = null;
326
        $this->partStreamFilterManager->setStream(null);
327
        $this->onChange();
328
    }
329
330
    /**
331
     * Sets the content of the part to the passed string.
332
     *
333
     * @param string $string
334
     * @param string $charset
335
     */
336
    public function setContent($string, $charset = MailMimeParser::DEFAULT_CHARSET)
337
    {
338
        $stream = Psr7\stream_for($string);
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

338
        $stream = /** @scrutinizer ignore-call */ Psr7\stream_for($string);
Loading history...
339
        $this->attachContentStream($stream, $charset);
340
        // this->onChange called in attachContentStream
341
    }
342
}
343