Passed
Push — master ( 46ed75...ca2387 )
by Zaahid
03:33
created

AbstractGenericConsumerService   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 21
eloc 40
c 1
b 0
f 0
dl 0
loc 145
ccs 45
cts 45
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getTokenSeparators() 0 3 1
A filterIgnoredSpaces() 0 17 3
A addSpaceToRetParts() 0 8 2
A addSpaces() 0 7 5
A processParts() 0 18 4
A isSpaceToken() 0 3 2
A isEndToken() 0 3 1
A shouldAddSpace() 0 3 2
A isStartToken() 0 3 1
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
8
namespace ZBateson\MailMimeParser\Header\Consumer;
9
10
use ZBateson\MailMimeParser\Header\Part\CommentPart;
11
use ZBateson\MailMimeParser\Header\Part\HeaderPart;
12
use ZBateson\MailMimeParser\Header\Part\Token;
13
14
/**
15
 * A minimal implementation of AbstractConsumerService splitting tokens by
16
 * whitespace.
17
 *
18
 * Although the class doesn't have any abstract methods, it's defined as
19
 * abstract because it doesn't define specific sub-consumers as constructor
20
 * dependencies, and so is defined as abstract to avoid its direct use (use
21
 * the concrete GenericConsumerService or GenericConsumerMimeLiteralPartService
22
 * classes instead).
23
 *
24
 * @author Zaahid Bateson
25
 */
26
abstract class AbstractGenericConsumerService extends AbstractConsumerService
27
{
28
    /**
29
     * Returns the regex '\s+' (whitespace) pattern matcher as a token marker so
30
     * the header value is split along whitespace characters.
31
     *
32
     * @return string[] an array of regex pattern matchers
33
     */
34 1
    protected function getTokenSeparators() : array
35
    {
36 1
        return ['\s+'];
37
    }
38
39
    /**
40
     * AbstractGenericConsumerService doesn't have start/end tokens, and so
41
     * always returns false.
42
     */
43 105
    protected function isEndToken(string $token) : bool
44
    {
45 105
        return false;
46
    }
47
48
    /**
49
     * AbstractGenericConsumerService doesn't have start/end tokens, and so
50
     * always returns false.
51
     *
52
     * @codeCoverageIgnore
53
     */
54
    protected function isStartToken(string $token) : bool
55
    {
56
        return false;
57
    }
58
59
    /**
60
     * Returns true if a space should be added based on the passed last and next
61
     * parts.
62
     *
63
     */
64 74
    private function shouldAddSpace(HeaderPart $nextPart, HeaderPart $lastPart) : bool
65
    {
66 74
        return (!$lastPart->ignoreSpacesAfter() || !$nextPart->ignoreSpacesBefore());
67
    }
68
69
    /**
70
     * Loops over the $parts array from the current position, checks if the
71
     * space should be added, then adds it to $retParts and returns.
72
     *
73
     * @param HeaderPart[] $parts
74
     * @param HeaderPart[] $retParts
75
     */
76 74
    private function addSpaceToRetParts(array $parts, array &$retParts, int $curIndex, HeaderPart &$spacePart, HeaderPart $lastPart) : static
77
    {
78 74
        $nextPart = $parts[$curIndex];
79 74
        if ($this->shouldAddSpace($nextPart, $lastPart)) {
80 74
            $retParts[] = $spacePart;
81 74
            $spacePart = null;
82
        }
83 74
        return $this;
84
    }
85
86
    /**
87
     * Checks if the passed space part should be added to the returned parts and
88
     * adds it.
89
     *
90
     * Never adds a space if it's the first part, otherwise only add it if
91
     * either part isn't set to ignore the space
92
     *
93
     * @param HeaderPart[] $parts
94
     * @param HeaderPart[] $retParts
95
     */
96 105
    private function addSpaces(array $parts, array &$retParts, int $curIndex, ?HeaderPart &$spacePart = null) : static
97
    {
98 105
        $lastPart = \end($retParts);
99 105
        if ($spacePart !== null && $curIndex < \count($parts) && $parts[$curIndex]->getValue() !== '' && $lastPart !== false) {
100 74
            $this->addSpaceToRetParts($parts, $retParts, $curIndex, $spacePart, $lastPart);
101
        }
102 105
        return $this;
103
    }
104
105
    /**
106
     * Returns true if the passed HeaderPart is a Token instance and a space.
107
     *
108
     */
109 105
    private function isSpaceToken(HeaderPart $part) : bool
110
    {
111 105
        return ($part instanceof Token && $part->isSpace());
112
    }
113
114
    /**
115
     * Filters out ignorable spaces between parts in the passed array.
116
     *
117
     * Spaces with parts on either side of it that specify they can be ignored
118
     * are filtered out.  filterIgnoredSpaces is called from within
119
     * processParts, and if needed by an implementing class that overrides
120
     * processParts, must be specifically called.
121
     *
122
     * @param HeaderPart[] $parts
123
     * @return HeaderPart[]
124
     */
125 105
    protected function filterIgnoredSpaces(array $parts)
126
    {
127 105
        $partsFiltered = \array_values(\array_filter($parts));
128 105
        $retParts = [];
129 105
        $spacePart = null;
130 105
        $count = \count($partsFiltered);
131 105
        for ($i = 0; $i < $count; ++$i) {
132 105
            $part = $partsFiltered[$i];
133 105
            if ($this->isSpaceToken($part)) {
134 74
                $spacePart = $part;
135 74
                continue;
136
            }
137 105
            $this->addSpaces($partsFiltered, $retParts, $i, $spacePart);
138 105
            $retParts[] = $part;
139
        }
140
        // ignore trailing spaces
141 105
        return $retParts;
142
    }
143
144
    /**
145
     * Overridden to combine all part values into a single string and return it
146
     * as an array with a single element.
147
     *
148
     * The returned IHeaderParts are all LiteralParts.
149
     *
150
     * @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
151
     * @return \ZBateson\MailMimeParser\Header\IHeaderPart[]
152
     */
153 95
    protected function processParts(array $parts) : array
154
    {
155 95
        $ret = [];
156 95
        $runningValue = '';
157 95
        $filtered = $this->filterIgnoredSpaces($parts);
158 95
        foreach ($filtered as $part) {
159 95
            if ($part instanceof CommentPart) {
160 14
                $ret[] = $this->partFactory->newLiteralPart($runningValue);
161 14
                $runningValue = '';
162 14
                $ret[] = $part;
163
            } else {
164 95
                $runningValue .= $part->getValue();
165
            }
166
        }
167 95
        if (!empty($runningValue)) {
168 95
            $ret[] = $this->partFactory->newLiteralPart($runningValue);
169
        }
170 95
        return $ret;
171
    }
172
}
173