Completed
Pull Request — master (#42)
by Frederik
02:04
created

ItemList::fromString()   D

Complexity

Conditions 20
Paths 40

Size

Total Lines 102
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 420

Importance

Changes 0
Metric Value
dl 0
loc 102
ccs 0
cts 83
cp 0
rs 4.7294
c 0
b 0
f 0
cc 20
eloc 67
nc 40
nop 1
crap 420

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\Protocol\Imap\MessageData;
5
6
use Genkgo\Mail\Protocol\Imap\MessageData\Item\NameItem;
7
use Genkgo\Mail\Protocol\Imap\MessageData\Item\PartialItem;
8
use Genkgo\Mail\Protocol\Imap\MessageData\Item\SectionItem;
9
10
final class ItemList
11
{
12
    /**
13
     *
14
     */
15
    private CONST STATE_NONE = 0;
16
    /**
17
     *
18
     */
19
    private CONST STATE_NAME = 1;
20
    /**
21
     *
22
     */
23
    private CONST STATE_SECTION = 2;
24
    /**
25
     *
26
     */
27
    private CONST STATE_PARTIAL = 3;
28
    /**
29
     *
30
     */
31
    private CONST STATE_OCTET = 4;
32
    /**
33
     * @var array
34
     */
35
    private $list = [];
36
    /**
37
     * @var int
38
     */
39
    private $size;
40
    /**
41
     * @var string
42
     */
43
    private $body;
44
45
    /**
46
     * ItemList constructor.
47
     * @param array $list
48
     */
49
    public function __construct(array $list = [])
50
    {
51
        $this->list = $list;
52
    }
53
54
    /**
55
     * @param ItemInterface $item
56
     * @return ItemList
57
     */
58
    public function withItem(ItemInterface $item): self
59
    {
60
        $clone = clone $this;
61
        $clone->list[$item->getName()] = $item;
62
        return $clone;
63
    }
64
65
    /**
66
     * @param int $size
67
     * @return ItemList
68
     */
69
    public function withOctet(int $size): self
70
    {
71
        $clone = clone $this;
72
        $clone->size = $size;
73
        return $clone;
74
    }
75
76
    /**
77
     * @param string $body
78
     * @return ItemList
79
     */
80
    public function withBody(string $body): self
81
    {
82
        $clone = clone $this;
83
        $clone->body = $body;
84
        return $clone;
85
    }
86
87
    /**
88
     * @return string
89
     */
90
    public function getBody(): string
91
    {
92
        return $this->body;
93
    }
94
95
    /**
96
     * @param $name
97
     * @return ItemInterface
98
     */
99
    public function getName($name): ItemInterface
100
    {
101
        if (!isset($this->list[$name])) {
102
            throw new \UnexpectedValueException(
103
                sprintf('Unknown name %s', $name)
104
            );
105
        }
106
107
        return $this->list[$name];
108
    }
109
110
    /**
111
     * @return ItemInterface
112
     */
113
    public function last(): ItemInterface
114
    {
115
        if (empty($this->list)) {
116
            throw new \OutOfBoundsException('Cannot return last item from empty list');
117
        }
118
119
        return end($this->list);
120
    }
121
122
    /**
123
     * @return string
124
     */
125
    public function __toString(): string
126
    {
127
        $string = implode(
128
            ' ',
129
            array_map(
130
                function (ItemInterface $item) {
131
                    return (string)$item;
132
                },
133
                $this->list
134
            )
135
        );
136
137
        if (count($this->list) > 1) {
138
            return '(' . $string . ')';
139
        }
140
141
        return $string;
142
    }
143
144
    /**
145
     * @param string $serializedList
146
     * @return ItemList
147
     */
148
    public static function fromString(string $serializedList): self
149
    {
150
        $list = new self();
151
152
        $index = 0;
153
        $state = self::STATE_NAME;
154
        $sequence = '';
155
156
        while (isset($serializedList[$index])) {
157
            $char = $serializedList[$index];
158
            $sequence .= $char;
159
160
            switch ($char) {
161
                case '[':
162
                    if ($state !== self::STATE_NAME) {
163
                        throw new \InvalidArgumentException('Invalid character [ found');
164
                    }
165
166
                    $list = $list->withItem(new NameItem(substr($sequence, 0, -1)));
167
                    $sequence = '[';
168
                    $state = self::STATE_SECTION;
169
                    break;
170
                case ']':
171
                    if ($state !== self::STATE_SECTION) {
172
                        throw new \InvalidArgumentException('Invalid character ] found');
173
                    }
174
175
                    $list = $list->withItem(
176
                        new SectionItem($list->last(), SectionList::fromString($sequence))
177
                    );
178
179
                    $sequence = '';
180
                    $state = self::STATE_NAME;
181
                    break;
182
                case '<':
183
                    if ($state !== self::STATE_NAME) {
184
                        throw new \InvalidArgumentException('Invalid character < found');
185
                    }
186
187
                    $state = self::STATE_PARTIAL;
188
                    break;
189
                case '>':
190
                    if ($state !== self::STATE_PARTIAL) {
191
                        throw new \InvalidArgumentException('Invalid character > found');
192
                    }
193
194
                    $list = $list->withItem(
195
                        new PartialItem($list->last(), Partial::fromString($sequence))
196
                    );
197
198
                    $sequence = '';
199
                    $state = self::STATE_NAME;
200
                    break;
201
                case '{':
202
                    if ($state !== self::STATE_NONE) {
203
                        throw new \InvalidArgumentException('Invalid character { found');
204
                    }
205
206
207
                    $state = self::STATE_OCTET;
208
                    break;
209
                case '}':
210
                    if ($state !== self::STATE_OCTET) {
211
                        throw new \InvalidArgumentException('Invalid characters } found');
212
                    }
213
214
                    $list = $list->withOctet((int)substr($sequence, 1, -1));
215
                    $sequence = '';
216
217
                    $state = self::STATE_NAME;
218
                    break;
219
                case ' ':
220
                    if ($sequence === ' ') {
221
                        $state = self::STATE_NONE;
222
                    }
223
224
                    if ($state === self::STATE_NONE) {
225
                        $sequence = '';
226
                    }
227
228
                    if ($state === self::STATE_NAME) {
229
                        $list = $list->withItem(new NameItem(substr($sequence, 0, -1)));
230
                        $sequence = '';
231
                        $state = self::STATE_NONE;
232
                    }
233
234
                    break;
235
                case "\n":
236
                    $list = $list->withBody(substr($serializedList, $index + 1));
237
                    $sequence = '';
238
                    break 2;
239
            }
240
241
            $index++;
242
        }
243
244
        if ($sequence) {
245
            $list = $list->withItem(new NameItem($sequence));
246
        }
247
248
        return $list;
249
    }
250
}