AggregateResponse::fromResponseLines()   C
last analyzed

Complexity

Conditions 12
Paths 29

Size

Total Lines 70

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 14.0892

Importance

Changes 0
Metric Value
dl 0
loc 70
ccs 31
cts 41
cp 0.7561
rs 6.2278
c 0
b 0
f 0
cc 12
nc 29
nop 2
crap 14.0892

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\Response;
5
6
use Genkgo\Mail\Exception\AssertionFailedException;
7
use Genkgo\Mail\Protocol\ConnectionInterface;
8
use Genkgo\Mail\Protocol\Imap\CommandResponseCanBeParsedInterface;
9
use Genkgo\Mail\Protocol\Imap\RequestInterface;
10
use Genkgo\Mail\Protocol\Imap\ResponseInterface;
11
12
/**
13
 * @implements \IteratorAggregate<int, ResponseInterface[]>
14
 */
15
final class AggregateResponse implements \IteratorAggregate
16
{
17
    /**
18
     * @var array|ResponseInterface[]
19
     */
20
    private $lines = [];
21
22
    /**
23
     * @return \Iterator|ResponseInterface[]
24
     */
25 1
    public function getIterator(): \Iterator
26
    {
27 1
        return new \ArrayIterator($this->lines);
28
    }
29
30
    /**
31
     * @return ResponseInterface
32
     */
33 19
    public function first(): ResponseInterface
34
    {
35 19
        if (empty($this->lines)) {
36
            throw new \OutOfBoundsException('Cannot return item of empty response');
37
        }
38
39 19
        return \reset($this->lines);
40
    }
41
42
    /**
43
     * @return ResponseInterface
44
     */
45 18
    public function last(): ResponseInterface
46
    {
47 18
        if (empty($this->lines)) {
48 1
            throw new \OutOfBoundsException('Cannot return item of empty response');
49
        }
50
51 17
        return \end($this->lines);
52
    }
53
54
    /**
55
     * @param int $index
56
     * @return ResponseInterface
57
     */
58 3
    public function at(int $index): ResponseInterface
59
    {
60 3
        if (!isset($this->lines[$index])) {
61 1
            throw new \OutOfBoundsException('GenericItem not in response');
62
        }
63
64 2
        return $this->lines[$index];
65
    }
66
67
    /**
68
     * @return bool
69
     */
70 26
    public function hasCompleted(): bool
71
    {
72 26
        if (empty($this->lines)) {
73 15
            return false;
74
        }
75
76 26
        $lastCommand = \end($this->lines);
77
        try {
78 26
            $lastCommand->assertTagged();
79 25
            return true;
80 9
        } catch (AssertionFailedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
81
        }
82
83
        try {
84 9
            $lastCommand->assertContinuation();
85 7
            return true;
86 2
        } catch (AssertionFailedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
87
        }
88
89 2
        return false;
90
    }
91
92
    /**
93
     * @return string
94
     */
95
    public function __toString(): string
96
    {
97
        return \implode(
98
            '',
99
            \array_map(
100
                function (ResponseInterface $response) {
101
                    return (string)$response;
102
                },
103
                $this->lines
104
            )
105
        );
106
    }
107
108
    /**
109
     * @param RequestInterface $request
110
     * @param ConnectionInterface $connection
111
     * @return AggregateResponse
112
     */
113 15
    public static function fromServerResponse(ConnectionInterface $connection, RequestInterface $request): self
114
    {
115 15
        return self::fromResponseLines(
116
            (function () use ($connection) {
117 15
                while ($line = $connection->receive()) {
118 15
                    yield $line;
119
                }
120 15
            })(),
121
            $request
122
        );
123
    }
124
125
    /**
126
     * @param \Iterator<int, string> $lines
127
     * @param RequestInterface $request
128
     * @return static
129
     */
130 26
    public static function fromResponseLines(\Iterator $lines, RequestInterface $request): self
131
    {
132 26
        $response = new self();
133 26
        $currentLine = [];
134
135 26
        foreach ($lines as $line) {
136 26
            switch (\substr($line, 0, 2)) {
137 26
                case '+ ':
138 7
                    if ($currentLine !== []) {
139
                        $response->lines[] = new UntaggedResponse(\implode('', $currentLine));
140
                        $currentLine = [];
141
                    }
142
143 7
                    $response->lines[] = new CommandContinuationRequestResponse(
144 7
                        \substr($line, 2)
145
                    );
146 7
                    break;
147 25
                case '* ':
148 17
                    if ($currentLine !== []) {
149
                        $response->lines[] = new UntaggedResponse(\implode('', $currentLine));
150
                        $currentLine = [];
151
                    }
152
153 17
                    if ($request instanceof CommandResponseCanBeParsedInterface) {
154 2
                        $response->lines[] = $request->createParsedResponse(
155
                            (function () use ($line, $lines) {
156 2
                                yield $line;
157
158 2
                                while ($lines->valid()) {
159 2
                                    $lines->next();
160 2
                                    yield $lines->current();
161
                                }
162 2
                            })()
163
                        );
164
                    } else {
165 15
                        $currentLine = [\substr($line, 2)];
166
                    }
167 17
                    break;
168
                default:
169
                    try {
170 25
                        $taggedResponse = new TaggedResponse(
171 25
                            $request->getTag(),
172 25
                            $request->getTag()->extractBodyFromLine($line)
173
                        );
174
175 25
                        if ($currentLine !== []) {
176 15
                            $response->lines[] = new UntaggedResponse(\implode('', $currentLine));
177 15
                            $currentLine = [];
178
                        }
179
180 25
                        $response->lines[] = $taggedResponse;
181
                    } catch (\InvalidArgumentException $e) {
182
                        if ($response->lines === []) {
183
                            throw new \UnexpectedValueException(
184
                                'Expected line to begin with +, * or tag. Got: ' . $line
185
                            );
186
                        }
187
188
                        $currentLine[] = $line;
189
                    }
190 25
                    break;
191
            }
192
193 26
            if ($response->hasCompleted()) {
194 26
                return $response;
195
            }
196
        }
197
198
        throw new \UnexpectedValueException('Unexpected end of response');
199
    }
200
}
201