Completed
Push — master ( 7d15ad...041b6d )
by Mehmet
03:10
created

Client   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 104
dl 0
loc 201
rs 10
c 0
b 0
f 0
wmc 19

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A getEndpoint() 0 10 3
A withAirlineCode() 0 5 1
A __call() 0 3 1
A request() 0 23 2
A endpointFactory() 0 7 2
A getQueryParams() 0 20 4
A withLanguageCode() 0 5 1
A httpRequest() 0 35 4
1
<?php declare(strict_types=1);
2
3
/**
4
 * @package TK\API
5
 * @author Mehmet Korkmaz <[email protected]>
6
 * @license https://opensource.org/licenses/mit-license.php MIT
7
 *
8
 * Documentation can be found at https://developer.turkishairlines.com/documentation/
9
 */
10
11
namespace TK\API;
12
13
use GuzzleHttp\Client as GuzzleClient;
14
use Psr\Http\Message\ResponseInterface;
15
use Psr\Log\LoggerInterface;
16
use TK\API\Endpoint\EndpointInterface;
17
use TK\API\Exception\InvalidArgumentException;
18
use TK\API\Exception\BadMethodCallException;
19
use TK\API\Exception\RequestException;
20
use TypeError;
21
use GuzzleHttp\Exception\RequestException as GuzzleRequestException;
22
use Ulid\Ulid;
23
24
final class Client
25
{
26
    public const HTTP_POST = 'POST';
27
    public const HTTP_GET = 'GET';
28
    /**
29
     * @var array
30
     */
31
    private static $validEndpoints = [
32
33
        'getAvailability',
34
        'getTimetable',
35
        'getPortList',
36
        'rejectActions',
37
        'getFareFamilyList',
38
        'retrieveReservationDetail',
39
        'calculateFlightMiles',
40
        'calculateAwardMilesWithTax'
41
    ];
42
43
44
    /**
45
     * @var Environment
46
     */
47
    private $environment;
48
    /**
49
     * @var GuzzleClient
50
     */
51
    private $guzzleClient;
52
53
    private $logger;
54
    private $languageCode;
55
    private $airlineCode;
56
57
58
    private $headers = [
59
        'User-Agent' => 'mkorkmaz/tk-api-php-client 2.0'
60
    ];
61
62
    /**
63
     * Client constructor.
64
     * @param Environment $environment
65
     * @param GuzzleClient $guzzleClient
66
     * @param LoggerInterface $logger
67
     */
68
    public function __construct(Environment $environment, GuzzleClient $guzzleClient, LoggerInterface $logger)
69
    {
70
        $this->environment = $environment;
71
        $this->headers['apiKey'] = $environment->getApiKey();
72
        $this->headers['apiSecret'] = $environment->getApiSecret();
73
        $this->guzzleClient = $guzzleClient;
74
        $this->logger = $logger;
75
        $this->airlineCode = 'TK';
76
        $this->languageCode = 'TR';
77
    }
78
79
    public function withAirlineCode(string $airlineCode) : self
80
    {
81
        $new = clone $this;
82
        $new->airlineCode = $airlineCode;
83
        return $new;
84
    }
85
86
    public function withLanguageCode(string $languageCode) : self
87
    {
88
        $new = clone $this;
89
        $new->languageCode = $languageCode;
90
        return $new;
91
    }
92
    /**
93
     * @param $name
94
     * @param $arguments
95
     * @throws BadMethodCallException
96
     * @throws RequestException
97
     * @throws InvalidArgumentException
98
     * @return array
99
     */
100
    public function __call(string $name, array $arguments)
101
    {
102
        return $this->request($this->getEndpoint($name, $arguments));
103
    }
104
105
106
    private function getEndpoint(string $name, array $arguments) : EndpointInterface
107
    {
108
        $namespace = '\\TK\\API\\Endpoint';
109
        $endpointClass = $namespace . '\\' . \ucfirst($name);
110
        if (!\in_array($name, self::$validEndpoints, true) || !class_exists($endpointClass)) {
111
            $message = sprintf('%s (%s) is not valid TK API endpoint.', $name, $endpointClass);
112
            $this->logger->error($message);
113
            throw new BadMethodCallException($message);
114
        }
115
        return $this->endpointFactory($endpointClass, $arguments);
116
    }
117
118
   
119
120
    /**
121
     * @param string $endpointClass
122
     * @param array $arguments
123
     * @return EndpointInterface
124
     * @throws BadMethodCallException
125
     * @throws InvalidArgumentException
126
     */
127
    private function endpointFactory(string $endpointClass, array $arguments) : EndpointInterface
128
    {
129
        try {
130
            return new $endpointClass($arguments[0]);
131
        } catch (TypeError $e) {
132
            $message = 'This endpoint needs arguments, no argument provided.';
133
            throw new InvalidArgumentException($message);
134
        }
135
    }
136
137
    private function request(EndpointInterface $endpoint) : array
138
    {
139
        $response = $this->httpRequest($endpoint);
140
        $responseBodyString = (string) $response->getBody();
141
        $responseBody = json_decode($responseBodyString, true);
142
        if ($responseBody['status'] === 'FAILURE') {
143
            $this->logger->error('TK API ERROR', $responseBody['message']);
144
            throw new RequestException(
145
                'TK API ERROR: ' .
146
                $responseBody['message']['code'] . ' - ' .
147
                $responseBody['message']['description'] . ' OriginalResponse: ' . $responseBodyString
148
            );
149
        }
150
        return [
151
            'status' => $response->getStatusCode(),
152
            'reason' => $response->getReasonPhrase(),
153
            'headers' => $response->getHeaders(),
154
            'requestId' => $responseBody['requestId'],
155
            'response' => [
156
                'status' => $responseBody['status'],
157
                'code' => $responseBody['message']['code']
158
            ],
159
            'data' => $responseBody['data'][$endpoint->getResponseRoot()]
160
        ];
161
    }
162
163
    /**
164
     * @param EndpointInterface $endpoint
165
     * @return ResponseInterface
166
     */
167
    private function httpRequest(EndpointInterface $endpoint) : ResponseInterface
168
    {
169
        $this->headers = array_merge($this->headers, $endpoint->getHeaders());
170
           $queryParams = $this->getQueryParams($endpoint);
171
172
        $uri = $this->environment->getApiUrl() . $endpoint->getEndpoint();
173
        $options = [];
174
        $httpRequestMethod = $endpoint->getHttpRequestMethod();
175
        if ($httpRequestMethod === self::HTTP_POST) {
176
            $this->headers['Content-Type'] = 'application/json';
177
            $options['json'] = $queryParams;
178
        }
179
        if ($httpRequestMethod === self::HTTP_GET) {
180
            $uri .= '?' . http_build_query($queryParams);
181
        }
182
        $uri .=  '?apikey='. $this->environment->getApiKey();
183
        $options['headers'] = $this->headers;
184
        $this->logger->debug(
185
            'API call for :' . $endpoint->getEndpoint(),
186
            [
187
                'httpRequestMethod' => $httpRequestMethod,
188
                'uri' => $uri,
189
                'headers' => $this->headers,
190
                'queryParams' => $queryParams
191
            ]
192
        );
193
        try {
194
            return $this->guzzleClient->{strtolower($httpRequestMethod)}($uri, $options);
195
        } catch (GuzzleRequestException $e) {
196
            $exceptionMessage = (string) $e->getResponse()
197
                ->getBody()
198
                ->getContents();
199
            $message = sprintf('TK API REQUEST ERROR: %s', $exceptionMessage);
200
            $this->logger->error($message);
201
            throw new RequestException($message);
202
        }
203
    }
204
205
    private function getQueryParams(EndpointInterface $endpoint) : array
206
    {
207
        $requiresRequestHeaders = $endpoint->doesRequireRequestHeaders();
208
        $queryParams = $endpoint->getQueryParams();
209
        if ($requiresRequestHeaders) {
210
            $queryParams['requestHeader'] = [
211
                'clientUsername' => $this->environment->getClientUsername(),
212
                'clientTransactionId' => (string) Ulid::generate(),
213
                'channel' => $this->environment->getChannel(),
214
                'languageCode' => $queryParams['languageCode'] ?? $this->languageCode,
215
                'airlineCode' => $queryParams['airlineCode'] ?? $this->airlineCode
216
            ];
217
            if (array_key_exists('languageCode', $queryParams)) {
218
                unset($queryParams['languageCode']);
219
            }
220
            if (array_key_exists('airlineCode', $queryParams)) {
221
                unset($queryParams['airlineCode']);
222
            }
223
        }
224
        return $queryParams;
225
    }
226
}
227