HttpClientCall::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
declare(strict_types=1);
8
9
namespace Tebru\Retrofit\Internal;
10
11
use Psr\Http\Message\RequestInterface;
12
use Psr\Http\Message\ResponseInterface;
13
use Tebru\Retrofit\Call;
14
use Tebru\Retrofit\Exception\ResponseHandlingFailedException;
15
use Tebru\Retrofit\HttpClient;
16
use Tebru\Retrofit\Response;
17
use Throwable;
18
19
/**
20
 * Class HttpClientCall
21
 *
22
 * @author Nate Brunette <[email protected]>
23
 */
24
final class HttpClientCall implements Call
25
{
26
    /**
27
     * A retrofit http client implementation
28
     *
29
     * @var HttpClient
30
     */
31
    private $client;
32
33
    /**
34
     * A web service resource as a method model
35
     *
36
     * @var ServiceMethod
37
     */
38
    private $serviceMethod;
39
40
    /**
41
     * The runtime arguments that a request should be constructed with
42
     *
43
     * @var array
44
     */
45
    private $args;
46
47
    /**
48
     * The constructed request
49
     *
50
     * @var RequestInterface
51
     */
52
    private $request;
53
54
    /**
55
     * Constructor
56
     *
57
     * @param HttpClient $client
58
     * @param ServiceMethod $serviceMethod
59
     * @param array $args
60
     */
61 25
    public function __construct(HttpClient $client, ServiceMethod $serviceMethod, array $args)
62
    {
63 25
        $this->client = $client;
64 25
        $this->serviceMethod = $serviceMethod;
65 25
        $this->args = $args;
66 25
    }
67
68
    /**
69
     * Execute request synchronously
70
     *
71
     * A [@see Response] will be returned
72
     *
73
     * @return Response
74
     */
75 18
    public function execute(): Response
76
    {
77 18
        $response = $this->client->send($this->request());
78
79 18
        return $this->createResponse($response);
80
    }
81
82
    /**
83
     * Execute request asynchronously
84
     *
85
     * This method accepts two optional callbacks.
86
     *
87
     * onResponse() will be called for any request that gets a response,
88
     * whether it was successful or not. It will send a [@see Response] as
89
     * the parameter.
90
     *
91
     * onFailure() will be called in the event a network request failed. It
92
     * will send the [@see Throwable] that was encountered.
93
     *
94
     * Example of method signatures:
95
     *
96
     * $call->enqueue(
97
     *     function (\Tebru\Retrofit\Call $call, \Tebru\Retrofit\Response $response) {},
98
     *     function (\Throwable $throwable) {}
99
     * );
100
     *
101
     * @param callable $onResponse On any response
102
     * @param callable $onFailure On any network request failure
103
     * @return Call
104
     * @throws \LogicException
105
     */
106 6
    public function enqueue(?callable $onResponse = null, ?callable $onFailure = null): Call
107
    {
108 6
        $this->client->sendAsync(
109 6
            $this->request(),
110
            function (ResponseInterface $response) use ($onResponse) {
111 4
                if ($onResponse !== null) {
112 4
                    $onResponse($this->createResponse($response));
113
                }
114 6
            },
115
            function (Throwable $throwable) use ($onFailure) {
116 2
                if ($onFailure === null) {
117 1
                    throw $throwable;
118
                }
119
120 1
                $onFailure($throwable);
121 6
            }
122
        );
123
124 6
        return $this;
125
    }
126
127
    /**
128
     * When making requests asynchronously, call wait() to execute the requests
129
     *
130
     * @return void
131
     */
132 6
    public function wait(): void
133
    {
134 6
        $this->client->wait();
135 3
    }
136
137
    /**
138
     * Get the PSR-7 request
139
     *
140
     * @return RequestInterface
141
     */
142 24
    public function request(): RequestInterface
143
    {
144 24
        if ($this->request === null) {
145 24
            $this->request = $this->serviceMethod->toRequest($this->args);
146
        }
147
148 24
        return $this->request;
149
    }
150
151
    /**
152
     * Create a [@see Response] from a PSR-7 response
153
     *
154
     * @param ResponseInterface $response
155
     * @return RetrofitResponse
156
     */
157 22
    private function createResponse(ResponseInterface $response): RetrofitResponse
158
    {
159 22
        $code = $response->getStatusCode();
160 22
        if ($code >= 200 && $code < 300) {
161
            try {
162 18
                $responseBody = $this->serviceMethod->toResponseBody($response);
163 2
            } catch (Throwable $throwable) {
164 2
                throw new ResponseHandlingFailedException(
165 2
                    $this->request(),
166 2
                    $response,
167 2
                    'Retrofit: Could not convert response body',
168 2
                    $throwable
169
                );
170
            }
171
172 16
            return new RetrofitResponse($response, $responseBody, null);
173
        }
174
175
        try {
176 4
            $errorBody = $this->serviceMethod->toErrorBody($response);
177 2
        } catch (Throwable $throwable) {
178 2
            throw new ResponseHandlingFailedException(
179 2
                $this->request(),
180 2
                $response,
181 2
                'Retrofit: Could not convert error body',
182 2
                $throwable
183
            );
184
        }
185
186 2
        return new RetrofitResponse($response, null, $errorBody);
187
    }
188
}
189