Completed
Pull Request — master (#72)
by Nate
03:35
created

DefaultServiceMethodBuilder::build()   C

Complexity

Conditions 14
Paths 12

Size

Total Lines 74
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 74
rs 5.3785
c 0
b 0
f 0
cc 14
eloc 42
nc 12
nop 0

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
/*
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\ServiceMethod;
10
11
use LogicException;
12
use Tebru\Retrofit\CallAdapter;
13
use Tebru\Retrofit\ParameterHandler;
14
use Tebru\Retrofit\ResponseBodyConverter;
15
use Tebru\Retrofit\ServiceMethodBuilder;
16
17
/**
18
 * Class DefaultServiceMethodBuilder
19
 *
20
 * Constructs a [@ServiceMethod]
21
 *
22
 * @author Nate Brunette <[email protected]>
23
 */
24
final class DefaultServiceMethodBuilder implements ServiceMethodBuilder
25
{
26
    /**
27
     * The request method
28
     *
29
     * @var string
30
     */
31
    private $method;
32
33
    /**
34
     * The request base url
35
     *
36
     * @var string
37
     */
38
    private $baseUrl;
39
40
    /**
41
     * The request path
42
     *
43
     * @var string
44
     */
45
    private $path;
46
47
    /**
48
     * True if the request has a body
49
     *
50
     * @var bool
51
     */
52
    private $hasBody;
53
54
    /**
55
     * The request body content type
56
     *
57
     * @var string
58
     */
59
    private $contentType;
60
61
    /**
62
     * Array of headers
63
     *
64
     * @var array
65
     */
66
    private $headers = [];
67
68
    /**
69
     * Array of Parameter handlers, indexed to match the position of the parameters
70
     *
71
     * @var ParameterHandler[]
72
     */
73
    private $parameterHandlers = [];
74
75
    /**
76
     * Converts successful response bodies to expected value
77
     *
78
     * @var ResponseBodyConverter
79
     */
80
    private $responseBodyConverter;
81
82
    /**
83
     * Converts error response bodies to expected value
84
     *
85
     * @var ResponseBodyConverter
86
     */
87
    private $errorBodyConverter;
88
89
    /**
90
     * Adapts a [@see Call] to expected value
91
     *
92
     * @var CallAdapter
93
     */
94
    private $callAdapter;
95
96
    /**
97
     * Set the request method (e.g. GET, POST)
98
     *
99
     * @param string $method
100
     * @return ServiceMethodBuilder
101
     * @throws \LogicException
102
     */
103
    public function setMethod(string $method): ServiceMethodBuilder
104
    {
105
        if ($this->method !== null) {
106
            throw new LogicException(sprintf(
107
                'Retrofit: Only one http method is allowed. Trying to set %s, but %s already exists',
108
                strtoupper($method),
109
                $this->method
110
            ));
111
        }
112
113
        $this->method = strtoupper($method);
114
115
        return $this;
116
    }
117
118
    /**
119
     * Set the request base url (e.g. http://example.com)
120
     *
121
     * @param string $baseUrl
122
     * @return ServiceMethodBuilder
123
     */
124
    public function setBaseUrl(string $baseUrl): ServiceMethodBuilder
125
    {
126
        $this->baseUrl = $baseUrl;
127
128
        return $this;
129
    }
130
131
    /**
132
     * Set the request path
133
     *
134
     * @param string $path
135
     * @return ServiceMethodBuilder
136
     */
137
    public function setPath(string $path): ServiceMethodBuilder
138
    {
139
        $this->path = $path;
140
141
        return $this;
142
    }
143
144
    /**
145
     * Set to true if an annotation exists that denotes a request body. This should also set
146
     * the request content type.
147
     *
148
     * @param bool $hasBody
149
     * @return ServiceMethodBuilder
150
     * @throws \LogicException
151
     */
152
    public function setHasBody(bool $hasBody): ServiceMethodBuilder
153
    {
154
        if ($this->hasBody !== null && $this->hasBody !== $hasBody) {
155
            throw new LogicException(
156
                'Retrofit: Body cannot be changed after it has been set. This indicates a conflict between ' .
157
                'HTTP Request annotations, body annotations, and request type annotations. For example, ' .
158
                '@GET cannot be used with @Body, @Field, or @Part annotations'
159
            );
160
        }
161
162
        $this->hasBody = $hasBody;
163
164
        return $this;
165
    }
166
167
    /**
168
     * Set the content type of the request. A content type should not be set if there
169
     * isn't a request body.
170
     *
171
     * @param string $contentType
172
     * @return ServiceMethodBuilder
173
     * @throws \LogicException
174
     */
175
    public function setContentType(string $contentType): ServiceMethodBuilder
176
    {
177
        if ($this->contentType !== null && $this->contentType !== $contentType) {
178
            throw new LogicException(
179
                'Retrofit: Content type cannot be changed after it has been set. This indicates a conflict between ' .
180
                'HTTP Request annotations, body annotations, and request type annotations. For example, ' .
181
                '@GET cannot be used with @Body, @Field, or @Part annotations'
182
            );
183
        }
184
185
        $this->contentType = $contentType;
186
187
        return $this;
188
    }
189
190
    /**
191
     * Convenience method to declare that the request has content and is json
192
     *
193
     * @return ServiceMethodBuilder
194
     * @throws \LogicException
195
     */
196
    public function setIsJson(): ServiceMethodBuilder
197
    {
198
        $this->setHasBody(true);
199
        $this->setContentType('application/json');
200
201
        return $this;
202
    }
203
204
205
    /**
206
     * Convenience method to declare that the request has content and is form encoded
207
     *
208
     * @return ServiceMethodBuilder
209
     * @throws \LogicException
210
     */
211
    public function setIsFormUrlEncoded(): ServiceMethodBuilder
212
    {
213
        $this->setHasBody(true);
214
        $this->setContentType('application/x-www-form-urlencoded');
215
216
        return $this;
217
    }
218
219
    /**
220
     * Convenience method to declare that the request has content and is multipart
221
     *
222
     * @return ServiceMethodBuilder
223
     * @throws \LogicException
224
     */
225
    public function setIsMultipart(): ServiceMethodBuilder
226
    {
227
        $this->setHasBody(true);
228
        $this->setContentType('multipart/form-data');
229
230
        return $this;
231
    }
232
233
    /**
234
     * Add a request header. Header name should be normalized.
235
     *
236
     * @param string $name
237
     * @param string $header
238
     * @return ServiceMethodBuilder
239
     */
240
    public function addHeader(string $name, string $header): ServiceMethodBuilder
241
    {
242
        $this->headers[strtolower($name)][] = $header;
243
244
        return $this;
245
    }
246
247
    /**
248
     * Add a [@see ParameterHandler] at the position the parameter exists
249
     *
250
     * @param int $index
251
     * @param ParameterHandler $parameterHandler
252
     * @return ServiceMethodBuilder
253
     */
254
    public function addParameterHandler(int $index, ParameterHandler $parameterHandler): ServiceMethodBuilder
255
    {
256
        $this->parameterHandlers[$index] = $parameterHandler;
257
258
        return $this;
259
    }
260
261
    /**
262
     * Set the [@see CallAdapter]
263
     *
264
     * @param CallAdapter $callAdapter
265
     * @return ServiceMethodBuilder
266
     */
267
    public function setCallAdapter(CallAdapter $callAdapter): ServiceMethodBuilder
268
    {
269
        $this->callAdapter = $callAdapter;
270
271
        return $this;
272
    }
273
274
    /**
275
     * Set the response body converter to convert successful responses
276
     *
277
     * @param ResponseBodyConverter $responseBodyConverter
278
     * @return ServiceMethodBuilder
279
     */
280
    public function setResponseBodyConverter(ResponseBodyConverter $responseBodyConverter): ServiceMethodBuilder
281
    {
282
        $this->responseBodyConverter = $responseBodyConverter;
283
284
        return $this;
285
    }
286
287
    /**
288
     * Set the response body converter to convert error responses
289
     *
290
     * @param ResponseBodyConverter $errorBodyConverter
291
     * @return ServiceMethodBuilder
292
     */
293
    public function setErrorBodyConverter(ResponseBodyConverter $errorBodyConverter): ServiceMethodBuilder
294
    {
295
        $this->errorBodyConverter = $errorBodyConverter;
296
297
        return $this;
298
    }
299
300
    /**
301
     * Create a new [@see DefaultServiceMethod] from previously set parameters
302
     *
303
     * @return DefaultServiceMethod
304
     * @throws \LogicException
305
     */
306
    public function build(): DefaultServiceMethod
307
    {
308
        if ($this->method === null) {
309
            throw new LogicException(
310
                'Retrofit: Cannot build service method without HTTP method. Please specify @GET, @POST, etc'
311
            );
312
        }
313
314
        if ($this->baseUrl === null) {
315
            throw new LogicException(
316
                'Retrofit: Cannot build service method without base url. Please specify on RetrofitBuilder'
317
            );
318
        }
319
320
        if ($this->path === null) {
321
            throw new LogicException(
322
                'Retrofit: Cannot build service method without HTTP method. Please specify @GET, @POST, etc'
323
            );
324
        }
325
326
        if ($this->hasBody === true && $this->contentType === null) {
327
            throw new LogicException(
328
                'Retrofit: Cannot build service method with body and no content type. Set one using @Body, ' .
329
                '@Field, or @Part'
330
            );
331
        }
332
333
        if ($this->hasBody !== true && $this->contentType !== null) {
334
            throw new LogicException(
335
                'Retrofit: Cannot set a content-type without a body. This indicates a conflict between ' .
336
                'HTTP Request annotations, body annotations, and request type annotations. For example, ' .
337
                '@GET cannot be used with @Body, @Field, or @Part annotations'
338
            );
339
        }
340
341
        if ($this->responseBodyConverter === null) {
342
            throw new LogicException(
343
                'Retrofit: Cannot build service method without response body converter'
344
            );
345
        }
346
347
        if ($this->errorBodyConverter === null) {
348
            throw new LogicException(
349
                'Retrofit: Cannot build service method without error body converter'
350
            );
351
        }
352
353
        if ($this->callAdapter === null) {
354
            throw new LogicException(
355
                'Retrofit: Cannot build service method without call adapter'
356
            );
357
        }
358
359
        if ($this->contentType !== null && !isset($this->headers['content-type'])) {
360
            $this->addHeader('content-type', $this->contentType);
361
        }
362
363
        if ($this->hasBody === null) {
364
            $this->hasBody = false;
365
        }
366
367
        ksort($this->parameterHandlers);
368
369
        return new DefaultServiceMethod(
370
            $this->method,
371
            $this->baseUrl,
372
            $this->path,
373
            $this->headers,
374
            $this->parameterHandlers,
375
            $this->callAdapter,
376
            $this->responseBodyConverter,
377
            $this->errorBodyConverter
378
        );
379
    }
380
}
381