Test Failed
Push — master ( 66d82e...4ebaf8 )
by Zaahid
03:17
created

GenericReceivedConsumer   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 22
dl 0
loc 115
rs 10
c 0
b 0
f 0
wmc 9

7 Methods

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