Completed
Push — master ( 3ff097...503b9d )
by Frederik
06:54
created

AddressList::withList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail;
5
6
/**
7
 * Class AddressList
8
 * @package Genkgo\Mail
9
 */
10
final class AddressList implements \Countable, \IteratorAggregate
11
{
12
    /**
13
     *
14
     */
15
    private CONST PARSE_START = 1;
16
    /**
17
     *
18
     */
19
    private CONST PARSE_QUOTE = 2;
20
21
    /**
22
     * @var array|Address[]
23
     */
24
    private $addresses = [];
25
26
    /**
27
     * To constructor.
28
     * @param array|Address[] $recipients
29
     */
30 37
    public function __construct(array $recipients = [])
31
    {
32 37
        foreach ($recipients as $recipient) {
33 35
            if ($recipient instanceof Address === false) {
34 1
                throw new \InvalidArgumentException('Recipient must be EmailAddressAndName object');
35
            }
36
37 34
            $this->addresses[] = $recipient;
38
        }
39 36
    }
40
41
    /**
42
     * @param Address $address
43
     * @return AddressList
44
     */
45 2
    public function withAddress(Address $address): AddressList
46
    {
47 2
        $clone = clone $this;
48 2
        $clone->addresses[] = $address;
49 2
        return $clone;
50
    }
51
52
    /**
53
     * @param Address $address
54
     * @return AddressList
55
     */
56 2
    public function withoutAddress(Address $address): AddressList
57
    {
58 2
        $clone = clone $this;
59
60 2
        foreach ($this->addresses as $key => $mayRemoveAddress) {
61 2
            if ($mayRemoveAddress->equals($address)) {
62 2
                unset($clone->addresses[$key]);
63
            }
64
        }
65
66 2
        return $clone;
67
    }
68
69
    /**
70
     * @param AddressList $addressList
71
     * @return AddressList
72
     */
73 1
    public function withList(AddressList $addressList): AddressList
74
    {
75 1
        $clone = clone $this;
76 1
        $clone->addresses = array_merge($this->addresses, $addressList->addresses);
77 1
        return $clone;
78
    }
79
80
    /**
81
     * @return Address
82
     */
83 9
    public function first(): Address
84
    {
85 9
        if (empty($this->addresses)) {
86 2
            throw new \OutOfRangeException();
87
        }
88
89 8
        return reset($this->addresses);
90
    }
91
92
    /**
93
     * @return int
94
     */
95 10
    public function count(): int
96
    {
97 10
        return count($this->addresses);
98
    }
99
100
    /**
101
     * @return \ArrayIterator|Address[]
102
     */
103 1
    public function getIterator()
104
    {
105 1
        return new \ArrayIterator($this->addresses);
106
    }
107
108
    /**
109
     * @return string
110
     */
111 19
    public function __toString(): string
112
    {
113 19
        return implode(
114 19
            ',',
115 19
            array_map(
116 19
                function (Address $addressAndName) {
117 18
                    return (string) $addressAndName;
118 19
                },
119 19
                $this->addresses
120
            )
121
        );
122
    }
123
124
    /**
125
     * @param string $addressListAsString
126
     * @return AddressList
127
     */
128 18
    public static function fromString(string $addressListAsString)
129
    {
130 18
        $addressListAsString = trim($addressListAsString);
131 18
        if ($addressListAsString === '') {
132 2
            return new self([]);
133
        }
134
135 17
        $addresses = [];
136 17
        $length = strlen($addressListAsString) - 1;
137 17
        $n = -1;
138 17
        $state = self::PARSE_START;
139 17
        $escapeNext = false;
140 17
        $sequence = '';
141
142 17
        while ($n < $length) {
143 17
            $n++;
144
145 17
            $char = $addressListAsString[$n];
146
147 17
            $sequence .= $char;
148
149 17
            if ($char === '\\') {
150 3
                $escapeNext = true;
151 3
                continue;
152
            }
153
154 17
            if ($escapeNext) {
155 3
                $escapeNext = false;
156 3
                continue;
157
            }
158
159
            switch ($state) {
160 17
                case self::PARSE_QUOTE:
161 9
                    if ($char === '"') {
162 8
                        $state = self::PARSE_START;
163
                    }
164
165 9
                    break;
166
                default:
167 17
                    if ($char === '"') {
168 9
                        $state = self::PARSE_QUOTE;
169
                    }
170
171 17
                    if ($char === ',') {
172 4
                        $addresses[] = Address::fromString(substr($sequence, 0, -1));
173 4
                        $sequence = '';
174 4
                        $state = self::PARSE_START;
175
                    }
176 17
                    break;
177
            }
178
        }
179
180 17
        $addresses[] = Address::fromString($sequence);
181
182 16
        return new self($addresses);
183
    }
184
}