Completed
Pull Request — master (#88)
by Frederik
01:40
created

AuthNegotiation::negotiate()   C

Complexity

Conditions 11
Paths 17

Size

Total Lines 77

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 11

Importance

Changes 0
Metric Value
dl 0
loc 77
ccs 43
cts 43
cp 1
rs 6.3551
c 0
b 0
f 0
cc 11
nc 17
nop 1
crap 11

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\Negotiation;
5
6
use Genkgo\Mail\Exception\AssertionFailedException;
7
use Genkgo\Mail\Exception\ImapAuthenticationException;
8
use Genkgo\Mail\Protocol\Imap\Client;
9
use Genkgo\Mail\Protocol\Imap\NegotiationInterface;
10
use Genkgo\Mail\Protocol\Imap\Request\AuthPlainCommand;
11
use Genkgo\Mail\Protocol\Imap\Request\AuthPlainCredentialsRequest;
12
use Genkgo\Mail\Protocol\Imap\Request\CapabilityCommand;
13
use Genkgo\Mail\Protocol\Imap\Request\LoginCommand;
14
use Genkgo\Mail\Protocol\Imap\Response\Command\CapabilityCommandResponse;
15
use Genkgo\Mail\Protocol\Imap\Response\CompletionResult;
16
17
final class AuthNegotiation implements NegotiationInterface
18
{
19
    /**
20
     * @var int
21
     */
22
    private $method;
23
24
    /**
25
     * @var string
26
     */
27
    private $username;
28
29
    /**
30
     * @var string
31
     */
32
    private $password;
33
34
    /**
35
     * @param int $method
36
     * @param string $username
37
     * @param string $password
38
     */
39 8
    public function __construct(int $method, string $username, string $password)
40
    {
41 8
        $this->method = $method;
42 8
        $this->username = $username;
43 8
        $this->password = $password;
44 8
    }
45
46
    /**
47
     * @param Client $client
48
     * @throws ImapAuthenticationException
49
     */
50 7
    public function negotiate(Client $client): void
51
    {
52 7
        $method = $this->method;
53 7
        if ($method === Client::AUTH_AUTO) {
54 5
            $responseList = $client->emit(new CapabilityCommand($client->newTag()));
55
56 5
            $capabilities = CapabilityCommandResponse::fromString($responseList->first()->getBody());
57
58
            $responseList
59 5
                ->last()
60 5
                ->assertCompletion(CompletionResult::ok())
61 5
                ->assertTagged();
62
63
            $options = [
64 5
                'AUTH=PLAIN' => Client::AUTH_PLAIN,
65
            ];
66
67 5
            foreach ($options as $capability => $auth) {
68 5
                if ($capabilities->isAdvertising($capability)) {
69 2
                    $method = $auth;
70
                }
71
            }
72
73 5
            if ($method === Client::AUTH_AUTO && !$capabilities->isAdvertising('LOGINDISABLED')) {
74 2
                $method = Client::AUTH_LOGIN;
75
            }
76
77 5
            if ($method === Client::AUTH_AUTO) {
78 1
                throw new ImapAuthenticationException(
79 1
                    'IMAP server does not advertise one the supported AUTH methods (AUTH PLAIN)'
80
                );
81
            }
82
        }
83
84 6
        switch ($method) {
85
            case Client::AUTH_PLAIN:
86 4
                $tag = $client->newTag();
87
                $client
88 4
                    ->emit(new AuthPlainCommand($tag))
89 4
                    ->first()
90 4
                    ->assertContinuation();
91
92
                $taggedResponse = $client
93 4
                    ->emit(
94 4
                        new AuthPlainCredentialsRequest(
95 4
                            $tag,
96 4
                            $this->username,
97 4
                            $this->password
98
                        )
99
                    )
100 4
                    ->last()
101 4
                    ->assertTagged();
102
103
                try {
104 4
                    $taggedResponse->assertCompletion(CompletionResult::ok());
105 1
                } catch (AssertionFailedException $e) {
106 1
                    throw new ImapAuthenticationException(
107 1
                        'Failed to authenticate: ' . $taggedResponse->getBody()
108
                    );
109
                }
110 3
                break;
111
            case Client::AUTH_LOGIN:
112
                $taggedResponse = $client
113 2
                    ->emit(new LoginCommand($client->newTag(), $this->username, $this->password))
114 2
                    ->last()
115 2
                    ->assertTagged();
116
117
                try {
118 2
                    $taggedResponse->assertCompletion(CompletionResult::ok());
119 1
                } catch (AssertionFailedException $e) {
120 1
                    throw new ImapAuthenticationException(
121 1
                        'Failed to authenticate: ' . $taggedResponse->getBody()
122
                    );
123
                }
124 1
                break;
125
        }
126 4
    }
127
}
128