Completed
Push — master ( b5b205...8ece8a )
by Zaahid
02:24
created

GenericConsumer::addSpaces()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 7
rs 9.2
cc 4
eloc 4
nc 2
nop 4
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\HeaderPart;
10
use ZBateson\MailMimeParser\Header\Part\Token;
11
12
/**
13
 * A minimal implementation of AbstractConsumer defining a CommentConsumer and
14
 * QuotedStringConsumer as sub-consumers, and splitting tokens by whitespace.
15
 *
16
 * Note that GenericConsumer should be instantiated with a
17
 * MimeLiteralPartFactory instead of a HeaderPartFactory.  Sub-classes may not
18
 * need MimeLiteralPartFactory instances though.
19
 * 
20
 * @author Zaahid Bateson
21
 */
22
class GenericConsumer extends AbstractConsumer
23
{
24
    /**
25
     * Returns \ZBateson\MailMimeParser\Header\Consumer\CommentConsumer and
26
     * \ZBateson\MailMimeParser\Header\Consumer\QuotedStringConsumer as
27
     * sub-consumers.
28
     * 
29
     * @return AbstractConsumer[] the sub-consumers
30
     */
31
    protected function getSubConsumers()
32
    {
33
        return [
34
            $this->consumerService->getCommentConsumer(),
35
            $this->consumerService->getQuotedStringConsumer(),
36
        ];
37
    }
38
    
39
    /**
40
     * Returns the regex '\s+' (whitespace) pattern matcher as a token marker so
41
     * the header value is split along whitespace characters.  GenericConsumer
42
     * filters out whitespace-only tokens from getPartForToken.
43
     * 
44
     * The whitespace character delimits mime-encoded parts for decoding.
45
     * 
46
     * @return string[] an array of regex pattern matchers
47
     */
48
    protected function getTokenSeparators()
49
    {
50
        return ['\s+'];
51
    }
52
    
53
    /**
54
     * GenericConsumer doesn't have start/end tokens, and so always returns
55
     * false.
56
     * 
57
     * @param string $token
58
     * @return boolean false
59
     */
60
    protected function isEndToken($token)
61
    {
62
        return false;
63
    }
64
    
65
    /**
66
     * GenericConsumer doesn't have start/end tokens, and so always returns
67
     * false.
68
     * 
69
     * @param string $token
70
     * @return boolean false
71
     */
72
    protected function isStartToken($token)
73
    {
74
        return false;
75
    }
76
    
77
    /**
78
     * Returns true if a space should be added based on the passed last and next
79
     * parts.
80
     * 
81
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $nextPart
82
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $lastPart
83
     * @return bool
84
     */
85
    private function shouldAddSpace(HeaderPart $nextPart, HeaderPart $lastPart)
86
    {
87
        return (!$lastPart->ignoreSpacesAfter() || !$nextPart->ignoreSpacesBefore());
88
    }
89
    
90
    /**
91
     * Loops over the $parts array from the current position, checks if the
92
     * space should be added, then adds it to $retParts and returns.
93
     * 
94
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
95
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $retParts
96
     * @param int $curIndex
97
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $spacePart
98
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $lastPart
99
     */
100
    private function addSpaceToRetParts(
101
        array $parts,
102
        array &$retParts,
103
        $curIndex,
104
        HeaderPart &$spacePart,
105
        HeaderPart $lastPart
106
    ) {
107
        $count = count($parts);
108
        for ($j = $curIndex; $j < $count; ++$j) {
109
            $nextPart = $parts[$j];
110
            if ($this->shouldAddSpace($nextPart, $lastPart)) {
111
                $retParts[] = $spacePart;
112
                $spacePart = null;
113
                break;
114
            }
115
        }
116
    }
117
    
118
    /**
119
     * Checks if the passed space part should be added to the returned parts and
120
     * adds it.
121
     * 
122
     * Never adds a space if it's the first part, otherwise only add it if
123
     * either part isn't set to ignore the space
124
     * 
125
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
126
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $retParts
127
     * @param int $curIndex
128
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $spacePart
129
     */
130
    private function addSpaces(array $parts, array &$retParts, $curIndex, HeaderPart &$spacePart = null)
131
    {
132
        $lastPart = end($retParts);
133
        if ($spacePart !== null && $parts[$curIndex]->getValue() !== '' && $lastPart !== false) {
134
            $this->addSpaceToRetParts($parts, $retParts, $curIndex, $spacePart, $lastPart);
135
        }
136
    }
137
    
138
    /**
139
     * Returns true if the passed HeaderPart is a Token instance and a space.
140
     * 
141
     * @param HeaderPart $part
142
     * @return bool
143
     */
144
    private function isSpaceToken(HeaderPart $part)
145
    {
146
        return ($part instanceof Token && $part->isSpace());
147
    }
148
    
149
    /**
150
     * Filters out ignorable spaces between parts in the passed array.
151
     * 
152
     * Spaces with parts on either side of it that specify they can be ignored
153
     * are filtered out.  filterIgnoredSpaces is called from within
154
     * processParts, and if needed by an implementing class that overrides
155
     * processParts, must be specifically called.
156
     * 
157
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
158
     * @return \ZBateson\MailMimeParser\Header\Part\HeaderPart[]
159
     */
160
    protected function filterIgnoredSpaces(array $parts)
161
    {
162
        $retParts = [];
163
        $spacePart = null;
164
        $count = count($parts);
165
        for ($i = 0; $i < $count; ++$i) {
166
            $part = $parts[$i];
167
            if ($this->isSpaceToken($part)) {
168
                $spacePart = $part;
169
                continue;
170
            }
171
            $this->addSpaces($parts, $retParts, $i, $spacePart);
172
            $retParts[] = $part;
173
        }
174
        // ignore trailing spaces
175
        return $retParts;
176
    }
177
    
178
    /**
179
     * Overridden to combine all part values into a single string and return it
180
     * as an array with a single element.
181
     * 
182
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
183
     * @return \ZBateson\MailMimeParser\Header\Part\LiteralPart[]|array
184
     */
185
    protected function processParts(array $parts)
186
    {
187
        $strValue = '';
188
        $filtered = $this->filterIgnoredSpaces($parts);
189
        foreach ($filtered as $part) {
190
            $strValue .= $part->getValue();
191
        }
192
        return [$this->partFactory->newLiteralPart($strValue)];
193
    }
194
}
195