Completed
Pull Request — master (#31)
by Gawain
01:46
created

ClientFactory::fromString()   D

Complexity

Conditions 14
Paths 259

Size

Total Lines 74
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 14.1132

Importance

Changes 0
Metric Value
dl 0
loc 74
ccs 44
cts 48
cp 0.9167
rs 4.0377
c 0
b 0
f 0
cc 14
eloc 50
nc 259
nop 1
crap 14.1132

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