|
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; |
|
8
|
|
|
|
|
9
|
|
|
use ZBateson\MailMimeParser\Header\HeaderFactory; |
|
10
|
|
|
use ZBateson\MailMimeParser\Header\ParameterHeader; |
|
11
|
|
|
use ZBateson\MailMimeParser\Message\Writer\MimePartWriter; |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Represents a single part of a multi-part mime message. |
|
15
|
|
|
* |
|
16
|
|
|
* A MimePart object may have any number of child parts, or may be a child |
|
17
|
|
|
* itself with its own parent or parents. |
|
18
|
|
|
* |
|
19
|
|
|
* The content of the part can be read from its PartStream resource handle, |
|
20
|
|
|
* accessible via MimePart::getContentResourceHanlde. |
|
21
|
|
|
* |
|
22
|
|
|
* @author Zaahid Bateson |
|
23
|
|
|
*/ |
|
24
|
|
|
class MimePart |
|
25
|
|
|
{ |
|
26
|
|
|
/** |
|
27
|
|
|
* @var \ZBateson\MailMimeParser\Header\HeaderFactory the HeaderFactory |
|
28
|
|
|
* object used for created headers |
|
29
|
|
|
*/ |
|
30
|
|
|
protected $headerFactory; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* @var \ZBateson\MailMimeParser\Header\AbstractHeader[] array of header |
|
34
|
|
|
* objects |
|
35
|
|
|
*/ |
|
36
|
|
|
protected $headers; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* @var \ZBateson\MailMimeParser\Message\MimePart parent part |
|
40
|
|
|
*/ |
|
41
|
|
|
protected $parent; |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* @var resource the content's resource handle |
|
45
|
|
|
*/ |
|
46
|
|
|
protected $handle; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* @var \ZBateson\MailMimeParser\Message\MimePart[] array of parts in this |
|
50
|
|
|
* message |
|
51
|
|
|
*/ |
|
52
|
|
|
protected $parts = []; |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* @var \ZBateson\MailMimeParser\Message\MimePart[][] Maps mime types to |
|
56
|
|
|
* parts for looking up in getPartByMimeType |
|
57
|
|
|
*/ |
|
58
|
|
|
protected $mimeToPart = []; |
|
59
|
|
|
|
|
60
|
|
|
/** |
|
61
|
|
|
* @var \ZBateson\MailMimeParser\Message\Writer\MimePartWriter the part |
|
62
|
|
|
* writer for this MimePart |
|
63
|
|
|
*/ |
|
64
|
|
|
protected $partWriter = null; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* Sets up class dependencies. |
|
68
|
|
|
* |
|
69
|
|
|
* @param HeaderFactory $headerFactory |
|
70
|
|
|
* @param MimePartWriter $partWriter |
|
71
|
|
|
*/ |
|
72
|
91 |
|
public function __construct(HeaderFactory $headerFactory, MimePartWriter $partWriter) |
|
73
|
|
|
{ |
|
74
|
91 |
|
$this->headerFactory = $headerFactory; |
|
75
|
91 |
|
$this->partWriter = $partWriter; |
|
76
|
91 |
|
} |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* Closes the attached resource handle. |
|
80
|
|
|
*/ |
|
81
|
91 |
|
public function __destruct() |
|
82
|
|
|
{ |
|
83
|
91 |
|
if (is_resource($this->handle)) { |
|
84
|
10 |
|
fclose($this->handle); |
|
85
|
10 |
|
} |
|
86
|
91 |
|
} |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* Adds the passed part to the parts array, and registers non-attachment/ |
|
90
|
|
|
* non-multipart parts by their content type. |
|
91
|
|
|
* |
|
92
|
|
|
* If the $position parameter is non-null, adds the part at the passed |
|
93
|
|
|
* position index. |
|
94
|
|
|
* |
|
95
|
|
|
* @param \ZBateson\MailMimeParser\Message\MimePart $part |
|
96
|
|
|
* @param int $position |
|
97
|
|
|
*/ |
|
98
|
83 |
|
public function addPart(MimePart $part, $position = null) |
|
99
|
|
|
{ |
|
100
|
83 |
|
if ($part->getParent() !== null && $this !== $part->getParent()) { |
|
101
|
24 |
|
$part->getParent()->addPart($part, $position); |
|
102
|
83 |
|
} elseif ($part !== $this) { |
|
103
|
59 |
|
array_splice($this->parts, ($position === null) ? count($this->parts) : $position, 0, [ $part ]); |
|
104
|
59 |
|
} |
|
105
|
83 |
|
$this->registerPart($part); |
|
106
|
83 |
|
} |
|
107
|
|
|
|
|
108
|
|
|
/** |
|
109
|
|
|
* Registers non-attachment parts in the mime type registry |
|
110
|
|
|
* |
|
111
|
|
|
* @param \ZBateson\MailMimeParser\Message\MimePart $part |
|
112
|
|
|
*/ |
|
113
|
83 |
|
protected function registerPart(MimePart $part) |
|
114
|
|
|
{ |
|
115
|
83 |
|
if ($part->getHeaderValue('Content-Disposition') === null && !$part->isMultiPart()) { |
|
116
|
79 |
|
$key = strtolower($part->getHeaderValue('Content-Type', 'text/plain')); |
|
117
|
79 |
|
if (!isset($this->mimeToPart[$key])) { |
|
118
|
79 |
|
$this->mimeToPart[$key] = []; |
|
119
|
79 |
|
} |
|
120
|
79 |
|
$this->mimeToPart[$key][] = $part; |
|
121
|
79 |
|
} |
|
122
|
83 |
|
} |
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* Removes the part from the mime-type registry. |
|
126
|
|
|
* |
|
127
|
|
|
* @param \ZBateson\MailMimeParser\Message\MimePart $part |
|
128
|
|
|
*/ |
|
129
|
14 |
|
protected function unregisterPart(MimePart $part) |
|
130
|
|
|
{ |
|
131
|
14 |
|
$key = strtolower($part->getHeaderValue('Content-Type', 'text/plain')); |
|
132
|
14 |
|
if (isset($this->mimeToPart[$key])) { |
|
133
|
11 |
|
foreach ($this->mimeToPart[$key] as $index => $p) { |
|
134
|
11 |
|
if ($p === $part) { |
|
135
|
11 |
|
array_splice($this->mimeToPart[$key], $index, 1); |
|
136
|
11 |
|
break; |
|
137
|
|
|
} |
|
138
|
11 |
|
} |
|
139
|
11 |
|
} |
|
140
|
14 |
|
} |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* Unregisters the child part from this part and returns its position or |
|
144
|
|
|
* null if it wasn't found. |
|
145
|
|
|
* |
|
146
|
|
|
* @param \ZBateson\MailMimeParser\Message\MimePart $part |
|
147
|
|
|
* @return int or null if not found |
|
148
|
|
|
*/ |
|
149
|
14 |
|
public function removePart(MimePart $part) |
|
150
|
|
|
{ |
|
151
|
14 |
|
$parent = $part->getParent(); |
|
152
|
14 |
|
$this->unregisterPart($part); |
|
153
|
14 |
|
if ($this !== $parent && $parent !== null) { |
|
154
|
1 |
|
return $parent->removePart($part); |
|
155
|
|
|
} else { |
|
156
|
14 |
|
$position = array_search($part, $this->parts, true); |
|
157
|
14 |
|
if ($position !== false) { |
|
158
|
11 |
|
array_splice($this->parts, $position, 1); |
|
159
|
11 |
|
return $position; |
|
160
|
|
|
} |
|
161
|
|
|
} |
|
162
|
4 |
|
return null; |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* Returns the part at the given 0-based index, or null if none is set. |
|
167
|
|
|
* |
|
168
|
|
|
* @param int $index |
|
169
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart |
|
170
|
|
|
*/ |
|
171
|
2 |
|
public function getPart($index) |
|
172
|
|
|
{ |
|
173
|
2 |
|
$parts = $this->getAllParts(); |
|
174
|
2 |
|
if (!isset($parts[$index])) { |
|
175
|
|
|
return null; |
|
176
|
|
|
} |
|
177
|
2 |
|
return $parts[$index]; |
|
178
|
|
|
} |
|
179
|
|
|
|
|
180
|
|
|
/** |
|
181
|
|
|
* Returns all child parts, and child parts of all children. |
|
182
|
|
|
* |
|
183
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart[] |
|
184
|
|
|
*/ |
|
185
|
11 |
|
public function getAllParts() |
|
186
|
|
|
{ |
|
187
|
11 |
|
$aParts = []; |
|
188
|
11 |
|
foreach ($this->parts as $part) { |
|
189
|
11 |
|
$aParts = array_merge($aParts, [ $part ], $part->getAllParts()); |
|
190
|
11 |
|
} |
|
191
|
11 |
|
return $aParts; |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
/** |
|
195
|
|
|
* Returns the total number of parts in this and all children. |
|
196
|
|
|
* |
|
197
|
|
|
* @return int |
|
198
|
|
|
*/ |
|
199
|
1 |
|
public function getPartCount() |
|
200
|
|
|
{ |
|
201
|
1 |
|
return count($this->parts) + array_sum( |
|
202
|
1 |
|
array_map(function ($part) { |
|
203
|
1 |
|
return $part->getPartCount(); |
|
204
|
1 |
|
}, |
|
205
|
1 |
|
$this->parts) |
|
206
|
1 |
|
); |
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
|
|
/** |
|
210
|
|
|
* Returns the direct child at the given 0-based index, or null if none is |
|
211
|
|
|
* set. |
|
212
|
|
|
* |
|
213
|
|
|
* @param int $index |
|
214
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart |
|
215
|
|
|
*/ |
|
216
|
9 |
|
public function getChild($index) |
|
217
|
|
|
{ |
|
218
|
9 |
|
if (!isset($this->parts[$index])) { |
|
219
|
|
|
return null; |
|
220
|
|
|
} |
|
221
|
9 |
|
return $this->parts[$index]; |
|
222
|
|
|
} |
|
223
|
|
|
|
|
224
|
|
|
/** |
|
225
|
|
|
* Returns all direct child parts. |
|
226
|
|
|
* |
|
227
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart[] |
|
228
|
|
|
*/ |
|
229
|
80 |
|
public function getChildParts() |
|
230
|
|
|
{ |
|
231
|
80 |
|
return $this->parts; |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* Returns the number of direct children under this part. |
|
236
|
|
|
* |
|
237
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart[] |
|
238
|
|
|
*/ |
|
239
|
1 |
|
public function getChildCount() |
|
240
|
|
|
{ |
|
241
|
1 |
|
return count($this->parts); |
|
242
|
|
|
} |
|
243
|
|
|
|
|
244
|
|
|
/** |
|
245
|
|
|
* Returns the part associated with the passed mime type if it exists. |
|
246
|
|
|
* |
|
247
|
|
|
* @param string $mimeType |
|
248
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart or null |
|
249
|
|
|
*/ |
|
250
|
22 |
View Code Duplication |
public function getPartByMimeType($mimeType) |
|
|
|
|
|
|
251
|
|
|
{ |
|
252
|
22 |
|
$key = strtolower($mimeType); |
|
253
|
22 |
|
if (isset($this->mimeToPart[$key])) { |
|
254
|
22 |
|
return $this->mimeToPart[$key][0]; |
|
255
|
|
|
} |
|
256
|
|
|
return null; |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
/** |
|
260
|
|
|
* Returns an array of all parts associated with the passed mime type if any |
|
261
|
|
|
* exist or null otherwise. |
|
262
|
|
|
* |
|
263
|
|
|
* @param string $mimeType |
|
264
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart[] or null |
|
265
|
|
|
*/ |
|
266
|
|
View Code Duplication |
public function getAllPartsByMimeType($mimeType) |
|
|
|
|
|
|
267
|
|
|
{ |
|
268
|
|
|
$key = strtolower($mimeType); |
|
269
|
|
|
if (isset($this->mimeToPart[$key])) { |
|
270
|
|
|
return $this->mimeToPart[$key]; |
|
271
|
|
|
} |
|
272
|
|
|
return null; |
|
273
|
|
|
} |
|
274
|
|
|
|
|
275
|
|
|
/** |
|
276
|
|
|
* Returns true if there's a content stream associated with the part. |
|
277
|
|
|
* |
|
278
|
|
|
* @return boolean |
|
279
|
|
|
*/ |
|
280
|
16 |
|
public function hasContent() |
|
281
|
|
|
{ |
|
282
|
16 |
|
if ($this->handle !== null) { |
|
283
|
16 |
|
return true; |
|
284
|
|
|
} |
|
285
|
1 |
|
return false; |
|
286
|
|
|
} |
|
287
|
|
|
|
|
288
|
|
|
/** |
|
289
|
|
|
* Returns true if this part's mime type is multipart/* |
|
290
|
|
|
* |
|
291
|
|
|
* @return bool |
|
292
|
|
|
*/ |
|
293
|
83 |
|
public function isMultiPart() |
|
294
|
|
|
{ |
|
295
|
83 |
|
return preg_match( |
|
296
|
83 |
|
'~multipart/\w+~i', |
|
297
|
83 |
|
$this->getHeaderValue('Content-Type', 'text/plain') |
|
298
|
83 |
|
); |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
/** |
|
302
|
|
|
* Returns true if this part's mime type is text/plain, text/html or has a |
|
303
|
|
|
* text/* and has a defined 'charset' attribute. |
|
304
|
|
|
* |
|
305
|
|
|
* @return bool |
|
306
|
|
|
*/ |
|
307
|
83 |
|
public function isTextPart() |
|
308
|
|
|
{ |
|
309
|
83 |
|
$type = $this->getHeaderValue('Content-Type', 'text/plain'); |
|
310
|
83 |
|
if ($type === 'text/html' || $type === 'text/plain') { |
|
311
|
72 |
|
return true; |
|
312
|
|
|
} |
|
313
|
61 |
|
$charset = $this->getHeaderParameter('Content-Type', 'charset'); |
|
314
|
61 |
|
return ($charset !== null && preg_match( |
|
315
|
4 |
|
'~text/\w+~i', |
|
316
|
4 |
|
$this->getHeaderValue('Content-Type', 'text/plain') |
|
317
|
61 |
|
)); |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
/** |
|
321
|
|
|
* Attaches the resource handle for the part's content. The attached handle |
|
322
|
|
|
* is closed when the MimePart object is destroyed. |
|
323
|
|
|
* |
|
324
|
|
|
* @param resource $contentHandle |
|
325
|
|
|
*/ |
|
326
|
85 |
|
public function attachContentResourceHandle($contentHandle) |
|
327
|
|
|
{ |
|
328
|
85 |
|
if ($this->handle !== null && $this->handle !== $contentHandle) { |
|
329
|
11 |
|
fclose($this->handle); |
|
330
|
11 |
|
} |
|
331
|
85 |
|
$this->handle = $contentHandle; |
|
332
|
85 |
|
} |
|
333
|
|
|
|
|
334
|
|
|
/** |
|
335
|
|
|
* Detaches the content resource handle from this part but does not close |
|
336
|
|
|
* it. |
|
337
|
|
|
*/ |
|
338
|
14 |
|
protected function detachContentResourceHandle() |
|
339
|
|
|
{ |
|
340
|
14 |
|
$this->handle = null; |
|
341
|
14 |
|
} |
|
342
|
|
|
|
|
343
|
|
|
/** |
|
344
|
|
|
* Sets the content of the part to the passed string (effectively creates |
|
345
|
|
|
* a php://temp stream with the passed content and calls |
|
346
|
|
|
* attachContentResourceHandle with the opened stream). |
|
347
|
|
|
* |
|
348
|
|
|
* @param string $string |
|
349
|
|
|
*/ |
|
350
|
9 |
|
public function setContent($string) |
|
351
|
|
|
{ |
|
352
|
9 |
|
$handle = fopen('php://temp', 'r+'); |
|
353
|
9 |
|
fwrite($handle, $string); |
|
354
|
9 |
|
rewind($handle); |
|
355
|
9 |
|
$this->attachContentResourceHandle($handle); |
|
356
|
9 |
|
} |
|
357
|
|
|
|
|
358
|
|
|
/** |
|
359
|
|
|
* Returns the resource stream handle for the part's content or null if not |
|
360
|
|
|
* set. rewind() is called on the stream before returning it. |
|
361
|
|
|
* |
|
362
|
|
|
* The resource is automatically closed by MimePart's destructor and should |
|
363
|
|
|
* not be closed otherwise. |
|
364
|
|
|
* |
|
365
|
|
|
* @return resource |
|
366
|
|
|
*/ |
|
367
|
84 |
|
public function getContentResourceHandle() |
|
368
|
|
|
{ |
|
369
|
84 |
|
if (is_resource($this->handle)) { |
|
370
|
84 |
|
rewind($this->handle); |
|
371
|
84 |
|
} |
|
372
|
84 |
|
return $this->handle; |
|
373
|
|
|
} |
|
374
|
|
|
|
|
375
|
|
|
/** |
|
376
|
|
|
* Shortcut to reading stream content and assigning it to a string. Returns |
|
377
|
|
|
* null if the part doesn't have a content stream. |
|
378
|
|
|
* |
|
379
|
|
|
* @return string |
|
380
|
|
|
*/ |
|
381
|
15 |
|
public function getContent() |
|
382
|
|
|
{ |
|
383
|
15 |
|
if ($this->hasContent()) { |
|
384
|
15 |
|
return stream_get_contents($this->handle); |
|
385
|
|
|
} |
|
386
|
|
|
return null; |
|
387
|
|
|
} |
|
388
|
|
|
|
|
389
|
|
|
/** |
|
390
|
|
|
* Adds a header with the given $name and $value. |
|
391
|
|
|
* |
|
392
|
|
|
* Creates a new \ZBateson\MailMimeParser\Header\AbstractHeader object and |
|
393
|
|
|
* registers it as a header. |
|
394
|
|
|
* |
|
395
|
|
|
* @param string $name |
|
396
|
|
|
* @param string $value |
|
397
|
|
|
*/ |
|
398
|
86 |
|
public function setRawHeader($name, $value) |
|
399
|
|
|
{ |
|
400
|
86 |
|
$this->headers[strtolower($name)] = $this->headerFactory->newInstance($name, $value); |
|
401
|
86 |
|
} |
|
402
|
|
|
|
|
403
|
|
|
/** |
|
404
|
|
|
* Removes the header with the given name |
|
405
|
|
|
* |
|
406
|
|
|
* @param string $name |
|
407
|
|
|
*/ |
|
408
|
8 |
|
public function removeHeader($name) |
|
409
|
|
|
{ |
|
410
|
8 |
|
unset($this->headers[strtolower($name)]); |
|
411
|
8 |
|
} |
|
412
|
|
|
|
|
413
|
|
|
/** |
|
414
|
|
|
* Returns the AbstractHeader object for the header with the given $name |
|
415
|
|
|
* |
|
416
|
|
|
* Note that mime headers aren't case sensitive. |
|
417
|
|
|
* |
|
418
|
|
|
* @param string $name |
|
419
|
|
|
* @return \ZBateson\MailMimeParser\Header\AbstractHeader |
|
420
|
|
|
*/ |
|
421
|
88 |
|
public function getHeader($name) |
|
422
|
|
|
{ |
|
423
|
88 |
|
if (isset($this->headers[strtolower($name)])) { |
|
424
|
86 |
|
return $this->headers[strtolower($name)]; |
|
425
|
|
|
} |
|
426
|
83 |
|
return null; |
|
427
|
|
|
} |
|
428
|
|
|
|
|
429
|
|
|
/** |
|
430
|
|
|
* Returns the string value for the header with the given $name. |
|
431
|
|
|
* |
|
432
|
|
|
* Note that mime headers aren't case sensitive. |
|
433
|
|
|
* |
|
434
|
|
|
* @param string $name |
|
435
|
|
|
* @param string $defaultValue |
|
436
|
|
|
* @return string |
|
437
|
|
|
*/ |
|
438
|
85 |
|
public function getHeaderValue($name, $defaultValue = null) |
|
439
|
|
|
{ |
|
440
|
85 |
|
$header = $this->getHeader($name); |
|
441
|
85 |
|
if ($header !== null) { |
|
442
|
84 |
|
return $header->getValue(); |
|
443
|
|
|
} |
|
444
|
82 |
|
return $defaultValue; |
|
445
|
|
|
} |
|
446
|
|
|
|
|
447
|
|
|
/** |
|
448
|
|
|
* Returns the full array of headers for this part. |
|
449
|
|
|
* |
|
450
|
|
|
* @return \ZBateson\MailMimeParser\Header\AbstractHeader[] |
|
451
|
|
|
*/ |
|
452
|
81 |
|
public function getHeaders() |
|
453
|
|
|
{ |
|
454
|
81 |
|
return $this->headers; |
|
455
|
|
|
} |
|
456
|
|
|
|
|
457
|
|
|
/** |
|
458
|
|
|
* Returns a parameter of the header $header, given the parameter named |
|
459
|
|
|
* $param. |
|
460
|
|
|
* |
|
461
|
|
|
* Only headers of type |
|
462
|
|
|
* \ZBateson\MailMimeParser\Header\ParameterHeader have parameters. |
|
463
|
|
|
* Content-Type and Content-Disposition are examples of headers with |
|
464
|
|
|
* parameters. "Charset" is a common parameter of Content-Type. |
|
465
|
|
|
* |
|
466
|
|
|
* @param string $header |
|
467
|
|
|
* @param string $param |
|
468
|
|
|
* @param string $defaultValue |
|
469
|
|
|
* @return string |
|
470
|
|
|
*/ |
|
471
|
85 |
|
public function getHeaderParameter($header, $param, $defaultValue = null) |
|
472
|
|
|
{ |
|
473
|
85 |
|
$obj = $this->getHeader($header); |
|
474
|
85 |
|
if ($obj && $obj instanceof ParameterHeader) { |
|
475
|
84 |
|
return $obj->getValueFor($param, $defaultValue); |
|
476
|
|
|
} |
|
477
|
7 |
|
return $defaultValue; |
|
478
|
|
|
} |
|
479
|
|
|
|
|
480
|
|
|
/** |
|
481
|
|
|
* Sets the parent part. |
|
482
|
|
|
* |
|
483
|
|
|
* @param \ZBateson\MailMimeParser\Message\MimePart $part |
|
484
|
|
|
*/ |
|
485
|
82 |
|
public function setParent(MimePart $part) |
|
486
|
|
|
{ |
|
487
|
82 |
|
$this->parent = $part; |
|
488
|
82 |
|
} |
|
489
|
|
|
|
|
490
|
|
|
/** |
|
491
|
|
|
* Returns this part's parent. |
|
492
|
|
|
* |
|
493
|
|
|
* @return \ZBateson\MailMimeParser\Message\MimePart |
|
494
|
|
|
*/ |
|
495
|
84 |
|
public function getParent() |
|
496
|
|
|
{ |
|
497
|
84 |
|
return $this->parent; |
|
498
|
|
|
} |
|
499
|
|
|
} |
|
500
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.