Project Name : code coverage of AuthStack\UserDirectory\Service\RESTService

# Code coverage of Project Name: AuthStack\UserDirectory\Service\RESTService

## Class code coverage 81.25%

### Methods

- 100% __construct
- 0% setTimeZoneOffset
- 0% setTimeZoneDST
- 80% getHttpClient
- 100% section
- 100% config
- 0% options
- 100% getBaseUrl
- 66.67% remote
- 100% request
- 80% json
- 75% handleException
- 90.91% isJson

### Source

Line | Code
--- | ---
1 |
    <?php
2 |
3 |
    namespace AuthStack\UserDirectory\Service;
4 |
5 |
    use AuthStack\UserDirectory\Exceptions\JsonDecodingException;
6 |
    use AuthStack\UserDirectory\Exceptions\TransferException;
7 |
    use AuthStack\UserDirectory\Exceptions\UserDirectoryException;
8 |
    use Buckhill\Support\Traits\DotNotationAccessorTrait;
9 |
    use GuzzleHttp\Client;
10 |
    use Psr\Http\Message\ResponseInterface;
11 |
    use GuzzleHttp\Exception\RequestException;
12 |
13 |
    abstract class RESTService
14 |
    {
15 |
        use DotNotationAccessorTrait;
16 |
17 |
        protected $httpClient;
18 |
        protected $baseUrl;
19 |
        protected $config = [];
20 |
        protected $tz_offset;
21 |
        protected $tz_dst;
22 |
23 |
        public function __construct($baseUrl = '', array $options = [], array $routes = [], string $tz_offset = null, string $tz_dst = null)
24 |
        {
25 |
            $this->baseUrl = $baseUrl;
26 |
27 |
            $this->config = [
28 |
                'options' => $options,
29 |
                'routes' => $routes
30 |
            ];
31 |
32 |
            $this->tz_offset = $tz_offset;
33 |
            $this->tz_dst = $tz_dst;
34 |
        }
35 |
36 |
        public function setTimeZoneOffset(string $offset): self
37 |
        {
38 |
            $this->tz_offset = $offset;
39 |
40 |
            return $this;
41 |
        }
42 |
43 |
        public function setTimeZoneDST(string $dst): self
44 |
        {
45 |
            $this->tz_dst = $dst;
46 |
47 |
            return $this;
48 |
        }
49 |
50 |
        public function getHttpClient(): Client
51 |
        {
52 |
            if(!$this->httpClient instanceof Client)
53 |
            {
54 |
                if(!empty($this->tz_offset) && empty($this->tz_dst))
55 |
                {
56 |
                    $this->httpClient = new Client(['headers' => ['X-TimeZoneOffset' => $this->tz_offset, 'X-TimeZoneDST' => $this->tz_dst]]);
57 |
                }
58 |
59 |
                $this->httpClient = new Client();
60 |
            }
61 |
62 |
            return $this->httpClient;
63 |
        }
64 |
65 |
        protected function section($section)
66 |
        {
67 |
            $verb       = $this->config(sprintf("routes.%s.method", $section));
68 |
            $path       = sprintf("%s%s", $this->getBaseUrl(), $this->config(sprintf("routes.%s.path", $section)));
69 |
            $verify     = $this->config(sprintf("routes.%s.verify", $section), false);
70 |
71 |
            return [
72 |
                'method' => $verb,
73 |
                'path' => $path,
74 |
                'verify' => $verify
75 |
            ];
76 |
        }
77 |
78 |
        protected function config($path, $default = null)
79 |
        {
80 |
            return $this->dotNotationFromArray($this->config, $path, $default);
81 |
        }
82 |
83 |
        /**
84 |
         * @param array $options
85 |
         * @return array
86 |
         */
87 |
        protected function options(array $options)
88 |
        {
89 |
            return array_merge($this->config('options', []), $options);
90 |
        }
91 |
92 |
        /**
93 |
         * @return string
94 |
         */
95 |
        protected function getBaseUrl()
96 |
        {
97 |
            return $this->baseUrl;
98 |
        }
99 |
100 |
        /**
101 |
         * @param callable $callback
102 |
         * @param $nextException
103 |
         * @param callable|null $afterException
104 |
         * @return mixed
105 |
         */
106 |
        protected function remote(callable $callback, $nextException = UserDirectoryException::class, callable $afterException = null)
107 |
        {
108 |
            try
109 |
            {
110 |
                return $callback();
111 |
            }
112 |
            catch(\Exception $e)
113 |
            {
114 |
                // Useful for error logging
115 |
                if(is_callable($afterException))
116 |
                {
117 |
                    $afterException($e);
118 |
                }
119 |
120 |
                $this->handleException($e, $nextException);
121 |
            }
122 |
        }
123 |
124 |
        /**
125 |
         * @param $cfg_section
126 |
         * @param array|null $form_params
127 |
         * @param array|null $path_params
128 |
         * @param array|null $get_params
129 |
         * @return mixed|ResponseInterface
130 |
         */
131 |
        protected function request($cfg_section, array $form_params = null, array $path_params = null, array $get_params = null)
132 |
        {
133 |
            $client = $this->getHttpClient();
134 |
            $section = $this->section($cfg_section);
135 |
136 |
            $path = !empty($path_params) ? vsprintf($section['path'], $path_params) : $section['path'];
137 |
138 |
            $options = array_merge($this->config['options'], ['verify' => $section['verify']]);
139 |
140 |
            if(!empty($form_params))
141 |
            {
142 |
                $options['form_params'] = $form_params;
143 |
            }
144 |
145 |
            if(!empty($get_params))
146 |
            {
147 |
                $options['query'] = $get_params;
148 |
            }
149 |
150 |
            return $client->request($section['method'], $path, $options);
151 |
        }
152 |
153 |
        /**
154 |
         * @param array ...$params
155 |
         * @return array
156 |
         * @throws JsonDecodingException
157 |
         */
158 |
        protected function json(...$params): array
159 |
        {
160 |
            $result = $this->request(...$params);
161 |
162 |
            $json = @json_decode($result->getBody(), true);
163 |
164 |
            if(json_last_error() !== JSON_ERROR_NONE)
165 |
            {
166 |
                throw new JsonDecodingException(json_last_error_msg(), json_last_error());
167 |
            }
168 |
169 |
            return $json;
170 |
        }
171 |
172 |
        /**
173 |
         * @param RequestException $e
174 |
         * @param $nextException
175 |
         * @throws TransferException
176 |
         * @throws UserDirectoryException
177 |
         */
178 |
        protected function handleException(\Exception $e, $nextException)
179 |
        {
180 |
            if(method_exists($e, 'getResponse'))
181 |
            {
182 |
                $response = $e->getResponse();
183 |
184 |
                if($this->isJson($response))
185 |
                {
186 |
                    $body = @json_decode($e->getResponse()->getBody(), true);
187 |
188 |
                    $message = isset($body['message']) ? $body['message'] : $e->getResponse()->getBody()->getContents();
189 |
190 |
                    throw new $nextException($message, (int)$e->getCode());
191 |
                }
192 |
193 |
                throw new TransferException($e->getResponse()->getBody()->getContents(), $e->getCode());
194 |
            }
195 |
196 |
            throw new UserDirectoryException($e->getMessage(), $e->getCode());
197 |
        }
198 |
199 |
        /**
200 |
         * @param ResponseInterface $response
201 |
         * @return bool
202 |
         */
203 |
        protected function isJson(ResponseInterface $response)
204 |
        {
205 |
            $result = false;
206 |
207 |
            if($response->hasHeader('content-type'))
208 |
            {
209 |
                $contentType = $response->getHeader('content-type');
210 |
211 |
                if(is_string($contentType))
212 |
                {
213 |
                    $result = 0 === strcmp($contentType, 'application/json');
214 |
                }
215 |
216 |
                if(is_array($contentType))
217 |
                {
218 |
                    foreach($contentType as $ctype)
219 |
                    {
220 |
                        $result = 0 === strcmp($ctype, 'application/json');
221 |
222 |
                        if($result)
223 |
                            break;
224 |
                    }
225 |
                }
226 |
            }
227 |
228 |
            return $result;
229 |
        }
230 |
    }