Passed
Push — master ( c14bee...a86645 )
by Jasper
02:49
created

HttpClient::fetchToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2.1481

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 14
ccs 2
cts 3
cp 0.6667
rs 10
cc 2
nc 2
nop 0
crap 2.1481
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Swis\Melvin;
6
7
use Http\Discovery\Psr17FactoryDiscovery;
8
use Http\Discovery\Psr18ClientDiscovery;
9
use Psr\Http\Client\ClientExceptionInterface;
10
use Psr\Http\Client\ClientInterface;
11
use Psr\Http\Message\RequestFactoryInterface;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\StreamFactoryInterface;
14
use Swis\Melvin\Exceptions\AuthenticationException;
15
use Swis\Melvin\Exceptions\RequestException;
16
17
class HttpClient
18
{
19
    private string $baseUrl = 'https://melvin.ndw.nu/melvinservice/rest/';
20
21
    private string $username;
22
23
    private string $password;
24
25
    private string $token;
26
27
    protected ClientInterface $httpClient;
28
29
    protected RequestFactoryInterface $requestFactory;
30
31
    protected StreamFactoryInterface $streamFactory;
32
33 4
    public function __construct(
34
        string $username,
35
        string $password,
36
        ?ClientInterface $httpClient = null,
37
        ?RequestFactoryInterface $requestFactory = null,
38
        ?StreamFactoryInterface $streamFactory = null
39
    ) {
40 4
        $this->authenticate($username, $password);
41 4
        $this->httpClient = $httpClient ?: Psr18ClientDiscovery::find();
42 4
        $this->requestFactory = $requestFactory ?: Psr17FactoryDiscovery::findRequestFactory();
43 4
        $this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory();
44 4
    }
45
46
    /**
47
     * @param mixed|null $body
48
     *
49
     * @throws \JsonException
50
     * @throws \Swis\Melvin\Exceptions\AuthenticationException
51
     * @throws \Swis\Melvin\Exceptions\RequestException
52
     *
53
     * @return mixed
54
     */
55 4
    public function request(string $method, string $uri, $body = null)
56
    {
57 4
        $request = $this->createRequest($method, $uri, $body)
58 4
            ->withHeader('melvin-user-token', $this->getToken());
59
60 4
        return $this->sendRequest($request);
61
    }
62
63
    /**
64
     * @param string $username
65
     * @param string $password
66
     *
67
     * @return $this
68
     */
69 4
    public function authenticate(string $username, string $password): self
70
    {
71 4
        $this->username = $username;
72 4
        $this->password = $password;
73
74 4
        return $this;
75
    }
76
77
    /**
78
     * @param string $baseUrl
79
     *
80
     * @return $this
81
     */
82
    public function setBaseUrl(string $baseUrl): self
83
    {
84
        $this->baseUrl = $baseUrl;
85
86
        return $this;
87
    }
88
89
    /**
90
     * @param mixed|null $body
91
     *
92
     * @throws \JsonException
93
     */
94 4
    protected function createRequest(string $method, string $uri, $body = null): RequestInterface
95
    {
96 4
        $request = $this->requestFactory->createRequest($method, $this->baseUrl.ltrim($uri, '/'));
97
98 4
        if ($body !== null) {
99 4
            $request = $request->withBody($this->streamFactory->createStream(json_encode($body, JSON_THROW_ON_ERROR)))
100 4
                ->withHeader('Content-Type', 'application/json');
101
        }
102
103 4
        return $request;
104
    }
105
106
    /**
107
     * @throws \JsonException
108
     * @throws \Swis\Melvin\Exceptions\RequestException
109
     *
110
     * @return mixed
111
     */
112 4
    protected function sendRequest(RequestInterface $request)
113
    {
114
        try {
115 4
            $response = $this->httpClient->sendRequest($request);
116
        } catch (ClientExceptionInterface $exception) {
117
            throw RequestException::create($request, null, $exception);
118
        }
119
120 4
        if ($response->getStatusCode() !== 200) {
121
            throw RequestException::create($request, $response);
122
        }
123
124 4
        $responseBody = (string) $response->getBody();
125
126 4
        return json_decode($responseBody, false, 512, JSON_THROW_ON_ERROR);
127
    }
128
129
    /**
130
     * @throws \JsonException
131
     * @throws \Swis\Melvin\Exceptions\AuthenticationException
132
     * @throws \Swis\Melvin\Exceptions\RequestException
133
     */
134 4
    protected function getToken(): string
135
    {
136 4
        if (!isset($this->token)) {
137
            $this->token = $this->fetchToken();
138
        }
139
140 4
        return $this->token;
141 4
    }
142 4
143 4
    /**
144
     * @throws \JsonException
145 4
     * @throws \Swis\Melvin\Exceptions\AuthenticationException
146
     * @throws \Swis\Melvin\Exceptions\RequestException
147 4
     */
148
    protected function fetchToken(): string
149
    {
150
        $request = $this->createRequest(
151 4
            'POST',
152
            'authenticate/login',
153 4
            ['username' => $this->username, 'password' => $this->password]
154
        );
155
        $result = $this->sendRequest($request);
156
157
        if ($result->result !== 'SUCCESS') {
158
            throw new AuthenticationException('Failed to authenticate');
159
        }
160
161
        return $result->userToken;
162
    }
163
}
164