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

GenericReceivedConsumerService::processParts()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 14
ccs 11
cts 11
cp 1
rs 9.9332
cc 3
nc 3
nop 1
crap 3
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\Received;
9
10
use ZBateson\MailMimeParser\Header\Consumer\AbstractGenericConsumerService;
11
use ZBateson\MailMimeParser\Header\Consumer\CommentConsumerService;
12
use ZBateson\MailMimeParser\Header\Part\CommentPart;
13
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
14
15
/**
16
 * Consumes simple literal strings for parts of a Received header.
17
 *
18
 * Starts consuming when the initialized $partName string is located, for
19
 * instance when initialized with "FROM", will start consuming on " FROM" or
20
 * "FROM ".
21
 *
22
 * The consumer ends when any possible "Received" header part is found, namely
23
 * on one of the following tokens: from, by, via, with, id, for, or when the
24
 * start token for the date stamp is found, ';'.
25
 *
26
 * The consumer allows comments in and around the consumer... although the
27
 * Received header specification only allows them before a part, for example,
28
 * technically speaking this is valid:
29
 *
30
 * "FROM machine (host) (comment) BY machine"
31
 *
32
 * However, this is not:
33
 *
34
 * "FROM machine (host) BY machine WITH (comment) ESMTP"
35
 *
36
 * The consumer will allow both.
37
 *
38
 * @author Zaahid Bateson
39
 */
40
class GenericReceivedConsumerService extends AbstractGenericConsumerService
41
{
42
    /**
43
     * @var string the current part name being parsed.
44
     *
45
     * This is always the lower-case name provided to the constructor, not the
46
     * actual string that started the consumer, which could be in any case.
47
     */
48
    protected $partName;
49
50
    /**
51
     * Constructor overridden to include $partName parameter.
52
     *
53
     */
54 16
    public function __construct(
55
        HeaderPartFactory $partFactory,
56
        CommentConsumerService $commentConsumerService,
57
        string $partName
58
    ) {
59 16
        parent::__construct($partFactory, [ $commentConsumerService ]);
60 16
        $this->partName = $partName;
61
    }
62
63
    /**
64
     * Returns true if the passed token matches (case-insensitively)
65
     * $this->getPartName() with optional whitespace surrounding it.
66
     */
67 11
    protected function isStartToken(string $token) : bool
68
    {
69 11
        $pattern = '/^' . \preg_quote($this->partName, '/') . '$/i';
70 11
        return (\preg_match($pattern, $token) === 1);
71
    }
72
73
    /**
74
     * Returns true if the token matches (case-insensitively) any of the
75
     * following, with optional surrounding whitespace:
76
     *
77
     * o by
78
     * o via
79
     * o with
80
     * o id
81
     * o for
82
     * o ;
83
     */
84 14
    protected function isEndToken(string $token) : bool
85
    {
86 14
        return (\preg_match('/^(by|via|with|id|for|;)$/i', $token) === 1);
87
    }
88
89
    /**
90
     * Returns a whitespace separator (for filtering ignorable whitespace
91
     * between parts), and a separator matching the current part name as
92
     * set on $this->partName.
93
     *
94
     * @return string[] an array of regex pattern matchers
95
     */
96 16
    protected function getTokenSeparators() : array
97
    {
98 16
        return [
99 16
            '\s+',
100 16
            '(\A\s*|\s+)(?i)' . \preg_quote($this->partName, '/') . '(?-i)(?=\s+)'
101 16
        ];
102
    }
103
104
    /**
105
     * Overridden to combine all part values into a single string and return it
106
     * as the first element, followed by any comment elements as subsequent
107
     * elements.
108
     *
109
     * @param \ZBateson\MailMimeParser\Header\Part\IHeaderPart[] $parts
110
     * @return \ZBateson\MailMimeParser\Header\Part\IHeaderPart[]
111
     */
112 10
    protected function processParts(array $parts) : array
113
    {
114 10
        $strValue = '';
115 10
        $ret = [];
116 10
        $filtered = $this->filterIgnoredSpaces($parts);
117 10
        foreach ($filtered as $part) {
118 10
            if ($part instanceof CommentPart) {
119 6
                $ret[] = $part;
120 6
                continue;    // getValue() is empty anyway, but for clarity...
121
            }
122 10
            $strValue .= $part->getValue();
123
        }
124 10
        \array_unshift($ret, $this->partFactory->newReceivedPart($this->partName, $strValue));
125 10
        return $ret;
126
    }
127
}
128