Completed
Push — master ( 789708...940c54 )
by Frederik
02:07
created

Address::fromString()   D

Complexity

Conditions 21
Paths 119

Size

Total Lines 94
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 54
CRAP Score 21

Importance

Changes 0
Metric Value
dl 0
loc 94
ccs 54
cts 54
cp 1
rs 4.4356
c 0
b 0
f 0
cc 21
eloc 58
nc 119
nop 1
crap 21

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail;
5
6
use Genkgo\Mail\Header\HeaderValue;
7
8
/**
9
 * Class Address
10
 * @package Genkgo\Mail
11
 */
12
final class Address
13
{
14
    /**
15
     *
16
     */
17
    private CONST PARSE_POSITION_START = 1;
18
    /**
19
     *
20
     */
21
    private CONST PARSE_POSITION_QUOTE = 2;
22
    /**
23
     *
24
     */
25
    private CONST PARSE_STATE_EMAIL = 1;
26
    /**
27
     *
28
     */
29
    private CONST PARSE_STATE_TAGGED_EMAIL = 2;
30
31
    /**
32
     * @var EmailAddress
33
     */
34
    private $address;
35
36
    /**
37
     * @var string
38
     */
39
    private $name;
40
41
    /**
42
     * To constructor.
43
     * @param EmailAddress $address
44
     * @param string $name
45
     */
46 34
    public function __construct(EmailAddress $address, string $name = '')
47
    {
48 34
        if (preg_match('/\v/', $name) !== 0) {
49 1
            throw new \InvalidArgumentException('Cannot use vertical white space within name of email address');
50
        }
51
52 33
        $this->address = $address;
53 33
        $this->name = $name;
54 33
    }
55
56
    /**
57
     * @return EmailAddress
58
     */
59 9
    public function getAddress(): EmailAddress
60
    {
61 9
        return $this->address;
62
    }
63
64
    /**
65
     * @return string
66
     */
67 9
    public function getName(): string
68
    {
69 9
        return $this->name;
70
    }
71
72
    /**
73
     * @param Address $address
74
     * @return bool
75
     */
76 3
    public function equals(Address $address): bool
77
    {
78 3
        return $this->address->equals($address->address) && $this->name === $address->name;
79
    }
80
81
    /**
82
     * @return string
83
     */
84 18
    public function __toString(): string
85
    {
86 18
        if ($this->name === '') {
87 1
            return (string)$this->address;
88
        }
89
90 17
        $name = $this->name;
91
92 17
        $encodedName = addcslashes($name, "\0..\37\177\\\"");
93
94 17
        if ($encodedName !== $name || preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $this->name) === 1) {
95 2
            $encodedName = sprintf('"%s"', $encodedName);
96
        }
97
98 17
        return (string)(new HeaderValue($encodedName)) . ' <' . $this->address->getPunyCode() . '>';
99
    }
100
101
    /**
102
     * @param string $addressAsString
103
     * @return Address
104
     */
105 18
    public static function fromString(string $addressAsString)
106
    {
107 18
        $addressAsString = trim($addressAsString);
108
109 18
        if ($addressAsString === '') {
110 1
            throw new \InvalidArgumentException('Address cannot be empty');
111
        }
112
113 17
        $sequence = '';
114 17
        $length = strlen($addressAsString) - 1;
115 17
        $n = -1;
116 17
        $state = self::PARSE_STATE_EMAIL;
117 17
        $position = self::PARSE_POSITION_START;
118 17
        $escapeNext = false;
119 17
        $name = '';
120 17
        $email = '';
121 17
        $nameQuoted = false;
122
123 17
        while ($n < $length) {
124 17
            $n++;
125
126 17
            $char = $addressAsString[$n];
127
128 17
            if ($char === '\\') {
129 3
                $escapeNext = true;
130 3
                continue;
131
            }
132
133 17
            $sequence .= $char;
134
135 17
            if ($escapeNext) {
136 3
                $escapeNext = false;
137 3
                continue;
138
            }
139
140
            switch ($position) {
141 17
                case self::PARSE_POSITION_QUOTE:
142 12
                    if ($char === '"') {
143 10
                        $position = self::PARSE_POSITION_START;
144
                    }
145
146 12
                    break;
147
                default:
148 17
                    if ($char === '"') {
149 12
                        $position = self::PARSE_POSITION_QUOTE;
150 12
                        $nameQuoted = true;
151
                    }
152 17
                    break;
153
            }
154
155
            switch ($state) {
156 17
                case self::PARSE_STATE_TAGGED_EMAIL:
157 13
                    if ($position !== self::PARSE_POSITION_QUOTE && $char === '>') {
158 12
                        $state = self::PARSE_STATE_EMAIL;
159 12
                        $email = substr($sequence, 0, -1);
160
                    }
161
162 13
                    break;
163
                default:
164 17
                    if ($email !== '') {
165 1
                        throw new \InvalidArgumentException('Invalid characters used after <>');
166
                    }
167
168 17
                    if ($position !== self::PARSE_POSITION_QUOTE && $char === '<') {
169 13
                        $state = self::PARSE_STATE_TAGGED_EMAIL;
170 13
                        $name = trim(substr($sequence, 0, -1));
171 13
                        $sequence = '';
172
                    }
173 17
                    break;
174
            }
175
        }
176
177 16
        if ($position === self::PARSE_POSITION_QUOTE) {
178 2
            throw new \InvalidArgumentException('Address uses starting quotes but no ending quotes');
179
        }
180
181 14
        if ($state === self::PARSE_STATE_TAGGED_EMAIL) {
182 1
            throw new \InvalidArgumentException('Address uses starting tag (<) but no ending tag (>)');
183
        }
184
185 13
        if ($name === '' && $email === '') {
186 2
            return new self(new EmailAddress($sequence));
187
        }
188
189 11
        if ($nameQuoted && $name[0] !== '"') {
190 1
            throw new \InvalidArgumentException('Invalid characters before "');
191
        }
192
193 10
        if ($nameQuoted) {
194 7
            $name = substr($name, 1, -1);
195
        }
196
197 10
        return new self(new EmailAddress($email), $name);
198
    }
199
}