Completed
Push — master ( 235098...068efe )
by Frederik
02:09
created

AddressList::first()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
crap 2
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
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 36
    public function __construct(array $recipients = [])
31
    {
32 36
        foreach ($recipients as $recipient) {
33 34
            if ($recipient instanceof Address === false) {
34 1
                throw new \InvalidArgumentException('Recipient must be EmailAddressAndName object');
35
            }
36
37 33
            $this->addresses[] = $recipient;
38
        }
39 35
    }
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
     * @return Address
71
     */
72 8
    public function first(): Address
73
    {
74 8
        if (empty($this->addresses)) {
75 2
            throw new \OutOfRangeException();
76
        }
77
78 7
        return reset($this->addresses);
79
    }
80
81
    /**
82
     * @return int
83
     */
84 10
    public function count(): int
85
    {
86 10
        return count($this->addresses);
87
    }
88
89
    /**
90
     * @return string
91
     */
92 18
    public function __toString(): string
93
    {
94 18
        return implode(
95 18
            ',',
96 18
            array_map(
97 18
                function (Address $addressAndName) {
98 17
                    return (string) $addressAndName;
99 18
                },
100 18
                $this->addresses
101
            )
102
        );
103
    }
104
105
    /**
106
     * @param string $addressListAsString
107
     * @return AddressList
108
     */
109 17
    public static function fromString(string $addressListAsString)
110
    {
111 17
        $addressListAsString = trim($addressListAsString);
112 17
        if ($addressListAsString === '') {
113 2
            return new self([]);
114
        }
115
116 16
        $addresses = [];
117 16
        $length = strlen($addressListAsString) - 1;
118 16
        $n = -1;
119 16
        $state = self::PARSE_START;
120 16
        $escapeNext = false;
121 16
        $sequence = '';
122
123 16
        while ($n < $length) {
124 16
            $n++;
125
126 16
            $char = $addressListAsString[$n];
127
128 16
            $sequence .= $char;
129
130 16
            if ($char === '\\') {
131 3
                $escapeNext = true;
132 3
                continue;
133
            }
134
135 16
            if ($escapeNext) {
136 3
                $escapeNext = false;
137 3
                continue;
138
            }
139
140
            switch ($state) {
141 16
                case self::PARSE_QUOTE:
142 9
                    if ($char === '"') {
143 8
                        $state = self::PARSE_START;
144
                    }
145
146 9
                    break;
147
                default:
148 16
                    if ($char === '"') {
149 9
                        $state = self::PARSE_QUOTE;
150
                    }
151
152 16
                    if ($char === ',') {
153 4
                        $addresses[] = Address::fromString(substr($sequence, 0, -1));
154 4
                        $sequence = '';
155 4
                        $state = self::PARSE_START;
156
                    }
157 16
                    break;
158
            }
159
        }
160
161 16
        $addresses[] = Address::fromString($sequence);
162
163 15
        return new self($addresses);
164
    }
165
}