Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.77% covered (success)
98.77%
80 / 81
91.67% covered (success)
91.67%
11 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Http
98.77% covered (success)
98.77%
80 / 81
91.67% covered (success)
91.67%
11 / 12
37
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
10
 setUserInfo
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUserInfo
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 readResponse
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 getAuthorizedRequest
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
6.03
 setApiKey
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setWorkflowKey
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 readGetResult
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 readPostResult
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 readDeleteResult
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 readResult
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 createRequest
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsclient;
4
5use Psr\Http\Message\RequestInterface;
6use Psr\Http\Message\UriInterface;
7use Slim\Psr7\Headers;
8
9/**
10 * Adapter & Decorator Class to use the Psr7\Client
11 *
12 * Access api method_exists
13 * @SuppressWarnings(Coupling)
14 */
15class Http
16{
17    protected Psr7\Client $client;
18
19    /**
20     * @var string
21     */
22    protected string $http_baseurl = '';
23
24    /**
25     * @var bool
26     * with authentification request if true
27     */
28    public static $authEnabled = true;
29
30    /**
31     * @var UriInterface
32     */
33    protected UriInterface $uri;
34
35    /**
36     * @var bool
37     * Log requests and responses if true
38     */
39    public static $logEnabled = true;
40
41    /**
42     * @var array
43     * Contains a list of requests and responses if logging is enabled
44     */
45    public static $log = [];
46
47    /**
48     * @var string|null
49     */
50    protected ?string $apikeyString = null;
51
52    /**
53     * @var string|null
54     */
55    protected ?string $workflowkeyString = null;
56
57    /**
58     * @var int|null
59     */
60    public static $jsonCompressLevel = null;
61
62    public function __construct(string $baseUrl, ?Psr7\Client $client = null)
63    {
64        $path = parse_url($baseUrl, PHP_URL_PATH);
65        $this->http_baseurl = is_string($path) ? $path : '';
66        $this->uri = new Psr7\Uri();
67        $scheme = parse_url($baseUrl, PHP_URL_SCHEME);
68        $this->uri = $this->uri->withScheme(is_string($scheme) ? $scheme : '');
69        $host = parse_url($baseUrl, PHP_URL_HOST);
70        $this->uri = $this->uri->withHost(is_string($host) ? $host : '');
71        $port = parse_url($baseUrl, PHP_URL_PORT);
72        if (is_int($port) && $port !== 0) {
73            $this->uri = $this->uri->withPort($port);
74        }
75        $user = parse_url($baseUrl, PHP_URL_USER);
76        $pass = parse_url($baseUrl, PHP_URL_PASS);
77        if (is_string($user) && $user !== '') {
78            $this->setUserInfo($user, is_string($pass) ? $pass : null);
79        }
80        if (null === $client) {
81            $client = new Psr7\Client();
82        }
83        $this->client = $client;
84    }
85
86    public function setUserInfo(string $user, ?string $pass): self
87    {
88        $this->uri = $this->uri->withUserInfo($user, $pass);
89        return $this;
90    }
91
92    public function getUserInfo(): string
93    {
94        return $this->uri->getUserInfo();
95    }
96
97    /**
98     * Start request and fetch response
99     * The request is extended by auth informations
100     *
101     * @param \Psr\Http\Message\RequestInterface $request
102     *
103     * @return \Psr\Http\Message\ResponseInterface
104     */
105    public function readResponse(RequestInterface $request)
106    {
107        if (static::$authEnabled) {
108            $request = $this->getAuthorizedRequest($request);
109        }
110        if (null !== static::$jsonCompressLevel) {
111            $request = $request->withHeader('X-JsonCompressLevel', (string) static::$jsonCompressLevel);
112        }
113        $startTime = microtime(true);
114        $response = $this->client->readResponse($request);
115        if (self::$logEnabled) {
116            self::$log[] = $request;
117            self::$log[] = $response;
118            $responseSizeKb = round(strlen($response->getBody()->getContents()) / 1024);
119            self::$log[] = "Response ($responseSizeKb kb) time in s: " . round(microtime(true) - $startTime, 3);
120        }
121        return $response;
122    }
123
124    /**
125     * Extend the request by auth informations
126     *
127     * @param \Psr\Http\Message\RequestInterface $request
128     *
129     * @return \Psr\Http\Message\RequestInterface
130     */
131    public function getAuthorizedRequest(RequestInterface $request)
132    {
133        $userInfo = $request->getUri()->getUserInfo();
134        $xAuthKey = Auth::getKey();
135        if (null !== $xAuthKey && ! $userInfo) {
136            $request = $request->withHeader('X-Authkey', $xAuthKey);
137        } elseif ($userInfo) {
138            $request = $request->withHeader('Authorization', 'Basic ' . base64_encode($userInfo));
139        }
140        if (null !== $this->apikeyString) {
141            $request = $request->withHeader('X-Api-Key', $this->apikeyString);
142        }
143        if (null !== $this->workflowkeyString) {
144            $request = $request->withHeader('X-Workflow-Key', $this->workflowkeyString);
145        }
146
147        return $request;
148    }
149
150    public function setApiKey(string $apikeyString): self
151    {
152        $this->apikeyString = $apikeyString;
153        return $this;
154    }
155
156    public function setWorkflowKey(string $apikeyString): self
157    {
158        $this->workflowkeyString = $apikeyString;
159        return $this;
160    }
161
162    /**
163     * Creates a GET-Http-Request and fetches the response
164     *
165     * @param string $relativeUrl
166     * @param array|null $getParameters (optional)
167     * @param null|string $xToken
168     *
169     * @return Result
170     */
171    public function readGetResult($relativeUrl, ?array $getParameters = null, string|null $xToken = null)
172    {
173        $uri = $this->uri->withPath($this->http_baseurl . $relativeUrl);
174        if (null !== $getParameters) {
175            $uri = $uri->withQuery(http_build_query($getParameters));
176        }
177        $request = self::createRequest('GET', $uri);
178
179        if (null !== $xToken) {
180            $request = $request->withHeader('X-Token', $xToken);
181        }
182
183        return $this->readResult($request);
184    }
185
186    /**
187     * Creates a POST-Http-Request and fetches the response
188     *
189     * @param mixed $entity JSON-encodable payload (entity or collection)
190     */
191    public function readPostResult(string $relativeUrl, $entity, ?array $getParameters = null): Result
192    {
193        $uri = $this->uri->withPath($this->http_baseurl . $relativeUrl);
194        if (null !== $getParameters) {
195            $uri = $uri->withQuery(http_build_query($getParameters));
196        }
197        $request = self::createRequest('POST', $uri);
198        $body = new Psr7\Stream();
199        $body->write(json_encode($entity));
200        $request = $request->withBody($body);
201
202        return $this->readResult($request);
203    }
204
205    /**
206     * Creates a DELETE-Http-Request and fetches the response
207     *
208     * @param string $relativeUrl
209     * @param array $getParameters (optional)
210     *
211     * @return Result
212     */
213    public function readDeleteResult($relativeUrl, ?array $getParameters = null)
214    {
215        $uri = $this->uri->withPath($this->http_baseurl . $relativeUrl);
216        if (null !== $getParameters) {
217            $uri = $uri->withQuery(http_build_query($getParameters));
218        }
219        $request = self::createRequest('DELETE', $uri);
220        return $this->readResult($request);
221    }
222
223    protected function readResult(
224        RequestInterface $request,
225        int $try = 0
226    ): Result {
227        $response = $this->readResponse($request);
228        $result = new Result($response, $request);
229        if ($response->getStatuscode() == 500) {
230            try {
231                $result->getData();
232            } catch (Exception $exception) {
233                if (
234                    $try < 3 && in_array($exception->template, [
235                    "BO\\Zmsbackend\\Exception\\Pdo\\DeadLockFound",
236                    "BO\\Zmsbackend\\Exception\\Pdo\\LockTimeout",
237                    ])
238                ) {
239                    usleep(rand(1000000, 3000000));
240                    return $this->readResult($request, $try + 1);
241                }
242            }
243        }
244        return $result;
245    }
246
247    public static function createRequest(string $method, UriInterface $uri): RequestInterface
248    {
249        $request = new Psr7\Request($method, $uri, 'php://memory', new Headers([], []));
250        return $request;
251    }
252}