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

PartBuilder   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
eloc 42
c 2
b 0
f 0
dl 0
loc 246
ccs 56
cts 56
cp 1
rs 10

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getHeaderContainer() 0 3 1
A isMime() 0 7 3
A getStreamPartStartPos() 0 3 1
A setStreamPartStartPos() 0 3 1
A getMessageResourceHandle() 0 5 2
A getParent() 0 3 1
A setStreamPartEndPos() 0 5 2
A setStreamPartAndContentEndPos() 0 4 1
A getStreamPartLength() 0 3 1
A getStream() 0 5 2
A isContentParsed() 0 3 1
A getMessageResourceHandlePos() 0 3 1
A getStreamContentStartPos() 0 3 1
A setStreamContentStartPos() 0 3 1
A getStreamContentLength() 0 3 1
A __destruct() 0 4 2
A __construct() 0 9 2
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;
8
9
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
10
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
11
use ZBateson\MailMimeParser\Header\HeaderConsts;
12
use GuzzleHttp\Psr7\StreamWrapper;
13
use Psr\Http\Message\StreamInterface;
14
15
/**
16
 * Holds generic/all purpose information about a part while it's being parsed.
17
 *
18
 * The class holds:
19
 *  - a HeaderContainer to hold headers
20
 *  - stream positions (part start/end positions, content start/end)
21
 *  - the message's psr7 stream and a resource handle created from it (held
22
 *    only for a top-level PartBuilder representing the message, child
23
 *    PartBuilders do not duplicate/hold a separate stream).
24
 *
25
 * More specific information a parser needs to keep about a message as it's
26
 * parsing it should be stored in its ParserPartProxy.
27
 *
28
 * @author Zaahid Bateson
29
 */
30
class PartBuilder
31
{
32
    /**
33
     * @var int The offset read start position for this part (beginning of
34
     * headers) in the message's stream.
35
     */
36
    private $streamPartStartPos = null;
37
    
38
    /**
39
     * @var int The offset read end position for this part.  If the part is a
40
     * multipart mime part, the end position is after all of this parts
41
     * children.
42
     */
43
    private $streamPartEndPos = null;
44
    
45
    /**
46
     * @var int The offset read start position in the message's stream for the
47
     * beginning of this part's content (body).
48
     */
49
    private $streamContentStartPos = null;
50
    
51
    /**
52
     * @var int The offset read end position in the message's stream for the
53
     * end of this part's content (body).
54
     */
55
    private $streamContentEndPos = null;
56
57
    /**
58
     * @var PartHeaderContainer The parsed part's headers.
59
     */
60
    private $headerContainer;
61
62
    /**
63
     * @var StreamInterface the raw message input stream for a message, or null
64
     *      for a child part.
65
     */
66
    private $messageStream = null;
67
68
    /**
69
     * @var resource the raw message input stream handle constructed from
70
     *      $messageStream or null for a child part
71
     */
72
    private $messageHandle = null;
73
74
    /**
75
     * @var ParserPartProxy The parent ParserPartProxy.
76
     */
77
    private $parent = null;
78
79 108
    public function __construct(PartHeaderContainer $headerContainer, StreamInterface $messageStream = null, ParserPartProxy $parent = null)
80
    {
81 108
        $this->headerContainer = $headerContainer;
82 108
        $this->messageStream = $messageStream;
83 108
        $this->parent = $parent;
84 108
        if ($messageStream !== null) {
85 107
            $this->messageHandle = StreamWrapper::getResource($messageStream);
86
        }
87 108
        $this->setStreamPartStartPos($this->getMessageResourceHandlePos());
88 108
    }
89
90 22
    public function __destruct()
91
    {
92 22
        if ($this->messageHandle) {
93 5
            fclose($this->messageHandle);
94
        }
95 22
    }
96
97
    /**
98
     * The ParserPartProxy parent of this PartBuilder.
99
     *
100
     * @return ParserPartProxy
101
     */
102 104
    public function getParent()
103
    {
104 104
        return $this->parent;
105
    }
106
107
    /**
108
     * Returns this part's PartHeaderContainer.
109
     *
110
     * @return PartHeaderContainer the container
111
     */
112 105
    public function getHeaderContainer()
113
    {
114 105
        return $this->headerContainer;
115
    }
116
117
    /**
118
     * Returns the raw message StreamInterface for a message, getting it from
119
     * the parent part if this is a child part.
120
     *
121
     * @return StreamInterface
122
     */
123 102
    public function getStream()
124
    {
125 102
        return ($this->parent !== null) ?
126 72
            $this->parent->getStream() :
127 102
            $this->messageStream;
128
    }
129
130
    /**
131
     * Returns the resource handle for a the message's stream, getting it from
132
     * the parent part if this is a child part.
133
     *
134
     * @return resource
135
     */
136 108
    public function getMessageResourceHandle()
137
    {
138 108
        return ($this->parent !== null) ?
139 74
            $this->parent->getMessageResourceHandle() :
140 108
            $this->messageHandle;
141
    }
142
143
    /**
144
     * Shortcut for calling ftell($partBuilder->getMessageResourceHandle()).
145
     *
146
     * @return int
147
     */
148 108
    public function getMessageResourceHandlePos()
149
    {
150 108
        return ftell($this->getMessageResourceHandle());
151
    }
152
153
    /**
154
     * Returns the byte offset start position for this part within the message
155
     * stream if it's been set, or null otherwise.
156
     *
157
     * @return int|null
158
     */
159 101
    public function getStreamPartStartPos()
160
    {
161 101
        return $this->streamPartStartPos;
162
    }
163
164
    /**
165
     * Returns the number of raw bytes this part has.
166
     *
167
     * This method does not perform checks on whether the start pos and end pos
168
     * of this part have been set, and so could cause errors if called before
169
     * being set and are still null.
170
     *
171
     * @return int
172
     */
173 101
    public function getStreamPartLength()
174
    {
175 101
        return $this->streamPartEndPos - $this->streamPartStartPos;
176
    }
177
178
    /**
179
     * Returns the byte offset start position of the content of this part within
180
     * the main raw message stream, or null if not set.
181
     *
182
     * @return int|null
183
     */
184 104
    public function getStreamContentStartPos()
185
    {
186 104
        return $this->streamContentStartPos;
187
    }
188
189
    /**
190
     * Returns the length of this part's content stream.
191
     *
192
     * This method does not perform checks on whether the start pos and end pos
193
     * of this part's content have been set, and so could cause errors if called
194
     * before being set and are still null.
195
     *
196
     * @return int
197
     */
198 104
    public function getStreamContentLength()
199
    {
200 104
        return $this->streamContentEndPos - $this->streamContentStartPos;
201
    }
202
203
    /**
204
     * Sets the byte offset start position of the part in the raw message
205
     * stream.
206
     * 
207
     * @param int $streamPartStartPos
208
     */
209 108
    public function setStreamPartStartPos($streamPartStartPos)
210
    {
211 108
        $this->streamPartStartPos = $streamPartStartPos;
212 108
    }
213
214
    /**
215
     * Sets the byte offset end position of the part in the raw message stream,
216
     * and also calls its parent's setParentStreamPartEndPos to expand to parent
217
     * PartBuilders.
218
     * 
219
     * @param int $streamPartEndPos
220
     */
221 106
    public function setStreamPartEndPos($streamPartEndPos)
222
    {
223 106
        $this->streamPartEndPos = $streamPartEndPos;
224 106
        if ($this->parent !== null) {
225 74
            $this->parent->setStreamPartEndPos($streamPartEndPos);
226
        }
227 106
    }
228
229
    /**
230
     * Sets the byte offset start position of the content in the raw message
231
     * stream.
232
     * 
233
     * @param int $streamContentStartPos
234
     */
235 105
    public function setStreamContentStartPos($streamContentStartPos)
236
    {
237 105
        $this->streamContentStartPos = $streamContentStartPos;
238 105
    }
239
240
    /**
241
     * Sets the byte offset end position of the content and part in the raw
242
     * message stream.
243
     * 
244
     * @param int $streamContentEndPos
245
     */
246 105
    public function setStreamPartAndContentEndPos($streamContentEndPos)
247
    {
248 105
        $this->streamContentEndPos = $streamContentEndPos;
249 105
        $this->setStreamPartEndPos($streamContentEndPos);
250 105
    }
251
252
    /**
253
     * Returns true if the byte offset positions for this part's content have
254
     * been set.
255
     *
256
     * @return bool true if set.
257
     */
258 103
    public function isContentParsed()
259
    {
260 103
        return ($this->streamContentEndPos !== null);
261
    }
262
263
    /**
264
     * Returns true if this part, or any parent, have a Content-Type or
265
     * MIME-Version header set.
266
     *
267
     * @return bool true if it's a mime message or child of a mime message.
268
     */
269 104
    public function isMime()
270
    {
271 104
        if ($this->getParent() !== null) {
272 73
            return $this->getParent()->isMime();
273
        }
274 104
        return ($this->headerContainer->exists(HeaderConsts::CONTENT_TYPE) ||
275 104
            $this->headerContainer->exists(HeaderConsts::MIME_VERSION));
276
    }
277
}
278