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

ApiClientTrait::loadEndpoints()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
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