Completed
Push — master ( d86fa2...f0cf12 )
by smiley
02:15
created

ApiClientTrait::__call()   F

Complexity

Conditions 17
Paths 469

Size

Total Lines 71

Duplication

Lines 9
Ratio 12.68 %

Importance

Changes 0
Metric Value
cc 17
nc 469
nop 2
dl 9
loc 71
rs 1.7874
c 0
b 0
f 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
 * Trait ApiClientTrait
4
 *
5
 * @filesource   ApiClientTrait.php
6
 * @created      07.04.2018
7
 * @package      chillerlan\HTTP\MagicAPI
8
 * @author       smiley <[email protected]>
9
 * @copyright    2018 smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\HTTP\MagicAPI;
14
15
use chillerlan\HTTP\Psr7;
16
use Psr\Http\Message\ResponseInterface;
17
use Psr\Log\LoggerInterface;
18
use ReflectionClass;
19
20
/**
21
 * @link http://php.net/manual/language.oop5.magic.php#118617
22
 *
23
 * @implements chillerlan\MagicAPI\ApiClientInterface
24
 *
25
 * from \chillerlan\HTTP\HTTPClientInterface:
26
 * @method request(string $url, string $method = null, array $params = null, $body = null, array $headers = null):ResponseInterface
27
 */
28
trait ApiClientTrait{
29
30
	/**
31
	 * The logger instance.
32
	 *
33
	 * @var \Psr\Log\LoggerInterface
34
	 */
35
	protected $logger;
36
37
	/**
38
	 * @var \chillerlan\HTTP\MagicAPI\EndpointMapInterface
39
	 *
40
	 * method => [url, method, mandatory_params, params_in_url, ...]
41
	 */
42
	protected $endpoints;
43
44
	/**
45
	 * @param string $endpointMap
46
	 *
47
	 * @return \chillerlan\HTTP\MagicAPI\ApiClientInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be ApiClientTrait?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
48
	 * @throws \chillerlan\HTTP\MagicAPI\ApiClientException
49
	 */
50
	public function loadEndpoints(string $endpointMap):ApiClientInterface{
51
52
		if(class_exists($endpointMap)){
53
			$this->endpoints = new $endpointMap;
54
55
			if(!$this->endpoints instanceof EndpointMapInterface){
56
				throw new ApiClientException('invalid endpoint map');
57
			}
58
		}
59
60
		/** @noinspection PhpIncompatibleReturnTypeInspection */
61
		return $this;
62
	}
63
64
	/**
65
	 * ugly, isn't it?
66
	 * @todo WIP
67
	 *
68
	 * @param string $name
69
	 * @param array  $arguments
70
	 *
71
	 * @return \Psr\Http\Message\ResponseInterface
72
	 * @throws \chillerlan\HTTP\MagicAPI\APIClientException
73
	 */
74
	public function __call(string $name, array $arguments):ResponseInterface{
75
76
		if(!$this->endpoints instanceof EndpointMapInterface || !$this->endpoints->__isset($name)){
77
			throw new ApiClientException('endpoint not found');
78
		}
79
80
		$m = $this->endpoints->{$name};
81
82
		$endpoint      = $this->endpoints->API_BASE.$m['path'];
83
		$method        = $m['method'] ?? 'GET';
84
		$body          = null;
85
		$headers       = isset($m['headers']) && is_array($m['headers']) ? $m['headers'] : [];
86
		$path_elements = $m['path_elements'] ?? [];
87
		$params_in_url = count($path_elements);
88
		$params        = $arguments[$params_in_url] ?? [];
89
		$urlparams     = array_slice($arguments, 0, $params_in_url);
90
91
		if($params_in_url > 0){
92
93
			if(count($urlparams) < $params_in_url){
94
				throw new APIClientException('too few URL params, required: '.implode(', ', $path_elements));
95
			}
96
97
			$endpoint = sprintf($endpoint, ...$urlparams);
98
		}
99
100
		if(in_array($method, ['DELETE', 'POST', 'PATCH', 'PUT'], true)){
101
			$body = $arguments[$params_in_url + 1] ?? $params;
102
103
			if($params === $body){
104
				$params = [];
105
			}
106
107
			if(is_iterable($body)){
108
				$body = Psr7\clean_query_params($body);
109
			}
110
111
112
			if((is_array($body) || is_object($body)) && !empty($body)){
113
114
				if(!isset($headers['Content-type'])){
115
					$headers['Content-type'] = 'application/x-www-form-urlencoded';
116
				}
117
118 View Code Duplication
				if($headers['Content-type'] === 'application/x-www-form-urlencoded'){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
119
					$body = http_build_query($body, '', '&', PHP_QUERY_RFC1738);
120
				}
121
				elseif($headers['Content-type'] === 'application/json'){
122
					$body = json_encode($body);
123
				}
124
				else{
125
					$body = null; // @todo
126
				}
127
128
			}
129
130
131
		}
132
133
		$params = Psr7\clean_query_params($params);
134
135
		if($this->logger instanceof LoggerInterface){
136
137
			$this->logger->debug('ApiClientTrait::__call() -> '.(new ReflectionClass($this))->getShortName().'::'.$name.'()', [
138
				'$endpoint' => $endpoint, '$method' => $method, '$params' => $params, '$body' => $body, '$headers' => $headers,
139
			]);
140
141
		}
142
143
		return $this->request($endpoint, $method, $params, $body, $headers);
144
	}
145
146
}
147