AddressConsumerService   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 12
eloc 30
c 0
b 0
f 0
dl 0
loc 99
ccs 40
cts 40
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getTokenSeparators() 0 3 1
A isStartToken() 0 3 1
B processParts() 0 30 7
A __construct() 0 17 1
A isEndToken() 0 3 2
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 Psr\Log\LoggerInterface;
11
use ZBateson\MailMimeParser\Header\Part\AddressGroupPart;
12
use ZBateson\MailMimeParser\Header\Part\AddressPart;
13
use ZBateson\MailMimeParser\Header\Part\MimeToken;
14
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
15
16
/**
17
 * Parses a single part of an address header.
18
 *
19
 * Represents a single part of a list of addresses.  A part could be one email
20
 * address, or one 'group' containing multiple addresses.  The consumer ends on
21
 * finding either a comma token, representing a separation between addresses, or
22
 * a semi-colon token representing the end of a group.
23
 *
24
 * A single email address may consist of just an email, or a name and an email
25
 * address.  Both of these are valid examples of a From header:
26
 *  - From: [email protected]
27
 *  - From: Jon Snow <[email protected]>
28
 *
29
 * Groups must be named, for example:
30
 *  - To: Winterfell: [email protected], Arya Stark <[email protected]>;
31
 *
32
 * Addresses may contain quoted parts and comments, and names may be mime-header
33
 * encoded.
34
 *
35
 * @author Zaahid Bateson
36
 */
37
class AddressConsumerService extends AbstractConsumerService
38
{
39 10
    public function __construct(
40
        LoggerInterface $logger,
41
        MimeTokenPartFactory $partFactory,
42
        AddressGroupConsumerService $addressGroupConsumerService,
43
        AddressEmailConsumerService $addressEmailConsumerService,
44
        CommentConsumerService $commentConsumerService,
45
        QuotedStringConsumerService $quotedStringConsumerService
46
    ) {
47 10
        $addressGroupConsumerService->setAddressConsumerService($this);
48 10
        parent::__construct(
49 10
            $logger,
50 10
            $partFactory,
51 10
            [
52 10
                $addressGroupConsumerService,
53 10
                $addressEmailConsumerService,
54 10
                $commentConsumerService,
55 10
                $quotedStringConsumerService
56 10
            ]
57 10
        );
58
    }
59
60
    /**
61
     * Overridden to return patterns matching end tokens ("," and ";"), and
62
     * whitespace.
63
     *
64
     * @return string[] the patterns
65
     */
66 10
    public function getTokenSeparators() : array
67
    {
68 10
        return [',', ';', '\s+'];
69
    }
70
71
    /**
72
     * Returns true for commas and semi-colons.
73
     *
74
     * Although the semi-colon is not strictly the end token of an
75
     * AddressConsumerService, it could end a parent
76
     * {@see AddressGroupConsumerService}.
77
     */
78 105
    protected function isEndToken(string $token) : bool
79
    {
80 105
        return ($token === ',' || $token === ';');
81
    }
82
83
    /**
84
     * AddressConsumer is "greedy", so this always returns true.
85
     */
86 97
    protected function isStartToken(string $token) : bool
87
    {
88 97
        return true;
89
    }
90
91
    /**
92
     * Performs final processing on parsed parts.
93
     *
94
     * AddressConsumerService's implementation looks for tokens representing the
95
     * beginning of an address part, to create a {@see AddressPart} out of a
96
     * name/address pair, or assign the name part to a parsed
97
     * {@see AddressGroupPart} returned from its AddressGroupConsumerService
98
     * sub-consumer.
99
     *
100
     * The returned array consists of a single element - either an
101
     * {@see AddressPart} or an {@see AddressGroupPart}.
102
     *
103
     * @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
104
     * @return \ZBateson\MailMimeParser\Header\IHeaderPart[]|array
105
     */
106 105
    protected function processParts(array $parts) : array
107
    {
108 105
        $found = null;
109 105
        $revved = \array_reverse($parts, true);
110 105
        foreach ($revved as $key => $part) {
111 105
            if ($part instanceof AddressGroupPart || $part instanceof AddressPart) {
112 98
                $found = $part;
113
                // purposefully ignoring anything after
114 98
                \array_splice($parts, $key);
115 98
                break;
116
            }
117
        }
118
119 105
        if ($found !== null) {
120 98
            if ($found instanceof AddressGroupPart) {
121 1
                return [$this->partFactory->newAddressGroupPart(
122 1
                    $parts,
123 1
                    [$found]
124 1
                )];
125
            }
126 98
            return [$this->partFactory->newAddress(
127 98
                $parts,
128 98
                [$found]
129 98
            )];
130
        }
131
132 8
        return [
133 8
            $this->partFactory->newAddress(
134 8
                [],
135 8
                \array_map(fn ($p) => ($p instanceof MimeToken) ? $this->partFactory->newToken($p->getRawValue()) : $p, $parts)
136 8
            )
137 8
        ];
138
    }
139
}
140