Client::putEndpoint()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LauLamanApps\NestApi\Http\Adapter\Guzzle;
6
7
use GuzzleHttp\ClientInterface as GuzzleClientInterface;
8
use GuzzleHttp\Exception\RequestException;
9
use LauLamanApps\NestApi\Exception\NestApiException;
10
use LauLamanApps\NestApi\Http\Adapter\Guzzle\Exception\Handler;
11
use LauLamanApps\NestApi\Http\Adapter\Guzzle\Exception\NotFoundException;
12
use LauLamanApps\NestApi\Http\Adapter\Guzzle\Exception\RedirectException;
13
use LauLamanApps\NestApi\Http\ClientInterface;
14
use LauLamanApps\NestApi\Http\Endpoint\Exception\EndpointCouldNotBeMappedException;
15
use LauLamanApps\NestApi\Http\Endpoint\MapperInterface;
16
use LauLamanApps\NestApi\Http\Exception\ApiCallException;
17
use Psr\Http\Message\ResponseInterface;
18
19
final class Client implements ClientInterface
20
{
21
    /**
22
     * @var GuzzleClientInterface
23
     */
24
    private $guzzleClient;
25
26
    /**
27
     * @var MapperInterface
28
     */
29
    private $endpointMapper;
30
31 8
    public function __construct(
32
        GuzzleClientInterface $guzzleClient,
33
        MapperInterface $urlMapper
34
    ) {
35 8
        $this->guzzleClient = $guzzleClient;
36 8
        $this->endpointMapper = $urlMapper;
37 8
    }
38
39
    /**
40
     * @throws EndpointCouldNotBeMappedException
41
     * @throws NestApiException
42
     * @throws NotFoundException
43
     */
44 2
    public function getEndpoint(string $endpoint, ?array $urlBits = []): ResponseInterface
45
    {
46 2
        return $this->get(
47 2
            $this->endpointMapper->map($endpoint, $urlBits)
0 ignored issues
show
Bug introduced by
It seems like $urlBits can also be of type null; however, parameter $bits of LauLamanApps\NestApi\Htt...\MapperInterface::map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

47
            $this->endpointMapper->map($endpoint, /** @scrutinizer ignore-type */ $urlBits)
Loading history...
48
        );
49
    }
50
51
    /**
52
     * @throws NestApiException
53
     * @throws NotFoundException
54
     * @return ResponseInterface
55
     */
56 2
    public function getUrl(string $url): ResponseInterface
57
    {
58 2
        return $this->get($url);
59
    }
60
61 1
    public function getJson(ResponseInterface $response): string
62
    {
63 1
        return (string) $response->getBody();
64
    }
65
66
    /**
67
     * @throws NotFoundException
68
     * @throws NestApiException
69
     */
70 4
    private function get(string $url, ?array $options = []): ResponseInterface
71
    {
72
        try {
73 4
            $response = $this->guzzleClient->get($url, $options);
74
75 3
            $this->wasSuccessfulRequest($response);
76
77 3
            return $response;
78 2
        } catch (RedirectException $exception) {
79 1
            return $this->get($exception->getLocation(), $options);
80 1
        } catch (RequestException $exception) {
81 1
            Handler::handleRequestException($exception);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Psr\Http\Message\ResponseInterface. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
82
        }
83
    }
84
85
    /**
86
     * @throws NestApiException
87
     */
88 3
    public function putEndpoint(string $endpoint, array $urlBits = null, array $data): ResponseInterface
89
    {
90 3
        return $this->put(
91 3
            $this->endpointMapper->map($endpoint, $urlBits),
0 ignored issues
show
Bug introduced by
It seems like $urlBits can also be of type null; however, parameter $bits of LauLamanApps\NestApi\Htt...\MapperInterface::map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
            $this->endpointMapper->map($endpoint, /** @scrutinizer ignore-type */ $urlBits),
Loading history...
92 3
            ['json' => $data]
93
        );
94
    }
95
96
    /**
97
     * @throws ApiCallException
98
     * @throws NestApiException
99
     * @throws NotFoundException
100
     */
101 3
    private function put(string $url, ?array $options = []): ResponseInterface
102
    {
103
        try {
104 3
            $response = $this->guzzleClient->put($url, $options);
105 2
            $this->wasSuccessfulRequest($response);
106
107 2
            return $response;
108 2
        } catch (RedirectException $exception) {
109 1
            return $this->put($exception->getLocation(), $options);
110 1
        } catch (RequestException $exception) {
111 1
            Handler::handleRequestException($exception);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Psr\Http\Message\ResponseInterface. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
112
        }
113
    }
114
115
    /**
116
     * @throws RedirectException
117
     * @throws ApiCallException
118
     */
119 5
    private function wasSuccessfulRequest(ResponseInterface $response): void
120
    {
121 5
        switch ($response->getStatusCode()) {
122 5
            case 307:
123 2
                throw new RedirectException($response->getHeader('Location')[0]);
124
125
                break;
126 5
            case 200:
127 5
                return;
128
129
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
130
            default:
131
                throw new ApiCallException($response-> getStatusCode() . ' ' . $response->getReasonPhrase());
132
        }
133
    }
134
}
135