ClientFactory::fromString()   D
last analyzed

Complexity

Conditions 13
Paths 195

Size

Total Lines 90

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 51
CRAP Score 13.2971

Importance

Changes 0
Metric Value
dl 0
loc 90
ccs 51
cts 58
cp 0.8793
rs 4.8781
c 0
b 0
f 0
cc 13
nc 195
nop 2
crap 13.2971

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;
5
6
use Genkgo\Mail\Protocol\AutomaticConnection;
7
use Genkgo\Mail\Protocol\ConnectionInterface;
8
use Genkgo\Mail\Protocol\CryptoConstant;
9
use Genkgo\Mail\Protocol\Imap\Negotiation\AuthNegotiation;
10
use Genkgo\Mail\Protocol\Imap\Negotiation\ForceTlsUpgradeNegotiation;
11
use Genkgo\Mail\Protocol\Imap\Negotiation\TryTlsUpgradeNegotiation;
12
use Genkgo\Mail\Protocol\Imap\TagFactory\GeneratorTagFactory;
13
use Genkgo\Mail\Protocol\PlainTcpConnection;
14
use Genkgo\Mail\Protocol\SecureConnection;
15
use Genkgo\Mail\Protocol\SecureConnectionOptions;
16
17
final class ClientFactory
18
{
19
    private const AUTH_ENUM = [
20
        Client::AUTH_NONE => true,
21
        Client::AUTH_PLAIN => true,
22
        Client::AUTH_LOGIN => true,
23
        Client::AUTH_AUTO => true
24
    ];
25
26
    /**
27
     * @var ConnectionInterface
28
     */
29
    private $connection;
30
31
    /**
32
     * @var string
33
     */
34
    private $password = '';
35
36
    /**
37
     * @var float
38
     */
39
    private $timeout = 1;
40
41
    /**
42
     * @var string
43
     */
44
    private $username = '';
45
46
    /**
47
     * @var int
48
     */
49
    private $authMethod = Client::AUTH_NONE;
50
51
    /**
52
     * @var bool
53
     */
54
    private $insecureConnectionAllowed = false;
55
56
    /**
57
     * @var string
58
     */
59
    private $reconnectAfter = 'PT300S';
60
61
    /**
62
     * @var int
63
     */
64
    private $startTls;
65
66
    /**
67
     * @param ConnectionInterface $connection
68
     */
69 9
    public function __construct(ConnectionInterface $connection)
70
    {
71 9
        $this->connection = $connection;
72 9
        $this->startTls = CryptoConstant::getDefaultMethod(PHP_VERSION);
73 9
    }
74
75
    /**
76
     * @param float $connectionTimeout
77
     * @return ClientFactory
78
     */
79 1
    public function withTimeout(float $connectionTimeout): ClientFactory
80
    {
81 1
        $clone = clone $this;
82 1
        $clone->timeout = $connectionTimeout;
83 1
        return $clone;
84
    }
85
86
    /**
87
     * @param int $method
88
     * @param string $password
89
     * @param string $username
90
     * @return ClientFactory
91
     */
92 3
    public function withAuthentication(int $method, string $username, string $password): ClientFactory
93
    {
94 3
        if (!isset(self::AUTH_ENUM[$method])) {
95 1
            throw new \InvalidArgumentException('Invalid authentication method');
96
        }
97
98 2
        $clone = clone $this;
99 2
        $clone->authMethod = $method;
100 2
        $clone->username = $username;
101 2
        $clone->password = $password;
102 2
        return $clone;
103
    }
104
105
    /**
106
     * @return ClientFactory
107
     */
108 1
    public function withInsecureConnectionAllowed(): ClientFactory
109
    {
110 1
        $clone = clone $this;
111 1
        $clone->insecureConnectionAllowed = true;
112 1
        return $clone;
113
    }
114
115
    /**
116
     * @param int $crypto
117
     * @return ClientFactory
118
     */
119 1
    public function withStartTls(int $crypto): ClientFactory
120
    {
121 1
        $clone = clone $this;
122 1
        $clone->startTls = $crypto;
123 1
        return $clone;
124
    }
125
126
    /**
127
     * @return ClientFactory
128
     */
129 2
    public function withoutStartTls(): ClientFactory
130
    {
131 2
        $clone = clone $this;
132 2
        $clone->startTls = 0;
133 2
        return $clone;
134
    }
135
136
    /**
137
     * @return Client
138
     */
139 7
    public function newClient(): Client
140
    {
141 7
        $negotiators = [];
142
143 7
        if ($this->startTls !== 0) {
144 4
            if ($this->insecureConnectionAllowed) {
145
                $negotiators[] = new TryTlsUpgradeNegotiation(
146
                    $this->connection,
147
                    $this->startTls
148
                );
149
            } else {
150 4
                $negotiators[] = new ForceTlsUpgradeNegotiation(
151 4
                    $this->connection,
152 4
                    $this->startTls
153
                );
154
            }
155
        }
156
157 7
        if ($this->authMethod !== Client::AUTH_NONE) {
158 2
            $negotiators[] = new AuthNegotiation(
159 2
                $this->authMethod,
160 2
                $this->username,
161 2
                $this->password
162
            );
163
        }
164
165 7
        return new Client(
166 7
            new AutomaticConnection(
167 7
                $this->connection,
168 7
                new \DateInterval($this->reconnectAfter)
169
            ),
170 7
            new GeneratorTagFactory(),
171
            $negotiators
172
        );
173
    }
174
175
    /**
176
     * @param string $dataSourceName
177
     * @param array<string, array<string, mixed>> $contextOptions
178
     * @return ClientFactory
179
     */
180 6
    public static function fromString(string $dataSourceName, array $contextOptions = []):ClientFactory
181
    {
182 6
        $components = \parse_url($dataSourceName);
183 6
        if ($components === false || !isset($components['scheme'], $components['host'])) {
184 1
            throw new \InvalidArgumentException('Scheme and host are required');
185
        }
186
187 5
        if (isset($components['query'])) {
188 2
            \parse_str($components['query'], $query);
189
        } else {
190 3
            $query = [];
191
        }
192
193 5
        $insecureConnectionAllowed = false;
194 5
        $startTls = true;
195
196 5
        switch ($components['scheme']) {
197 5
            case 'imap':
198 1
                $connection = new PlainTcpConnection(
199 1
                    $components['host'],
200 1
                    $components['port'] ?? 143,
201 1
                    1.0,
202
                    $contextOptions
203
                );
204 1
                break;
205 4
            case 'imaps':
206 2
                $connection = new SecureConnection(
207 2
                    $components['host'],
208 2
                    $components['port'] ?? 993,
209 2
                    new SecureConnectionOptions(
210 2
                        (int)($query['crypto'] ?? CryptoConstant::getDefaultMethod(PHP_VERSION)),
211 2
                        10,
212
                        $contextOptions
213
                    )
214
                );
215 2
                break;
216 2
            case 'imap-starttls':
217 1
                $insecureConnectionAllowed = true;
218 1
                $startTls = false;
219
220 1
                $connection = new PlainTcpConnection(
221 1
                    $components['host'],
222 1
                    $components['port'] ?? 143,
223 1
                    1.0,
224
                    $contextOptions
225
                );
226 1
                break;
227 1
            case 'imap+starttls':
228
                $insecureConnectionAllowed = true;
229
                $startTls = true;
230
231
                $connection = new PlainTcpConnection(
232
                    $components['host'],
233
                    $components['port'] ?? 143,
234
                    1.0,
235
                    $contextOptions
236
                );
237
                break;
238
            default:
239 1
                throw new \InvalidArgumentException(\sprintf(
240 1
                    'Provided scheme "%s://" is invalid. Only imap:// imaps:// and imap-starttls:// are supported',
241 1
                    $components['scheme']
242
                ));
243
        }
244
245 4
        $factory = new self($connection);
246 4
        $factory->insecureConnectionAllowed = $insecureConnectionAllowed;
247
248 4
        if (isset($components['user'], $components['pass'])) {
249 1
            $factory->authMethod = Client::AUTH_AUTO;
250 1
            $factory->username = \urldecode($components['user']);
251 1
            $factory->password = \urldecode($components['pass']);
252
        }
253
254 4
        if (isset($query['timeout'])) {
255 1
            $factory->timeout = (float)$query['timeout'];
256
        }
257
258 4
        if (isset($query['reconnectAfter'])) {
259 1
            $factory->reconnectAfter = $query['reconnectAfter'];
260
        }
261
262 4
        if (!$startTls) {
263 1
            $factory->startTls = 0;
264 3
        } elseif (isset($query['crypto'])) {
265 1
            $factory->startTls = (int)$query['crypto'];
266
        }
267
268 4
        return $factory;
269
    }
270
}
271