Skip to content

Commit 85d443c

Browse files
authored
Merge pull request #20 from contentful/feat/interfaces
Add more interfaces
2 parents 85789dc + 2de238e commit 85d443c

21 files changed

+749
-183
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"require": {
66
"php": "^7.0",
77
"ext-json": "*",
8+
"ext-mbstring": "*",
89
"guzzlehttp/guzzle": "^6.3",
910
"guzzlehttp/psr7": "^1.4",
1011
"psr/http-message": "^1.0",

src/Api/BaseClient.php

Lines changed: 84 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,20 @@
1313

1414
use Contentful\Core\Log\NullLogger;
1515
use GuzzleHttp\Client as HttpClient;
16-
use GuzzleHttp\Exception\ClientException;
1716
use Jean85\PrettyVersions;
18-
use Psr\Http\Message\RequestInterface;
17+
use Psr\Http\Message\ResponseInterface;
1918
use Psr\Log\LoggerInterface;
2019
use function GuzzleHttp\json_decode as guzzle_json_decode;
2120

2221
/**
2322
* Abstract client for common code for the different clients.
2423
*/
25-
abstract class BaseClient
24+
abstract class BaseClient implements ClientInterface
2625
{
2726
/**
28-
* @var HttpClient
27+
* @var Requester
2928
*/
30-
private $httpClient;
29+
private $requester;
3130

3231
/**
3332
* @var LoggerInterface
@@ -69,14 +68,18 @@ public function __construct(
6968
HttpClient $httpClient = \null
7069
) {
7170
$this->logger = $logger ?: new NullLogger();
72-
$this->httpClient = $httpClient ?: new HttpClient();
71+
$this->requester = new Requester(
72+
$httpClient ?: new HttpClient(),
73+
$this->getApi(),
74+
$this->getExceptionNamespace()
75+
);
7376

7477
if ('/' === \mb_substr($host, -1)) {
7578
$host = \mb_substr($host, 0, -1);
7679
}
7780
$this->host = $host;
7881

79-
$this->userAgentGenerator = new UserAgentGenerator($this->getSdkName(), $this->getVersion());
82+
$this->userAgentGenerator = new UserAgentGenerator($this->getSdkName(), self::getVersion());
8083
$this->requestBuilder = new RequestBuilder(
8184
$accessToken,
8285
$host,
@@ -86,184 +89,77 @@ public function __construct(
8689
}
8790

8891
/**
89-
* @return string
90-
*/
91-
private function getVersion(): string
92-
{
93-
try {
94-
$version = PrettyVersions::getVersion($this->getPackageName());
95-
$shortVersion = $version->getShortVersion();
96-
97-
// Removes the ".x-dev" part which is inserted during development
98-
if ('.x-dev' === \mb_substr($shortVersion, -6)) {
99-
$shortVersion = \mb_substr($shortVersion, 0, -6).'-dev';
100-
}
101-
102-
return $shortVersion;
103-
} catch (\OutOfBoundsException $exception) {
104-
return '0.0.0-alpha';
105-
}
106-
}
107-
108-
/**
109-
* Set the application name and version.
110-
* The values are used as part of the X-Contentful-User-Agent header.
111-
*
112-
* @param string $name
113-
* @param string $version
114-
*
115-
* @return $this
116-
*/
117-
public function setApplication(string $name, string $version = '')
118-
{
119-
$this->userAgentGenerator->setApplication($name, $version);
120-
121-
return $this;
122-
}
123-
124-
/**
125-
* Set the integration name and version.
126-
* The values are used as part of the X-Contentful-User-Agent header.
92+
* Make a call to the API and returns the parsed JSON.
12793
*
128-
* @param string $name
129-
* @param string $version
130-
*
131-
* @return $this
132-
*/
133-
public function setIntegration(string $name, string $version = '')
134-
{
135-
$this->userAgentGenerator->setIntegration($name, $version);
136-
137-
return $this;
138-
}
139-
140-
/**
14194
* @param string $method The HTTP method
142-
* @param string $path The URI path
95+
* @param string $uri The URI path
14396
* @param array $options An array of optional parameters. The following keys are accepted:
14497
* * query An array of query parameters that will be appended to the URI
14598
* * headers An array of headers that will be added to the request
14699
* * body The request body
147-
* * baseUri A string that can be used to override the default client base URI
100+
* * host A string that can be used to override the default client base URI
148101
*
149102
* @throws \Exception
150103
*
151-
* @return array|null
104+
* @return array
152105
*/
153-
protected function request(string $method, string $path, array $options = [])
106+
protected function callApi(string $method, string $uri, array $options = []): array
154107
{
155-
$request = $this->requestBuilder->build($method, $path, $options);
108+
$request = $this->requestBuilder->build($method, $uri, $options);
156109

157-
$message = $this->callApi($request);
110+
$message = $this->requester->sendRequest($request);
158111
$this->messages[] = $message;
159112

160-
$logMessage = \sprintf(
161-
'%s %s (%.3Fs)',
162-
$request->getMethod(),
163-
(string) $request->getUri(),
164-
$message->getDuration()
165-
);
166-
167-
// This is a "simple" log, for general purpose
168-
$this->logger->log(
169-
$message->getLogLevel(),
170-
$logMessage
171-
);
172-
// This is a debug log, with all message details
173-
$this->logger->debug($logMessage, $message->jsonSerialize());
113+
$this->logMessage($message);
174114

175115
$exception = $message->getException();
176116
if (\null !== $exception) {
177117
throw $exception;
178118
}
179119

180-
$response = $message->getResponse();
181-
$body = $response
182-
? (string) $response->getBody()
183-
: \null;
184-
185-
return $body
186-
? guzzle_json_decode($body, \true)
187-
: [];
120+
return $this->parseResponse($message->getResponse());
188121
}
189122

190123
/**
191-
* Performs a query to the API, and returns a message object
192-
* which contains all information needed for processing and logging.
124+
* Write information about a message object into the logger.
193125
*
194-
* @param RequestInterface $request
195-
*
196-
* @return Message
126+
* @param Message $message
197127
*/
198-
private function callApi(RequestInterface $request): Message
128+
private function logMessage(Message $message)
199129
{
200-
$startTime = \microtime(\true);
201-
202-
$exception = \null;
203-
try {
204-
$response = $this->httpClient->send($request);
205-
} catch (ClientException $exception) {
206-
$response = $exception->hasResponse()
207-
? $exception->getResponse()
208-
: \null;
209-
210-
$exception = $this->createCustomException($exception);
211-
}
212-
213-
$duration = \microtime(\true) - $startTime;
214-
215-
return new Message(
216-
$this->getApi(),
217-
$duration,
218-
$request,
219-
$response,
220-
$exception
130+
$logMessage = \sprintf(
131+
'%s %s (%.3Fs)',
132+
$message->getRequest()->getMethod(),
133+
(string) $message->getRequest()->getUri(),
134+
$message->getDuration()
221135
);
222-
}
223-
224-
/**
225-
* Attempts to create a custom exception.
226-
* It will return a default exception if no suitable class is found.
227-
*
228-
* @param ClientException $exception
229-
*
230-
* @return Exception
231-
*/
232-
private function createCustomException(ClientException $exception): Exception
233-
{
234-
$errorId = '';
235-
$response = $exception->getResponse();
236-
if ($response) {
237-
$data = guzzle_json_decode((string) $response->getBody(), \true);
238-
$errorId = (string) $data['sys']['id'];
239-
}
240136

241-
$exceptionClass = $this->getExceptionClass($errorId);
137+
// This is a "simple" log, for general purpose
138+
$this->logger->log(
139+
$message->getLogLevel(),
140+
$logMessage
141+
);
242142

243-
return new $exceptionClass($exception);
143+
// This is a debug log, with all message details, useful for debugging
144+
$this->logger->debug($logMessage, $message->jsonSerialize());
244145
}
245146

246147
/**
247-
* Returns the FQCN of an exception class to be used for the given API error.
148+
* Parse the body of a JSON response.
248149
*
249-
* @param string $apiError
150+
* @param ResponseInterface|null $response
250151
*
251-
* @return string
152+
* @return array
252153
*/
253-
private function getExceptionClass(string $apiError): string
154+
private function parseResponse(ResponseInterface $response = \null): array
254155
{
255-
$namespace = $this->getExceptionNamespace();
256-
if ($namespace) {
257-
$class = $namespace.'\\'.$apiError.'Exception';
258-
259-
if (\class_exists($class)) {
260-
return $class;
261-
}
262-
}
263-
264-
$class = '\\Contentful\\Core\\Exception\\'.$apiError.'Exception';
156+
$body = $response
157+
? (string) $response->getBody()
158+
: \null;
265159

266-
return \class_exists($class) ? $class : Exception::class;
160+
return $body
161+
? guzzle_json_decode($body, \true)
162+
: [];
267163
}
268164

269165
/**
@@ -306,30 +202,64 @@ public function getHost(): string
306202
}
307203

308204
/**
309-
* Returns a string representation of the API currently in use.
310-
*
205+
* {@inheritdoc}
206+
*/
207+
public function setApplication(string $name, string $version = '')
208+
{
209+
$this->userAgentGenerator->setApplication($name, $version);
210+
211+
return $this;
212+
}
213+
214+
/**
215+
* {@inheritdoc}
216+
*/
217+
public function setIntegration(string $name, string $version = '')
218+
{
219+
$this->userAgentGenerator->setIntegration($name, $version);
220+
221+
return $this;
222+
}
223+
224+
/**
311225
* @return string
312226
*/
313-
abstract public function getApi(): string;
227+
public static function getVersion(): string
228+
{
229+
try {
230+
$shortVersion = PrettyVersions::getVersion(static::getPackageName())
231+
->getShortVersion()
232+
;
233+
234+
// Removes the ".x-dev" part which is inserted during development
235+
if ('.x-dev' === \mb_substr($shortVersion, -6)) {
236+
$shortVersion = \mb_substr($shortVersion, 0, -6).'-dev';
237+
}
238+
239+
return $shortVersion;
240+
} catch (\OutOfBoundsException $exception) {
241+
return '0.0.0-alpha';
242+
}
243+
}
314244

315245
/**
316246
* Returns the packagist name of the current package.
317247
*
318248
* @return string
319249
*/
320-
abstract protected function getPackageName(): string;
250+
abstract protected static function getPackageName(): string;
321251

322252
/**
323253
* The name of the library to be used in the User-Agent header.
324254
*
325255
* @return string
326256
*/
327-
abstract protected function getSdkName(): string;
257+
abstract protected static function getSdkName(): string;
328258

329259
/**
330260
* Returns the Content-Type (MIME-Type) to be used when communication with the API.
331261
*
332262
* @return string
333263
*/
334-
abstract protected function getApiContentType(): string;
264+
abstract protected static function getApiContentType(): string;
335265
}

src/Api/BaseQuery.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,19 +205,13 @@ public function setLimit(int $limit = \null)
205205
* Note that when ordering Entries by fields you must set the content_type URI query parameter to the ID of
206206
* the Content Type you want to filter by. Can be called multiple times to order by multiple values.
207207
*
208-
* @param string|null $field
209-
* @param bool $reverse
208+
* @param string $field
209+
* @param bool $reverse
210210
*
211211
* @return $this
212212
*/
213-
public function orderBy(string $field = \null, bool $reverse = \false)
213+
public function orderBy(string $field, bool $reverse = \false)
214214
{
215-
if (\null === $field) {
216-
$this->orderConditions = [];
217-
218-
return $this;
219-
}
220-
221215
if ($reverse) {
222216
$field = '-'.$field;
223217
}

0 commit comments

Comments
 (0)