Passed
Push — 1.0.0 ( 4505d9...06b3ad )
by Zaahid
04:10
created

AddressConsumer   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 12
dl 0
loc 112
ccs 31
cts 31
cp 1
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubConsumers() 0 6 1
A processParts() 0 16 3
A isStartToken() 0 3 1
A getTokenSeparators() 0 3 1
A isEndToken() 0 3 2
A processSinglePart() 0 13 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
use ZBateson\MailMimeParser\Header\Part\AddressGroupPart;
12
13
/**
14
 * Parses a single part of an address header.
15
 * 
16
 * Represents a single part of a list of addresses.  A part could be one email
17
 * address, or one 'group' containing multiple addresses.  The consumer ends on
18
 * finding either a comma token, representing a separation between addresses, or
19
 * a semi-colon token representing the end of a group.
20
 * 
21
 * A single email address may consist of just an email, or a name and an email
22
 * address.  Both of these are valid examples of a From header:
23
 *  - From: [email protected]
24
 *  - From: Jon Snow <[email protected]>
25
 * 
26
 * Groups must be named, for example:
27
 *  - To: Winterfell: [email protected], Arya Stark <[email protected]>;
28
 *
29
 * Addresses may contain quoted parts and comments, and names may be mime-header
30
 * encoded.
31
 * 
32
 * @author Zaahid Bateson
33
 */
34
class AddressConsumer extends AbstractConsumer
35
{
36
    /**
37
     * Returns the following as sub-consumers:
38
     *  - \ZBateson\MailMimeParser\Header\Consumer\AddressGroupConsumer
39
     *  - \ZBateson\MailMimeParser\Header\Consumer\CommentConsumer
40
     *  - \ZBateson\MailMimeParser\Header\Consumer\QuotedStringConsumer
41
     * 
42
     * @return AbstractConsumer[] the sub-consumers
43
     */
44 6
    protected function getSubConsumers()
45
    {
46
        return [
47 6
            $this->consumerService->getAddressGroupConsumer(),
48 6
            $this->consumerService->getCommentConsumer(),
49 6
            $this->consumerService->getQuotedStringConsumer(),
50
        ];
51
    }
52
    
53
    /**
54
     * Overridden to return patterns matching the beginning part of an address
55
     * in a name/address part ("<" and ">" chars), end tokens ("," and ";"), and
56
     * whitespace.
57
     * 
58
     * @return string[] the patterns
59
     */
60 6
    public function getTokenSeparators()
61
    {
62 6
        return ['<', '>', ',', ';', '\s+'];
63
    }
64
    
65
    /**
66
     * Returns true for commas and semi-colons.
67
     * 
68
     * Although the semi-colon is not strictly the end token of an
69
     * AddressConsumer, it could end a parent AddressGroupConsumer. I can't
70
     * think of a valid scenario where this would be an issue, but additional
71
     * thought may be needed (and documented here).
72
     * 
73
     * @param string $token
74
     * @return boolean false
75
     */
76 6
    protected function isEndToken($token)
77
    {
78 6
        return ($token === ',' || $token === ';');
79
    }
80
    
81
    /**
82
     * AddressConsumer is "greedy", so this always returns true.
83
     * 
84
     * @param string $token
85
     * @return boolean false
86
     */
87 1
    protected function isStartToken($token)
88
    {
89 1
        return true;
90
    }
91
    
92
    /**
93
     * Checks if the passed part represents the beginning or end of an address
94
     * part (less than/greater than characters) and either appends the value of
95
     * the part to the passed $strValue, or sets up $strName
96
     * 
97
     * @param HeaderPart $part
98
     * @param string $strName
99
     * @param string $strValue
100
     */
101 6
    private function processSinglePart(HeaderPart $part, &$strName, &$strValue)
102
    {
103 6
        $pValue = $part->getValue();
104 6
        if ($part instanceof Token) {
105 6
            if ($pValue === '<') {
106 3
                $strName = $strValue;
107 3
                $strValue = '';
108 3
                return;
109 6
            } elseif ($pValue === '>') {
110 3
                return;
111
            }
112
        }
113 6
        $strValue .= $pValue;
114 6
    }
115
    
116
    /**
117
     * Performs final processing on parsed parts.
118
     * 
119
     * AddressConsumer's implementation looks for tokens representing the
120
     * beginning of an address part, to create a Part\AddressPart out of a
121
     * name/address pair, or assign the name part to a parsed Part\AddressGroupPart
122
     * returned from its AddressGroupConsumer sub-consumer.
123
     * 
124
     * The returned array consists of a single element - either a
125
     * Part\AddressPart or a Part\AddressGroupPart.
126
     * 
127
     * @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
128
     * @return \ZBateson\MailMimeParser\Header\Part\HeaderPart[]|array
129
     */
130 6
    protected function processParts(array $parts)
131
    {
132 6
        $strName = '';
133 6
        $strValue = '';
134 6
        foreach ($parts as $part) {
135 6
            if ($part instanceof AddressGroupPart) {
136
                return [
137 1
                    $this->partFactory->newAddressGroupPart(
138 1
                        $part->getAddresses(),
139 1
                        $strValue
140
                    )
141
                ];
142
            }
143 6
            $this->processSinglePart($part, $strName, $strValue);
144
        }
145 6
        return [$this->partFactory->newAddressPart($strName, $strValue)];
146
    }
147
}
148