Completed
Push — master ( c7cf7f...702f4a )
by Zaahid
02:37
created

GenericConsumer::addSpaces()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 16
rs 8.8571
cc 5
eloc 11
nc 4
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 $lastPart
82
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $nextPart
83
     * @return bool
84
     */
85
    private function shouldAddSpace(HeaderPart $lastPart, HeaderPart $nextPart)
86
    {
87
        return ($lastPart !== null && (!$lastPart->ignoreSpacesAfter() || !$nextPart->ignoreSpacesBefore()));
88
    }
89
    
90
    /**
91
     * Checks if the passed space part should be added to the returned parts and
92
     * adds it.
93
     * 
94
     * Never adds a space if it's the first part, otherwise only add it if
95
     * either part isn't set to ignore the space
96
     * 
97
     * @param array $parts
98
     * @param array $retParts
99
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart $spacePart
100
     * @param int $curIndex
101
     */
102
    private function addSpaces(array $parts, array &$retParts, &$spacePart, $curIndex)
103
    {
104
        if ($spacePart === null || $parts[$curIndex]->getValue() === '') {
105
            return;
106
        }
107
        $lastPart = end($retParts);
108
        $count = count($parts);
109
        for ($j = $curIndex; $j < $count; ++$j) {
110
            $nextPart = $parts[$j];
111
            if ($this->shouldAddSpace($lastPart, $nextPart)) {
112
                $retParts[] = $spacePart;
113
                $spacePart = null;
114
                break;
115
            }
116
        }
117
    }
118
    
119
    /**
120
     * 
121
     * @param HeaderPart $part
122
     * @return type
123
     */
124
    private function isSpaceToken(HeaderPart $part)
125
    {
126
        return ($part instanceof Token && $part->isSpace());
127
    }
128
    
129
    /**
130
     * Filters out ignorable spaces between parts in the passed array.
131
     * 
132
     * Spaces with parts on either side of it that specify they can be ignored
133
     * are filtered out.  filterIgnoredSpaces is called from within
134
     * processParts, and if needed by an implementing class that overrides
135
     * processParts, must be specifically called.
136
     * 
137
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
138
     * @return \ZBateson\MailMimeParser\Header\Part\HeaderPart[]
139
     */
140
    protected function filterIgnoredSpaces(array $parts)
141
    {
142
        $retParts = [];
143
        $spacePart = null;
144
        $count = count($parts);
145
        for ($i = 0; $i < $count; ++$i) {
146
            $part = $parts[$i];
147
            if ($this->isSpaceToken($part)) {
148
                $spacePart = $part;
149
                continue;
150
            }
151
            $this->addSpaces($parts, $retParts, $spacePart, $i);
0 ignored issues
show
Bug introduced by
It seems like $spacePart defined by null on line 143 can be null; however, ZBateson\MailMimeParser\...icConsumer::addSpaces() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
152
            $retParts[] = $part;
153
        }
154
        // ignore trailing spaces
155
        return $retParts;
156
    }
157
    
158
    /**
159
     * Overridden to combine all part values into a single string and return it
160
     * as an array with a single element.
161
     * 
162
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
163
     * @return \ZBateson\MailMimeParser\Header\Part\LiteralPart[]|array
164
     */
165
    protected function processParts(array $parts)
166
    {
167
        $strValue = '';
168
        $filtered = $this->filterIgnoredSpaces($parts);
169
        foreach ($filtered as $part) {
170
            $strValue .= $part->getValue();
171
        }
172
        return [$this->partFactory->newLiteralPart($strValue)];
173
    }
174
}
175