Skip to content

Commit dc29e5d

Browse files
authored
turn whole library async first (#29)
1 parent b55af95 commit dc29e5d

10 files changed

+445
-276
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"require": {
1818
"php": ">=5.6",
1919
"guzzlehttp/guzzle": "^6.0",
20+
"guzzlehttp/promises": "~1.1",
2021
"psr/cache": "~1.0.0"
2122
},
2223
"require-dev": {

src/Contentful.php

Lines changed: 89 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use GuzzleHttp\Client as GuzzleClient;
66
use GuzzleHttp\Exception\RequestException;
7+
use function GuzzleHttp\Promise\all;
78
use function GuzzleHttp\Promise\coroutine;
8-
use GuzzleHttp\Promise\FulfilledPromise;
99
use function GuzzleHttp\Promise\promise_for;
1010
use GuzzleHttp\Promise\PromiseInterface;
1111
use Markup\Contentful\Cache\NullCacheItemPool;
@@ -103,7 +103,9 @@ public function __construct(array $spaces, array $options = [])
103103
public function getSpace($space = null, array $options = [])
104104
{
105105
if ($space instanceof SpaceInterface) {
106-
return $space;
106+
return ($this->isAsyncCall($options))
107+
? promise_for($space)
108+
: $space;
107109
} else {
108110
$spaceName = $space;
109111
}
@@ -133,7 +135,9 @@ public function getSpace($space = null, array $options = [])
133135
public function getEntry($id, $space = null, array $options = [])
134136
{
135137
if ($this->envelope->hasEntry($id)) {
136-
return $this->envelope->findEntry($id);
138+
return ($this->isAsyncCall($options))
139+
? promise_for($this->envelope->findEntry($id))
140+
: $this->envelope->findEntry($id);
137141
}
138142
$spaceName = ($space instanceof SpaceInterface) ? $space->getName() : $space;
139143
$spaceData = $this->getSpaceDataForName(($space instanceof SpaceInterface) ? $space->getName() : $space);
@@ -187,7 +191,9 @@ public function getEntries(array $parameters = [], $space = null, array $options
187191
public function getAsset($id, $space = null, array $options = [])
188192
{
189193
if ($this->envelope->hasAsset($id)) {
190-
return $this->envelope->findAsset($id);
194+
return ($this->isAsyncCall($options))
195+
? promise_for($this->envelope->findAsset($id))
196+
: $this->envelope->findAsset($id);
191197
}
192198
$spaceName = ($space instanceof SpaceInterface) ? $space->getName() : $space;
193199
$spaceData = $this->getSpaceDataForName($spaceName);
@@ -215,7 +221,9 @@ public function getAsset($id, $space = null, array $options = [])
215221
public function getContentType($id, $space = null, array $options = [])
216222
{
217223
if ($this->envelope->hasContentType($id)) {
218-
return $this->envelope->findContentType($id);
224+
return ($this->isAsyncCall($options))
225+
? promise_for($this->envelope->findContentType($id))
226+
: $this->envelope->findContentType($id);
219227
}
220228

221229
//fetch them all and pick one out, as it is likely we'll want to access others
@@ -242,6 +250,14 @@ function ($contentTypes) use ($id) {
242250
public function getContentTypes(array $parameters = [], $space = null, array $options = [])
243251
{
244252
$spaceName = ($space instanceof SpaceInterface) ? $space->getName() : $space;
253+
if (!$parameters) {
254+
$stashedContentTypes = $this->envelope->getAllContentTypesForSpace($spaceName);
255+
if (null !== $stashedContentTypes) {
256+
return ($this->isAsyncCall($options))
257+
? promise_for($stashedContentTypes)
258+
: $stashedContentTypes;
259+
}
260+
}
245261
$spaceData = $this->getSpaceDataForName(($space instanceof SpaceInterface) ? $space->getName() : $space);
246262
$api = ($spaceData['preview_mode']) ? self::PREVIEW_API : self::CONTENT_DELIVERY_API;
247263

@@ -292,26 +308,40 @@ function () use ($name, $space, $options) {
292308
}
293309

294310
/**
295-
* @param Link $link
311+
* @param Link $link
296312
* @param array $options
297-
* @return ResourceInterface|PromiseInterface
313+
* @return PromiseInterface
298314
*/
299315
public function resolveLink($link, array $options = [])
300316
{
301317
//check whether the "link" is already actually a resolved resource
302318
if ($link instanceof ResourceInterface) {
303-
return $link;
319+
return promise_for($link);
304320
}
305321
try {
306322
switch ($link->getLinkType()) {
307323
case 'Entry':
308-
return $this->getEntry($link->getId(), $link->getSpaceName(), $options);
324+
return $this->getEntry(
325+
$link->getId(),
326+
$link->getSpaceName(),
327+
array_merge($options, ['async' => true])
328+
);
309329
case 'Asset':
310-
return $this->getAsset($link->getId(), $link->getSpaceName(), $options);
330+
return $this->getAsset(
331+
$link->getId(),
332+
$link->getSpaceName(),
333+
array_merge($options, ['async' => true])
334+
);
311335
case 'ContentType':
312-
return $this->getContentType($link->getId(), $link->getSpaceName(), $options);
336+
return $this->getContentType(
337+
$link->getId(),
338+
$link->getSpaceName(),
339+
array_merge($options, ['async' => true])
340+
);
313341
default:
314-
throw new \InvalidArgumentException(sprintf('Tried to resolve unknown link type "%s".', $link->getLinkType()));
342+
throw new \InvalidArgumentException(
343+
sprintf('Tried to resolve unknown link type "%s".', $link->getLinkType())
344+
);
315345
}
316346
} catch (ResourceUnavailableException $e) {
317347
throw new LinkUnresolvableException($link, null, 0, $e);
@@ -387,21 +417,24 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
387417
* Returns a built response if it passes test, or null if it doesn't.
388418
*
389419
* @param string $json
390-
* @return ResourceInterface|ResourceArray|null
420+
* @return PromiseInterface
391421
*/
392422
$buildResponseFromJson = function ($json) use ($spaceData, $assetDecorator, $shouldBuildTypedResources, $test) {
393423
$json = (is_array($json)) ? $json : json_decode($json, true);
394424
if (null === $json) {
395425
return null;
396426
}
397-
$builtResponse = $this->buildResponseFromRaw(
427+
428+
return $this->buildResponseFromRaw(
398429
$json,
399430
$spaceData['name'],
400431
$assetDecorator,
401432
$shouldBuildTypedResources
433+
)->then(
434+
function ($builtResponse) use ($test) {
435+
return (call_user_func($test, $builtResponse)) ? $builtResponse : null;
436+
}
402437
);
403-
404-
return (call_user_func($test, $builtResponse)) ? $builtResponse : null;
405438
};
406439
$log = function ($description, $isCacheHit, $type) use ($timer, $queryType, $api) {
407440
$this->logger->log(
@@ -425,7 +458,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
425458
LogInterface::TYPE_RESPONSE
426459
);
427460

428-
$builtResponse = $buildResponseFromJson($cacheItemJson);
461+
$builtResponse = (yield $buildResponseFromJson($cacheItemJson));
429462
if ($builtResponse) {
430463
yield promise_for($builtResponse);
431464
return;
@@ -444,7 +477,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
444477
true,
445478
LogInterface::TYPE_RESOURCE
446479
);
447-
$builtResponse = $buildResponseFromJson($fallbackJson);
480+
$builtResponse = (yield $buildResponseFromJson($fallbackJson));
448481
if ($builtResponse) {
449482
yield promise_for($builtResponse);
450483
return;
@@ -478,7 +511,12 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
478511
/**
479512
* @var ResponseInterface $response
480513
*/
481-
$response = (yield $this->sendRequestAsync($request, $queryParams));
514+
$response = ($shouldBuildTypedResources)
515+
? array_values((yield all([
516+
$this->sendRequestWithQueryParams($request, $queryParams),
517+
$this->ensureContentTypesLoaded($spaceName)
518+
])))[0]
519+
: (yield $this->sendRequestWithQueryParams($request, $queryParams));
482520
} catch (RequestException $e) {
483521
/**
484522
* @var CacheItemInterface $fallbackCacheItem
@@ -496,12 +534,12 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
496534
$writeCacheItem->set($fallbackJson);
497535
$writeCache->save($writeCacheItem);
498536

499-
yield promise_for($this->buildResponseFromRaw(
537+
yield $this->buildResponseFromRaw(
500538
json_decode($fallbackJson, true),
501539
$spaceData['name'],
502540
$assetDecorator,
503541
$shouldBuildTypedResources
504-
));
542+
);
505543
return;
506544
}
507545
}
@@ -542,7 +580,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
542580
$responseJson = json_encode(
543581
(!$unavailableException) ? $this->responseAsArrayFromJson($response) : null
544582
);
545-
$builtResponse = ($responseJson) ? $buildResponseFromJson($responseJson) : null;
583+
$builtResponse = ($responseJson) ? (yield $buildResponseFromJson($responseJson)) : null;
546584
$isValidResponse = (bool) $builtResponse;
547585

548586
//save into cache
@@ -587,7 +625,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
587625
true,
588626
LogInterface::TYPE_RESOURCE
589627
);
590-
$builtResponse = $buildResponseFromJson($fallbackJson);
628+
$builtResponse = (yield $buildResponseFromJson($fallbackJson));
591629
if ($builtResponse) {
592630
yield promise_for($builtResponse);
593631
return;
@@ -722,10 +760,10 @@ private function setApiVersionHeaderOnRequest($request, $api)
722760

723761
/**
724762
* @param array $data
725-
* @param string $spaceName
726-
* @param AssetDecoratorInterface $assetDecorator
763+
* @param null $spaceName
764+
* @param AssetDecoratorInterface|null $assetDecorator
727765
* @param bool $useTypedResources
728-
* @return ResourceInterface
766+
* @return PromiseInterface
729767
*/
730768
private function buildResponseFromRaw(
731769
array $data,
@@ -891,4 +929,29 @@ private function resolveContentTypeNameFilter(IncompleteParameterInterface $filt
891929

892930
return $contentTypeFilterProvider->createForContentTypeName($filter->getValue(), $spaceName);
893931
}
932+
933+
/**
934+
* @param string $spaceName
935+
* @return PromiseInterface
936+
*/
937+
private function ensureContentTypesLoaded($spaceName)
938+
{
939+
return $this->getContentTypes([], $spaceName, ['async' => true, 'untyped' => true])
940+
->then(
941+
function ($types) use ($spaceName) {
942+
$this->envelope->insertAllContentTypesForSpace($types, $spaceName);
943+
944+
return $types;
945+
}
946+
);
947+
}
948+
949+
/**
950+
* @param array $options
951+
* @return bool
952+
*/
953+
private function isAsyncCall(array $options)
954+
{
955+
return isset($options['async']) && true === $options['async'];
956+
}
894957
}

src/Entry.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function getField($key)
5757
if ($this->fields[$key] instanceof Link) {
5858
if (!isset($this->resolvedLinks[$key])) {
5959
try {
60-
$resolvedLink = call_user_func($this->resolveLinkFunction, $this->fields[$key]);
60+
$resolvedLink = call_user_func($this->resolveLinkFunction, $this->fields[$key])->wait();
6161
} catch (LinkUnresolvableException $e) {
6262
$resolvedLink = null;
6363
}
@@ -70,7 +70,7 @@ public function getField($key)
7070
if (!isset($this->resolvedLinks[$key])) {
7171
$this->resolvedLinks[$key] = array_filter(array_map(function ($link) {
7272
try {
73-
$resolvedLink = call_user_func($this->resolveLinkFunction, $link);
73+
$resolvedLink = call_user_func($this->resolveLinkFunction, $link)->wait();
7474
} catch (LinkUnresolvableException $e) {
7575
//if the link is unresolvable we should consider it not published and return null so this is filtered out
7676
return null;
@@ -122,6 +122,8 @@ public function offsetUnset($offset)
122122
}
123123

124124
/**
125+
* Sets a function that can return a promise for a resolved link.
126+
*
125127
* @param callable $function
126128
* @return self
127129
*/

src/GuzzleAbstractionTrait.php

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,12 @@ trait GuzzleAbstractionTrait
1818
*/
1919
private $guzzle;
2020

21-
/**
22-
* @param Request $request
23-
* @param array $queryParams
24-
* @return ResponseInterface
25-
*/
26-
private function sendRequestWithQueryParams(Request $request, array $queryParams = [])
27-
{
28-
return $this->guzzle->send($request, [RequestOptions::QUERY => $queryParams]);
29-
}
30-
3121
/**
3222
* @param Request $request
3323
* @param array $queryParams
3424
* @return PromiseInterface
3525
*/
36-
private function sendRequestAsync(Request $request, array $queryParams = [])
26+
private function sendRequestWithQueryParams(Request $request, array $queryParams = [])
3727
{
3828
return $this->guzzle->sendAsync($request, [RequestOptions::QUERY => $queryParams]);
3929
}
@@ -74,7 +64,7 @@ private function setHeaderOnRequest(Request $request, $header, $value)
7464
}
7565

7666
/**
77-
* @param \GuzzleHttp\Psr7\Response $response
67+
* @param ResponseInterface $response
7868
* @return array
7969
*/
8070
private function responseAsArrayFromJson($response)

0 commit comments

Comments
 (0)