Completed
Pull Request — master (#42)
by Frederik
04:15 queued 01:07
created

ClientFactory::fromString()   C

Complexity

Conditions 12
Paths 99

Size

Total Lines 67
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 67
ccs 43
cts 43
cp 1
rs 5.8429
c 0
b 0
f 0
cc 12
eloc 45
nc 99
nop 1
crap 12

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