Passed
Branch simplistic (3d6a47)
by Ali
02:39
created

Api::setConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
3
/*
4
 * Part of the Saudi Address API PHP package.
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * Licensed under the MIT.
9
 *
10
 * This source file is subject to the MIT License that is
11
 * bundled with this package in the LICENSE file.
12
 *
13
 * @package    Saudi Address
14
 * @version    2.0
15
 * @author     Ali Alharthi
16
 * @license    MIT
17
 * @copyright  (c) 2020, Ali Alharthi
18
 * @link       https://aalharthi.sa
19
 */
20
21
namespace AliAlharthi\SaudiAddress\Api;
22
23
use AliAlharthi\SaudiAddress\ConfigInterface;
24
use AliAlharthi\SaudiAddress\Exception\Handler;
25
use GuzzleHttp\Client;
26
use GuzzleHttp\Exception\ClientException;
27
use GuzzleHttp\Exception\ConnectException;
28
use GuzzleHttp\Exception\TransferException;
29
use GuzzleHttp\HandlerStack;
30
use GuzzleHttp\Middleware;
31
use Psr\Http\Message\RequestInterface;
32
use Psr\Http\Message\ResponseInterface;
33
use RuntimeException;
34
35
abstract class Api implements ApiInterface
36
{
37
    const API_BASE_URL = 'https://apina.address.gov.sa/NationalAddress/';
38
    const USER_AGENT_SUFFIX = "alharthi-saudi-address-api-php-client/";
39
    const IN_CHARACTER_ENCODING = 'windows-1256';
40
    const OUT_CHARACTER_ENCODING = 'UTF-8';
41
42
    /**
43
     * The Config repository instance.
44
     *
45
     * @var \AliAlharthi\SaudiAddress\ConfigInterface
46
     */
47
    protected $config;
48
49
    /**
50
     * Constructor.
51
     *
52
     * @param   \AliAlharthi\SaudiAddress\ConfigInterface  $config
53
     */
54
    public function __construct(ConfigInterface $config)
55
    {
56
        $this->config = $config;
57
    }
58
59
    /**
60
     * Set the config.
61
     *
62
     * @param   \AliAlharthi\SaudiAddress\ConfigInterface  $config
63
     * @return  void
64
     */
65
    public function setConfig(ConfigInterface $config){
66
        $this->config = $config;
67
    }
68
69
    /**
70
     * Returns the Saudi National Address API endpoint.
71
     *
72
     * @return  string
73
     */
74
    public function baseUrl()
75
    {
76
        return self::API_BASE_URL;
77
    }
78
79
    /**
80
     * Execute a get request.
81
     *
82
     * @param   string  $url
83
     * @param   array   $parameters
84
     * @param   bool    $encode
85
     * @return  null|array
86
     */
87
    public function _get($url = null, $parameters = [], $encode = true)
88
    {
89
        return $this->execute('get', $url, $parameters, $encode);
90
    }
91
92
    /**
93
     * Execute a request.
94
     *
95
     * @param   string  $httpMethod
96
     * @param   string  $url
97
     * @param   array   $parameters
98
     * @param   bool    $encode
99
     * @return  null|array
100
     * @throws  AliAlharthi\SaudiAddress\Exception\Handler
101
     */
102
    public function execute($httpMethod, $url, $parameters = [], $encode = true)
103
    {
104
        try {
105
            $parameters['format'] = 'json';
106
            $parameters['language'] = $this->config->getLocale();
107
            $parameters = http_build_query($parameters);
108
            $response = $this->getClient()->{$httpMethod}($url, ['query' => $parameters]);
109
110
            return ($encode) ?
111
                json_decode(iconv(self::IN_CHARACTER_ENCODING, self::OUT_CHARACTER_ENCODING, ($response->getBody())), true) :
112
                json_decode($response->getBody(), true);
113
114
        } catch (ClientException $e) {
115
            new Handler($e);
116
        }
117
    }
118
119
    /**
120
     * Returns an Http client instance.
121
     *
122
     * @return  \GuzzleHttp\Client
123
     */
124
    protected function getClient()
125
    {
126
        return new Client([
127
            'base_uri' => $this->baseUrl(), 'handler' => $this->createHandler()
128
        ]);
129
    }
130
131
    /**
132
     * Create the client handler.
133
     *
134
     * @return  \GuzzleHttp\HandlerStack
135
     * @throws  \RuntimeException
136
     */
137
    protected function createHandler()
138
    {
139
        if (! $this->config->getApiKey()) {
140
            throw new RuntimeException('The Saudi National Address API key is not defined.');
141
        }
142
143
        $stack = HandlerStack::create();
144
145
        $stack->push(Middleware::mapRequest(function (RequestInterface $request) {
146
            $config = $this->config;
147
148
            $request = $request->withHeader('api_key', $config->getApiKey());
149
150
            $request = $request->withHeader('User-Agent', $this->generateUserAgent());
151
152
            $request = $request->withHeader('accept', 'application/json');
153
154
            return $request;
155
        }));
156
157
        $stack->push(Middleware::retry(function ($retries, RequestInterface $request, ResponseInterface $response = null, TransferException $exception = null) {
158
            return $retries < 3 && ($exception instanceof ConnectException || ($response && $response->getStatusCode() >= 500));
159
        }, function ($retries) {
160
            return (int) pow(2, $retries) * 1000;
161
        }));
162
163
        return $stack;
164
    }
165
166
    /**
167
     * Generates the main user agent string.
168
     *
169
     * @return  string
170
     */
171
    protected function generateUserAgent()
172
    {
173
        return self::USER_AGENT_SUFFIX . $this->config->getVersion();
174
    }
175
176
    /**
177
     * Return a value from cache.
178
     *
179
     * @param   string  $file
180
     * @return  array|null
181
     */
182
    protected function cacheValue($file)
183
    {
184
        if ($this->config->getCache() && file_exists($file)) {
185
            return unserialize(file_get_contents($file));
186
        }
187
188
        return null;
189
    }
190
}
191