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

ClientFactory::fromString()   D

Complexity

Conditions 14
Paths 259

Size

Total Lines 74
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 14.0142

Importance

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

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\ConnectionInterface;
7
use Genkgo\Mail\Protocol\CryptoConstant;
8
use Genkgo\Mail\Protocol\NullConnection;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Genkgo\Mail\Protocol\Smtp\NullConnection.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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