-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStoryblokClient.php
117 lines (100 loc) · 3.87 KB
/
StoryblokClient.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
declare(strict_types=1);
/**
* This file is part of Storyblok-Api.
*
* (c) SensioLabs Deutschland <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Storyblok\Api;
use OskarStark\Value\TrimmedNonEmptyString;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Storyblok\Api\Bridge\HttpClient\QueryStringHelper;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Webmozart\Assert\Assert;
use function Safe\parse_url;
/**
* @author Silas Joisten <[email protected]>
*/
final class StoryblokClient implements StoryblokClientInterface
{
private HttpClientInterface $client;
private ?int $cacheVersion = null;
public function __construct(
string $baseUri,
#[\SensitiveParameter]
private string $token,
int $timeout = 4,
private LoggerInterface $logger = new NullLogger(),
) {
$this->client = HttpClient::createForBaseUri($baseUri);
$this->token = TrimmedNonEmptyString::fromString($token, '$token must not be an empty string')->toString();
$this->client = HttpClient::createForBaseUri($baseUri, [
'timeout' => $timeout,
]);
}
public function withHttpClient(HttpClientInterface $client): self
{
$this->client = $client;
return $this;
}
public function request(string $method, string $url, array $options = []): ResponseInterface
{
Assert::notStartsWith($url, 'http', '$url should be relative: Got: %s');
Assert::startsWith($url, '/', '$url should start with a "/". Got: %s');
/*
* This workaround is necessary because the symfony/http-client does not support URL array syntax like in JavaScript.
* Specifically, this issue arises with the "OrFilter" query parameter, which needs to be formatted as follows:
* query_filter[__or][][field][filter]=value
*
* The default behavior of the Http Client includes the array key in the query string, causing a 500 error on the Storyblok API side.
* Instead of generating the required format, the symfony/http-client generates a query string that looks like:
* query_filter[__or][0][field][filter]=value&query_filter[__or][1][field][filter]=value
*/
if (\array_key_exists('query', $options)) {
$url = QueryStringHelper::applyQueryString($url, [
...$options['query'],
'token' => $this->token,
'cv' => $this->cacheVersion,
]);
unset($options['query']);
} else {
$options['query'] = [
'token' => $this->token,
'cv' => $this->cacheVersion,
];
}
try {
$response = $this->client->request(
$method,
$url,
array_merge_recursive(
$options,
[
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
],
],
),
);
$this->logger->debug('Response', $response->toArray(false));
} catch (\Throwable $e) {
$this->logger->error($e->getMessage());
throw $e;
}
if ($response->getStatusCode()) {
$parsed = [];
/** @var string $parsedUrl */
$parsedUrl = parse_url($response->getInfo('url'), \PHP_URL_QUERY);
parse_str($parsedUrl, $parsed);
$this->cacheVersion = \array_key_exists('cv', $parsed) ? (int) $parsed['cv'] : $this->cacheVersion;
}
return $response;
}
}