Passed
Push — 1.0.0 ( 5c7ec9...fcaf32 )
by Zaahid
03:19
created

ParameterConsumer::addToSplitPart()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 5
crap 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\Header\Consumer;
8
9
use ZBateson\MailMimeParser\Header\Part\Token;
10
use ZBateson\MailMimeParser\Header\Part\SplitParameterToken;
11
use ArrayObject;
12
13
/**
14
 * Reads headers separated into parameters consisting of a main value, and
15
 * subsequent name/value pairs - for example text/html; charset=utf-8.
16
 * 
17
 * A ParameterConsumer's parts are separated by a semi-colon.  Its name/value
18
 * pairs are separated with an '=' character.
19
 * 
20
 * Parts may be mime-encoded entities.  Additionally, a value can be quoted and
21
 * comments may exist.
22
 * 
23
 * @author Zaahid Bateson
24
 */
25
class ParameterConsumer extends GenericConsumer
26
{
27
    /**
28
     * Returns semi-colon and equals char as token separators.
29
     * 
30
     * @return string[]
31
     */
32 9
    protected function getTokenSeparators()
33
    {
34 9
        return [';', '='];
35
    }
36
    
37
    /**
38
     * Creates and returns a \ZBateson\MailMimeParser\Header\Part\Token out of
39
     * the passed string token and returns it, unless the token is an escaped
40
     * literal, in which case a LiteralPart is returned.
41
     * 
42
     * @param string $token
43
     * @param bool $isLiteral
44
     * @return \ZBateson\MailMimeParser\Header\Part\HeaderPart
45
     */
46 9
    protected function getPartForToken($token, $isLiteral)
47
    {
48 9
        if ($isLiteral) {
49 1
            return $this->partFactory->newLiteralPart($token);
50
        }
51 9
        return $this->partFactory->newToken($token);
52
    }
53
    
54
    /**
55
     * Adds the passed parameter with the given name and value to a
56
     * SplitParameterToken, at the passed index. If one with the given name
57
     * doesn't exist, it is created.
58
     * 
59
     * @param ArrayObject $splitParts
60
     * @param string $name
61
     * @param string $value
62
     * @param int $index
63
     * @param boolean $isEncoded
64
     */
65 6
    private function addToSplitPart(ArrayObject $splitParts, $name, $value, $index, $isEncoded)
66
    {
67 6
        $ret = null;
68 6
        if (!isset($splitParts[trim($name)])) {
69 6
            $ret = $this->partFactory->newSplitParameterToken($name);
70 6
            $splitParts[$name] = $ret;
71 6
        }
72 6
        $splitParts[$name]->addPart($value, $isEncoded, $index);
73 6
        return $ret;
74
    }
75
    
76
    /**
77
     * Instantiates and returns either a MimeLiteralPart if $strName is empty,
78
     * a SplitParameterToken if the parameter is a split parameter and is the
79
     * first in a series, null if it's a split parameter but is not the first
80
     * part in its series, or a ParameterPart is returned otherwise.
81
     * 
82
     * If the part is a SplitParameterToken, it's added to the passed
83
     * $splitParts as well with its name as a key.
84
     * 
85
     * @param string $strName
86
     * @param string $strValue
87
     * @param ArrayObject $splitParts
88
     * @return MimeLiteralPart|SplitParameterToken|ParameterPart
89
     */
90 9
    private function getPartFor($strName, $strValue, ArrayObject $splitParts)
91
    {
92 9
        if ($strName === '') {
93 9
            return $this->partFactory->newMimeLiteralPart($strValue);
94 9
        } elseif (preg_match('~^\s*([^\*]+)\*(\d*)(\*)?$~', $strName, $matches)) {
95 6
            return $this->addToSplitPart(
96 6
                $splitParts,
97 6
                $matches[1],
98 6
                $strValue,
99 6
                $matches[2],
100 6
                (empty($matches[2]) || !empty($matches[3]))
101 6
            );
102
        }
103 3
        return $this->partFactory->newParameterPart($strName, $strValue);
104
    }
105
106
    /**
107
     * Handles parameter separator tokens during final processing.
108
     * 
109
     * If the end token is found, a new HeaderPart is assigned to the passed
110
     * $combined array.  If an '=' character is found, $strCat is assigned to
111
     * $strName and emptied.
112
     * 
113
     * Returns true if the token was processed, and false otherwise.
114
     * 
115
     * @param string $tokenValue
116
     * @param array $combined
117
     * @param string $strName
118
     * @param string $strCat
119
     * @return boolean
120
     */
121 9
    private function processTokenPart(
122
        $tokenValue,
123
        ArrayObject $combined,
124
        ArrayObject $splitParts,
125
        &$strName,
126
        &$strCat
127
    ) {
128 9
        if ($tokenValue === ';') {
129 9
            $combined[] = $this->getPartFor($strName, $strCat, $splitParts);
130 9
            $strName = '';
131 9
            $strCat = '';
132 9
            return true;
133 9
        } elseif ($tokenValue === '=') {
134 9
            $strName = $strCat;
135 9
            $strCat = '';
136 9
            return true;
137
        }
138 9
        return false;
139
    }
140
    
141
    /**
142
     * Loops over parts in the passed array, creating ParameterParts out of any
143
     * parsed SplitParameterTokens, replacing them in the array.
144
     * 
145
     * The method then calls filterIgnoreSpaces to filter out empty elements in
146
     * the combined array and returns an array.
147
     * 
148
     * @param ArrayObject $combined
149
     * @return HeaderPart[]|array
150
     */
151 9
    private function finalizeParameterParts(ArrayObject $combined)
152
    {
153 9
        foreach ($combined as $key => $part) {
154 9
            if ($part instanceof SplitParameterToken) {
155 6
                $combined[$key] = $this->partFactory->newParameterPart(
156 6
                    $part->getName(),
157 6
                    $part->getValue(),
158 6
                    $part->getLanguage()
159 6
                );
160 6
            }
161 9
        }
162 9
        return $this->filterIgnoredSpaces($combined->getArrayCopy());
163
    }
164
    
165
    /**
166
     * Post processing involves creating Part\LiteralPart or Part\ParameterPart
167
     * objects out of created Token and LiteralParts.
168
     * 
169
     * @param HeaderPart[] $parts
170
     * @return HeaderPart[]|array
171
     */
172 9
    protected function processParts(array $parts)
173
    {
174 9
        $combined = new ArrayObject();
175 9
        $splitParts = new ArrayObject();
176 9
        $strCat = '';
177 9
        $strName = '';
178 9
        $parts[] = $this->partFactory->newToken(';');
179 9
        foreach ($parts as $part) {
180 9
            $pValue = $part->getValue();
181 9
            if ($part instanceof Token && $this->processTokenPart($pValue, $combined, $splitParts, $strName, $strCat)) {
182 9
                continue;
183
            }
184 9
            $strCat .= $pValue;
185 9
        }
186 9
        return $this->finalizeParameterParts($combined);
187
    }
188
}
189