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

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

## Class code coverage 78.79%

### Methods

- 100% __construct
- 0% setTimeZoneOffset
- 0% setTimeZoneDST
- 100% getHttpClient
- 100% section
- 100% config
- 0% options
- 100% getBaseUrl
- 66.67% remote
- 76.92% 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 = null;
21 |
        protected $tz_dst = null;
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 |
                $this->httpClient = new Client();
55 |
            }
56 |
57 |
            return $this->httpClient;
58 |
        }
59 |
60 |
        protected function section($section)
61 |
        {
62 |
            $verb       = $this->config(sprintf("routes.%s.method", $section));
63 |
            $path       = sprintf("%s%s", $this->getBaseUrl(), $this->config(sprintf("routes.%s.path", $section)));
64 |
            $verify     = $this->config(sprintf("routes.%s.verify", $section), false);
65 |
66 |
            return [
67 |
                'method' => $verb,
68 |
                'path' => $path,
69 |
                'verify' => $verify
70 |
            ];
71 |
        }
72 |
73 |
        protected function config($path, $default = null)
74 |
        {
75 |
            return $this->dotNotationFromArray($this->config, $path, $default);
76 |
        }
77 |
78 |
        /**
79 |
         * @param array $options
80 |
         * @return array
81 |
         */
82 |
        protected function options(array $options)
83 |
        {
84 |
            return array_merge($this->config('options', []), $options);
85 |
        }
86 |
87 |
        /**
88 |
         * @return string
89 |
         */
90 |
        protected function getBaseUrl()
91 |
        {
92 |
            return $this->baseUrl;
93 |
        }
94 |
95 |
        /**
96 |
         * @param callable $callback
97 |
         * @param $nextException
98 |
         * @param callable|null $afterException
99 |
         * @return mixed
100 |
         */
101 |
        protected function remote(callable $callback, $nextException = UserDirectoryException::class, callable $afterException = null)
102 |
        {
103 |
            try
104 |
            {
105 |
                return $callback();
106 |
            }
107 |
            catch(\Exception $e)
108 |
            {
109 |
                // Useful for error logging
110 |
                if(is_callable($afterException))
111 |
                {
112 |
                    $afterException($e);
113 |
                }
114 |
115 |
                $this->handleException($e, $nextException);
116 |
            }
117 |
        }
118 |
119 |
        /**
120 |
         * @param $cfg_section
121 |
         * @param array|null $form_params
122 |
         * @param array|null $path_params
123 |
         * @param array|null $get_params
124 |
         * @return mixed|ResponseInterface
125 |
         */
126 |
        protected function request($cfg_section, array $form_params = null, array $path_params = null, array $get_params = null)
127 |
        {
128 |
            $client = $this->getHttpClient();
129 |
            $section = $this->section($cfg_section);
130 |
131 |
            $path = !empty($path_params) ? vsprintf($section['path'], $path_params) : $section['path'];
132 |
133 |
            $options = array_merge($this->config['options'], ['verify' => $section['verify']]);
134 |
135 |
            // Add time zone headers
136 |
            if(!is_null($this->tz_offset) && !is_null($this->tz_dst))
137 |
            {
138 |
                if(!isset($options['headers'])) $options['headers'] = [];
139 |
140 |
                $options['headers']['X-TimeZoneOffset'] = $this->tz_offset;
141 |
                $options['headers']['X-TimeZoneDST'] = $this->tz_dst;
142 |
            }
143 |
144 |
            if(!empty($form_params))
145 |
            {
146 |
                $options['form_params'] = $form_params;
147 |
            }
148 |
149 |
            if(!empty($get_params))
150 |
            {
151 |
                $options['query'] = $get_params;
152 |
            }
153 |
154 |
            return $client->request($section['method'], $path, $options);
155 |
        }
156 |
157 |
        /**
158 |
         * @param array ...$params
159 |
         * @return array
160 |
         * @throws JsonDecodingException
161 |
         */
162 |
        protected function json(...$params): array
163 |
        {
164 |
            $result = $this->request(...$params);
165 |
166 |
            $json = @json_decode($result->getBody(), true);
167 |
168 |
            if(json_last_error() !== JSON_ERROR_NONE)
169 |
            {
170 |
                throw new JsonDecodingException(json_last_error_msg(), json_last_error());
171 |
            }
172 |
173 |
            return $json;
174 |
        }
175 |
176 |
        /**
177 |
         * @param RequestException $e
178 |
         * @param $nextException
179 |
         * @throws TransferException
180 |
         * @throws UserDirectoryException
181 |
         */
182 |
        protected function handleException(\Exception $e, $nextException)
183 |
        {
184 |
            if(method_exists($e, 'getResponse'))
185 |
            {
186 |
                $response = $e->getResponse();
187 |
188 |
                if($this->isJson($response))
189 |
                {
190 |
                    $body = @json_decode($e->getResponse()->getBody(), true);
191 |
192 |
                    $message = isset($body) && is_array($body) ? $body : $e->getResponse()->getBody()->getContents();
193 |
194 |
                    throw new $nextException($message, (int)$e->getCode());
195 |
                }
196 |
197 |
                throw new TransferException($e->getResponse()->getBody()->getContents(), $e->getCode());
198 |
            }
199 |
200 |
            throw new UserDirectoryException($e->getMessage(), $e->getCode());
201 |
        }
202 |
203 |
        /**
204 |
         * @param ResponseInterface $response
205 |
         * @return bool
206 |
         */
207 |
        protected function isJson(ResponseInterface $response)
208 |
        {
209 |
            $result = false;
210 |
211 |
            if($response->hasHeader('content-type'))
212 |
            {
213 |
                $contentType = $response->getHeader('content-type');
214 |
215 |
                if(is_string($contentType))
216 |
                {
217 |
                    $result = 0 === strcmp($contentType, 'application/json');
218 |
                }
219 |
220 |
                if(is_array($contentType))
221 |
                {
222 |
                    foreach($contentType as $ctype)
223 |
                    {
224 |
                        $result = 0 === strcmp($ctype, 'application/json');
225 |
226 |
                        if($result)
227 |
                            break;
228 |
                    }
229 |
                }
230 |
            }
231 |
232 |
            return $result;
233 |
        }
234 |
    }