|
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\Header\Consumer; |
|
8
|
|
|
|
|
9
|
|
|
use ZBateson\MailMimeParser\Header\Part\Token; |
|
10
|
|
|
|
|
11
|
|
|
/** |
|
12
|
|
|
* A minimal implementation of AbstractConsumer defining a CommentConsumer and |
|
13
|
|
|
* QuotedStringConsumer as sub-consumers, and splitting tokens by whitespace. |
|
14
|
|
|
* |
|
15
|
|
|
* Note that GenericConsumer should be instantiated with a |
|
16
|
|
|
* MimeLiteralPartFactory instead of a HeaderPartFactory. Sub-classes may not |
|
17
|
|
|
* need MimeLiteralPartFactory instances though. |
|
18
|
|
|
* |
|
19
|
|
|
* @author Zaahid Bateson |
|
20
|
|
|
*/ |
|
21
|
|
|
class GenericConsumer extends AbstractConsumer |
|
22
|
|
|
{ |
|
23
|
|
|
/** |
|
24
|
|
|
* Returns \ZBateson\MailMimeParser\Header\Consumer\CommentConsumer and |
|
25
|
|
|
* \ZBateson\MailMimeParser\Header\Consumer\QuotedStringConsumer as |
|
26
|
|
|
* sub-consumers. |
|
27
|
|
|
* |
|
28
|
|
|
* @return AbstractConsumer[] the sub-consumers |
|
29
|
|
|
*/ |
|
30
|
|
|
protected function getSubConsumers() |
|
31
|
|
|
{ |
|
32
|
|
|
return [ |
|
33
|
|
|
$this->consumerService->getCommentConsumer(), |
|
34
|
|
|
$this->consumerService->getQuotedStringConsumer(), |
|
35
|
|
|
]; |
|
36
|
|
|
} |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* Returns the regex '\s+' (whitespace) pattern matcher as a token marker so |
|
40
|
|
|
* the header value is split along whitespace characters. GenericConsumer |
|
41
|
|
|
* filters out whitespace-only tokens from getPartForToken. |
|
42
|
|
|
* |
|
43
|
|
|
* The whitespace character delimits mime-encoded parts for decoding. |
|
44
|
|
|
* |
|
45
|
|
|
* @return string[] an array of regex pattern matchers |
|
46
|
|
|
*/ |
|
47
|
|
|
protected function getTokenSeparators() |
|
48
|
|
|
{ |
|
49
|
|
|
return ['\s+']; |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* GenericConsumer doesn't have start/end tokens, and so always returns |
|
54
|
|
|
* false. |
|
55
|
|
|
* |
|
56
|
|
|
* @param string $token |
|
57
|
|
|
* @return boolean false |
|
58
|
|
|
*/ |
|
59
|
|
|
protected function isEndToken($token) |
|
60
|
|
|
{ |
|
61
|
|
|
return false; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* GenericConsumer doesn't have start/end tokens, and so always returns |
|
66
|
|
|
* false. |
|
67
|
|
|
* |
|
68
|
|
|
* @param string $token |
|
69
|
|
|
* @return boolean false |
|
70
|
|
|
*/ |
|
71
|
|
|
protected function isStartToken($token) |
|
72
|
|
|
{ |
|
73
|
|
|
return false; |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* Checks if the passed space part should be added to the returned parts and |
|
78
|
|
|
* adds it. |
|
79
|
|
|
* |
|
80
|
|
|
* Never adds a space if it's the first part, otherwise only add it if |
|
81
|
|
|
* either part isn't set to ignore the space |
|
82
|
|
|
* |
|
83
|
|
|
* @param array $parts |
|
84
|
|
|
* @param array $retParts |
|
85
|
|
|
* @param ZBateson\MailMimeParser\Header\Part\HeaderPart $spacePart |
|
86
|
|
|
* @param int $curIndex |
|
87
|
|
|
* @return boolean true if the part was added |
|
88
|
|
|
*/ |
|
89
|
|
|
private function checkAddFilteredSpace(array $parts, array &$retParts, &$spacePart, $curIndex) |
|
90
|
|
|
{ |
|
91
|
|
|
$lastPart = end($retParts); |
|
92
|
|
|
$count = count($parts); |
|
93
|
|
|
for ($j = $curIndex; $j < $count; ++$j) { |
|
94
|
|
|
$next = $parts[$j]; |
|
95
|
|
|
if ($lastPart !== null && (!$lastPart->ignoreSpacesAfter() || !$next->ignoreSpacesBefore())) { |
|
96
|
|
|
$retParts[] = $spacePart; |
|
97
|
|
|
$spacePart = null; |
|
98
|
|
|
return true; |
|
99
|
|
|
} |
|
100
|
|
|
} |
|
101
|
|
|
return false; |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Filters out ignorable spaces between parts in the passed array. |
|
106
|
|
|
* |
|
107
|
|
|
* Spaces with parts on either side of it that specify they can be ignored |
|
108
|
|
|
* are filtered out. filterIgnoredSpaces is called from within |
|
109
|
|
|
* processParts, and if needed by an implementing class that overrides |
|
110
|
|
|
* processParts, must be specifically called. |
|
111
|
|
|
* |
|
112
|
|
|
* @param ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts |
|
113
|
|
|
* @return ZBateson\MailMimeParser\Header\Part\HeaderPart[] |
|
114
|
|
|
*/ |
|
115
|
|
|
protected function filterIgnoredSpaces(array $parts) |
|
116
|
|
|
{ |
|
117
|
|
|
$retParts = []; |
|
118
|
|
|
$spacePart = null; |
|
119
|
|
|
$count = count($parts); |
|
120
|
|
|
for ($i = 0; $i < $count; ++$i) { |
|
121
|
|
|
$part = $parts[$i]; |
|
122
|
|
|
if ($part instanceof Token && $part->isSpace()) { |
|
123
|
|
|
$spacePart = $part; |
|
124
|
|
|
continue; |
|
125
|
|
|
} elseif ($spacePart !== null && $part->getValue() !== '') { |
|
126
|
|
|
$this->checkAddFilteredSpace($parts, $retParts, $spacePart, $i); |
|
127
|
|
|
} |
|
128
|
|
|
$retParts[] = $part; |
|
129
|
|
|
} |
|
130
|
|
|
// ignore trailing spaces |
|
131
|
|
|
return $retParts; |
|
132
|
|
|
} |
|
133
|
|
|
|
|
134
|
|
|
/** |
|
135
|
|
|
* Overridden to combine all part values into a single string and return it |
|
136
|
|
|
* as an array with a single element. |
|
137
|
|
|
* |
|
138
|
|
|
* @param ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts |
|
139
|
|
|
* @return ZBateson\MailMimeParser\Header\Part\LiteralPart[] |
|
140
|
|
|
*/ |
|
141
|
|
|
protected function processParts(array $parts) |
|
142
|
|
|
{ |
|
143
|
|
|
$strValue = ''; |
|
144
|
|
|
$filtered = $this->filterIgnoredSpaces($parts); |
|
145
|
|
|
foreach ($filtered as $part) { |
|
146
|
|
|
$strValue .= $part->getValue(); |
|
147
|
|
|
} |
|
148
|
|
|
return [$this->partFactory->newLiteralPart($strValue)]; |
|
|
|
|
|
|
149
|
|
|
} |
|
150
|
|
|
} |
|
151
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.