Completed
Push — master ( 3ff097...503b9d )
by Frederik
06:54
created

ClientFactory::newClient()   C

Complexity

Conditions 8
Paths 14

Size

Total Lines 68
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 68
ccs 39
cts 39
cp 1
rs 6.5974
c 0
b 0
f 0
cc 8
eloc 45
nc 14
nop 0
crap 8

How to fix   Long Method   

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\Smtp\Request\AuthLoginCommand;
8
use Genkgo\Mail\Protocol\Smtp\Request\AuthLoginPasswordRequest;
9
use Genkgo\Mail\Protocol\Smtp\Request\AuthLoginUsernameRequest;
10
use Genkgo\Mail\Protocol\Smtp\Request\AuthPlainCommand;
11
use Genkgo\Mail\Protocol\Smtp\Request\AuthPlainCredentialsRequest;
12
use Genkgo\Mail\Protocol\Smtp\Request\EhloCommand;
13
use Genkgo\Mail\Protocol\Smtp\Request\StartTlsCommand;
14
use Genkgo\Mail\Protocol\Smtp\Response\EhloResponse;
15
16
/**
17
 * Class ClientFactory
18
 * @package Genkgo\Mail\Protocol\Smtp
19
 */
20
final class ClientFactory implements ClientFactoryInterface
21
{
22
    /**
23
     *
24
     */
25
    public CONST AUTH_NONE = 0;
26
    /**
27
     *
28
     */
29
    public CONST AUTH_PLAIN = 1;
30
    /**
31
     *
32
     */
33
    public CONST AUTH_LOGIN = 2;
34
    /**
35
     *
36
     */
37
    public CONST AUTH_AUTO = 3;
38
    /**
39
     *
40
     */
41
    private CONST AUTH_ENUM = [self::AUTH_NONE, self::AUTH_PLAIN, self::AUTH_LOGIN, self::AUTH_AUTO];
42
    /**
43
     * @var ConnectionInterface
44
     */
45
    private $connection;
46
    /**
47
     * @var string
48
     */
49
    private $password = '';
50
    /**
51
     * @var float
52
     */
53
    private $timeout = 1;
54
    /**
55
     * @var string
56
     */
57
    private $username = '';
58
    /**
59
     * @var string
60
     */
61
    private $ehlo = '127.0.0.1';
62
    /**
63
     * @var
64
     */
65
    private $authMethod = self::AUTH_NONE;
66
67
    /**
68
     * ClientFactory constructor.
69
     * @param ConnectionInterface $connection
70
     */
71 8
    public function __construct(ConnectionInterface $connection)
72
    {
73 8
        $this->connection = $connection;
74 8
    }
75
76
    /**
77
     * @param float $connectionTimeout
78
     * @return ClientFactory
79
     */
80 1
    public function withTimeout(float $connectionTimeout): ClientFactory
81
    {
82 1
        $clone = clone $this;
83 1
        $clone->timeout = $connectionTimeout;
84 1
        return $clone;
85
    }
86
87
    /**
88
     * @param int $method
89
     * @param string $password
90
     * @param string $username
91
     * @return ClientFactory
92
     */
93 6
    public function withAuthentication(int $method, string $password, string $username): ClientFactory
94
    {
95 6
        if (!in_array($method, self::AUTH_ENUM)) {
96 1
            throw new \InvalidArgumentException('Invalid authentication method');
97
        }
98
99 5
        $clone = clone $this;
100 5
        $clone->authMethod = $method;
101 5
        $clone->username = $username;
102 5
        $clone->password = $password;
103 5
        return $clone;
104
    }
105
106
    /**
107
     * @param string $ehlo
108
     * @return ClientFactory
109
     */
110 3
    public function withEhlo(string $ehlo): ClientFactory
111
    {
112 3
        $clone = clone $this;
113 3
        $clone->ehlo = $ehlo;
114 3
        return $clone;
115
    }
116
117
    /**
118
     * @return Client
119
     */
120 6
    public function newClient(): Client
121
    {
122 6
        $client = new Client($this->connection);
123 6
        $reply = $client->request(new EhloCommand($this->ehlo));
124 6
        $reply->assertCompleted();
125
126 6
        $ehloResponse = new EhloResponse($reply);
127
128 6
        if ($ehloResponse->isAdvertising('STARTTLS')) {
129
            $client
130 1
                ->request(new StartTlsCommand())
131 1
                ->assertCompleted();
132
133 1
            $this->connection->upgrade(STREAM_CRYPTO_METHOD_TLS_CLIENT);
134
        }
135
136 6
        $method = $this->authMethod;
137 6
        if ($method === ClientFactory::AUTH_AUTO) {
138
            $options = [
139 2
                'AUTH PLAIN' => ClientFactory::AUTH_PLAIN,
140
                'AUTH LOGIN' => ClientFactory::AUTH_LOGIN
141
            ];
142
143 2
            foreach ($options as $advertisement => $auth) {
144 2
                if ($ehloResponse->isAdvertising($advertisement)) {
145 1
                    $method = $auth;
146
                }
147
            }
148
149 2
            if ($method === ClientFactory::AUTH_AUTO) {
150 1
                throw new \RuntimeException('SMTP server does not advertise which AUTH method to use');
151
            }
152
        }
153
154
        switch ($method) {
155 5
            case ClientFactory::AUTH_PLAIN:
156
                $client
157 1
                    ->request(new AuthPlainCommand())
158 1
                    ->assertIntermediate()
159 1
                    ->request(
160 1
                        new AuthPlainCredentialsRequest(
161 1
                            $this->username,
162 1
                            $this->password
163
                        )
164
                    )
165 1
                    ->assertCompleted();
166 1
                break;
167 4
            case ClientFactory::AUTH_LOGIN:
168
                $client
169 2
                    ->request(new AuthLoginCommand())
170 2
                    ->assertIntermediate()
171 2
                    ->request(
172 2
                        new AuthLoginUsernameRequest(
173 2
                            $this->username
174
                        )
175
                    )
176 2
                    ->assertIntermediate()
177 2
                    ->request(
178 2
                        new AuthLoginPasswordRequest(
179 2
                            $this->password
180
                        )
181
                    )
182 2
                    ->assertCompleted();
183 2
                break;
184
        }
185
186 5
        return $client;
187
    }
188
}
189