Passed
Pull Request — master (#171)
by Zaahid
06:32 queued 03:18
created

ParserPartStreamContainer::hasContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
nc 1
nop 0
crap 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\Parser\Part;
8
9
use ZBateson\MailMimeParser\Message\PartStreamContainer;
10
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
11
use ZBateson\MailMimeParser\Stream\StreamFactory;
12
use Psr\Http\Message\StreamInterface;
13
use SplObserver;
14
use SplSubject;
15
16
/**
17
 * A part stream container that proxies requests for content streams to a parser
18
 * to read the content.
19
 *
20
 * Keeps reference to the original stream a part was parsed from, using that
21
 * stream as the part's stream instead of the PartStreamContainer's
22
 * MessagePartStream (which dynamically creates a stream from an IMessagePart)
23
 * unless the part changed.
24
 * 
25
 * The ParserPartStreamContainer must also be attached to its underlying part
26
 * with SplSubject::attach() so the ParserPartStreamContainer gets notified of
27
 * any changes.
28
 *
29
 * @author Zaahid Bateson
30
 */
31
class ParserPartStreamContainer extends PartStreamContainer implements SplObserver
32
{
33
    /**
34
     * @var ParserPartProxy The parser proxy to ferry requests to on-demand.
35
     */
36
    protected $parserProxy;
37
38
    /**
39
     * @var StreamInterface the original stream for a parsed message, used when
40
     *      the message hasn't changed
41
     */
42
    protected $parsedStream;
43
44
    /**
45
     * @var bool true if the stream should be detached when this container is
46
     *      destroyed (thereby not closing the stream).
47
     */
48
    protected $detachParsedStream = false;
49
50
    /**
51
     * @var bool set to true if the part's been updated since it was created.
52
     */
53
    protected $partUpdated = false;
54
55
    /**
56
     * @var bool false if the content for the part represented by this container
57
     *      has not yet been requested from the parser.
58
     */
59
    protected $contentParseRequested = false;
60
61 115
    public function __construct(StreamFactory $streamFactory, ParserPartProxy $parserProxy)
62
    {
63 115
        parent::__construct($streamFactory);
64 115
        $this->parserProxy = $parserProxy;
65 115
    }
66
67 4
    public function __destruct()
68
    {
69 4
        if ($this->detachParsedStream && $this->parsedStream !== null) {
70 2
            $this->parsedStream->detach();
71
        }
72 4
    }
73
74
    /**
75
     * Requests content from the parser if not previously requested, and calls
76
     * PartStreamContainer::setContentStream().
77
     */
78 109
    protected function requestParsedContentStream()
79
    {
80 109
        if (!$this->contentParseRequested) {
81 109
            $this->contentParseRequested = true;
82 109
            $this->parserProxy->parseContent();
83 109
            parent::setContentStream($this->streamFactory->getLimitedContentStream(
84 109
                $this->parserProxy
85
            ));
86
        }
87 109
    }
88
89
    /**
90
     * Ensures the parser has parsed the entire part, and sets
91
     * $this->parsedStream to the original parsed stream (or a limited part of
92
     * it corresponding to the current part this stream container belongs to).
93
     */
94 102
    protected function requestParsedStream()
95
    {
96 102
        if ($this->parsedStream === null) {
97 102
            $this->parserProxy->parseAll();
98 102
            $this->parsedStream = $this->streamFactory->getLimitedPartStream(
99 102
                $this->parserProxy
100
            );
101 102
            if ($this->parsedStream !== null) {
102 102
                $this->detachParsedStream = ($this->parsedStream->getMetadata('mmp-detached-stream') === true);
103
            }
104
        }
105 102
    }
106
107 104
    public function hasContent()
108
    {
109 104
        $this->requestParsedContentStream();
110 104
        return parent::hasContent();
111
    }
112
113 103
    public function getContentStream($transferEncoding, $fromCharset, $toCharset)
114
    {
115 103
        $this->requestParsedContentStream();
116 103
        return parent::getContentStream($transferEncoding, $fromCharset, $toCharset);
117
    }
118
119 71
    public function getBinaryContentStream($transferEncoding)
120
    {
121 71
        $this->requestParsedContentStream();
122 71
        return parent::getBinaryContentStream($transferEncoding);
123
    }
124
125 21
    public function setContentStream(StreamInterface $contentStream = null)
126
    {
127
        // has to be overridden because requestParsedContentStream calls
128
        // parent::setContentStream as well, so needs to be parsed before
129
        // overriding the contentStream with a manual 'set'.
130 21
        $this->requestParsedContentStream();
131 21
        parent::setContentStream($contentStream);
132 21
    }
133
134 102
    public function getStream()
135
    {
136 102
        $this->requestParsedStream();
137 102
        if (!$this->partUpdated) {
138 24
            if ($this->parsedStream !== null) {
139 24
                $this->parsedStream->rewind();
140 24
                return $this->parsedStream;
141
            }
142
        }
143 93
        return parent::getStream();
144
    }
145
146 95
    public function update(SplSubject $subject)
147
    {
148 95
        $this->partUpdated = true;
149 95
    }
150
}
151