Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"require": {
"php": ">=5.6",
"guzzlehttp/guzzle": "^6.0",
"guzzlehttp/promises": "~1.1",
"psr/cache": "~1.0.0"
},
"require-dev": {
Expand Down
115 changes: 89 additions & 26 deletions src/Contentful.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\RequestException;
use function GuzzleHttp\Promise\all;
use function GuzzleHttp\Promise\coroutine;
use GuzzleHttp\Promise\FulfilledPromise;
use function GuzzleHttp\Promise\promise_for;
use GuzzleHttp\Promise\PromiseInterface;
use Markup\Contentful\Cache\NullCacheItemPool;
Expand Down Expand Up @@ -103,7 +103,9 @@ public function __construct(array $spaces, array $options = [])
public function getSpace($space = null, array $options = [])
{
if ($space instanceof SpaceInterface) {
return $space;
return ($this->isAsyncCall($options))
? promise_for($space)
: $space;
} else {
$spaceName = $space;
}
Expand Down Expand Up @@ -133,7 +135,9 @@ public function getSpace($space = null, array $options = [])
public function getEntry($id, $space = null, array $options = [])
{
if ($this->envelope->hasEntry($id)) {
return $this->envelope->findEntry($id);
return ($this->isAsyncCall($options))
? promise_for($this->envelope->findEntry($id))
: $this->envelope->findEntry($id);
}
$spaceName = ($space instanceof SpaceInterface) ? $space->getName() : $space;
$spaceData = $this->getSpaceDataForName(($space instanceof SpaceInterface) ? $space->getName() : $space);
Expand Down Expand Up @@ -187,7 +191,9 @@ public function getEntries(array $parameters = [], $space = null, array $options
public function getAsset($id, $space = null, array $options = [])
{
if ($this->envelope->hasAsset($id)) {
return $this->envelope->findAsset($id);
return ($this->isAsyncCall($options))
? promise_for($this->envelope->findAsset($id))
: $this->envelope->findAsset($id);
}
$spaceName = ($space instanceof SpaceInterface) ? $space->getName() : $space;
$spaceData = $this->getSpaceDataForName($spaceName);
Expand Down Expand Up @@ -215,7 +221,9 @@ public function getAsset($id, $space = null, array $options = [])
public function getContentType($id, $space = null, array $options = [])
{
if ($this->envelope->hasContentType($id)) {
return $this->envelope->findContentType($id);
return ($this->isAsyncCall($options))
? promise_for($this->envelope->findContentType($id))
: $this->envelope->findContentType($id);
}

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

Expand Down Expand Up @@ -292,26 +308,40 @@ function () use ($name, $space, $options) {
}

/**
* @param Link $link
* @param Link $link
* @param array $options
* @return ResourceInterface|PromiseInterface
* @return PromiseInterface
*/
public function resolveLink($link, array $options = [])
{
//check whether the "link" is already actually a resolved resource
if ($link instanceof ResourceInterface) {
return $link;
return promise_for($link);
}
try {
switch ($link->getLinkType()) {
case 'Entry':
return $this->getEntry($link->getId(), $link->getSpaceName(), $options);
return $this->getEntry(
$link->getId(),
$link->getSpaceName(),
array_merge($options, ['async' => true])
);
case 'Asset':
return $this->getAsset($link->getId(), $link->getSpaceName(), $options);
return $this->getAsset(
$link->getId(),
$link->getSpaceName(),
array_merge($options, ['async' => true])
);
case 'ContentType':
return $this->getContentType($link->getId(), $link->getSpaceName(), $options);
return $this->getContentType(
$link->getId(),
$link->getSpaceName(),
array_merge($options, ['async' => true])
);
default:
throw new \InvalidArgumentException(sprintf('Tried to resolve unknown link type "%s".', $link->getLinkType()));
throw new \InvalidArgumentException(
sprintf('Tried to resolve unknown link type "%s".', $link->getLinkType())
);
}
} catch (ResourceUnavailableException $e) {
throw new LinkUnresolvableException($link, null, 0, $e);
Expand Down Expand Up @@ -387,21 +417,24 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
* Returns a built response if it passes test, or null if it doesn't.
*
* @param string $json
* @return ResourceInterface|ResourceArray|null
* @return PromiseInterface
*/
$buildResponseFromJson = function ($json) use ($spaceData, $assetDecorator, $shouldBuildTypedResources, $test) {
$json = (is_array($json)) ? $json : json_decode($json, true);
if (null === $json) {
return null;
}
$builtResponse = $this->buildResponseFromRaw(

return $this->buildResponseFromRaw(
$json,
$spaceData['name'],
$assetDecorator,
$shouldBuildTypedResources
)->then(
function ($builtResponse) use ($test) {
return (call_user_func($test, $builtResponse)) ? $builtResponse : null;
}
);

return (call_user_func($test, $builtResponse)) ? $builtResponse : null;
};
$log = function ($description, $isCacheHit, $type) use ($timer, $queryType, $api) {
$this->logger->log(
Expand All @@ -425,7 +458,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
LogInterface::TYPE_RESPONSE
);

$builtResponse = $buildResponseFromJson($cacheItemJson);
$builtResponse = (yield $buildResponseFromJson($cacheItemJson));
if ($builtResponse) {
yield promise_for($builtResponse);
return;
Expand All @@ -444,7 +477,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
true,
LogInterface::TYPE_RESOURCE
);
$builtResponse = $buildResponseFromJson($fallbackJson);
$builtResponse = (yield $buildResponseFromJson($fallbackJson));
if ($builtResponse) {
yield promise_for($builtResponse);
return;
Expand Down Expand Up @@ -478,7 +511,12 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
/**
* @var ResponseInterface $response
*/
$response = (yield $this->sendRequestAsync($request, $queryParams));
$response = ($shouldBuildTypedResources)
? array_values((yield all([
$this->sendRequestWithQueryParams($request, $queryParams),
$this->ensureContentTypesLoaded($spaceName)
])))[0]
: (yield $this->sendRequestWithQueryParams($request, $queryParams));
} catch (RequestException $e) {
/**
* @var CacheItemInterface $fallbackCacheItem
Expand All @@ -496,12 +534,12 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
$writeCacheItem->set($fallbackJson);
$writeCache->save($writeCacheItem);

yield promise_for($this->buildResponseFromRaw(
yield $this->buildResponseFromRaw(
json_decode($fallbackJson, true),
$spaceData['name'],
$assetDecorator,
$shouldBuildTypedResources
));
);
return;
}
}
Expand Down Expand Up @@ -542,7 +580,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
$responseJson = json_encode(
(!$unavailableException) ? $this->responseAsArrayFromJson($response) : null
);
$builtResponse = ($responseJson) ? $buildResponseFromJson($responseJson) : null;
$builtResponse = ($responseJson) ? (yield $buildResponseFromJson($responseJson)) : null;
$isValidResponse = (bool) $builtResponse;

//save into cache
Expand Down Expand Up @@ -587,7 +625,7 @@ function () use ($spaceData, $spaceName, $endpointUrl, $exceptionMessage, $api,
true,
LogInterface::TYPE_RESOURCE
);
$builtResponse = $buildResponseFromJson($fallbackJson);
$builtResponse = (yield $buildResponseFromJson($fallbackJson));
if ($builtResponse) {
yield promise_for($builtResponse);
return;
Expand Down Expand Up @@ -722,10 +760,10 @@ private function setApiVersionHeaderOnRequest($request, $api)

/**
* @param array $data
* @param string $spaceName
* @param AssetDecoratorInterface $assetDecorator
* @param null $spaceName
* @param AssetDecoratorInterface|null $assetDecorator
* @param bool $useTypedResources
* @return ResourceInterface
* @return PromiseInterface
*/
private function buildResponseFromRaw(
array $data,
Expand Down Expand Up @@ -891,4 +929,29 @@ private function resolveContentTypeNameFilter(IncompleteParameterInterface $filt

return $contentTypeFilterProvider->createForContentTypeName($filter->getValue(), $spaceName);
}

/**
* @param string $spaceName
* @return PromiseInterface
*/
private function ensureContentTypesLoaded($spaceName)
{
return $this->getContentTypes([], $spaceName, ['async' => true, 'untyped' => true])
->then(
function ($types) use ($spaceName) {
$this->envelope->insertAllContentTypesForSpace($types, $spaceName);

return $types;
}
);
}

/**
* @param array $options
* @return bool
*/
private function isAsyncCall(array $options)
{
return isset($options['async']) && true === $options['async'];
}
}
6 changes: 4 additions & 2 deletions src/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function getField($key)
if ($this->fields[$key] instanceof Link) {
if (!isset($this->resolvedLinks[$key])) {
try {
$resolvedLink = call_user_func($this->resolveLinkFunction, $this->fields[$key]);
$resolvedLink = call_user_func($this->resolveLinkFunction, $this->fields[$key])->wait();
} catch (LinkUnresolvableException $e) {
$resolvedLink = null;
}
Expand All @@ -70,7 +70,7 @@ public function getField($key)
if (!isset($this->resolvedLinks[$key])) {
$this->resolvedLinks[$key] = array_filter(array_map(function ($link) {
try {
$resolvedLink = call_user_func($this->resolveLinkFunction, $link);
$resolvedLink = call_user_func($this->resolveLinkFunction, $link)->wait();
} catch (LinkUnresolvableException $e) {
//if the link is unresolvable we should consider it not published and return null so this is filtered out
return null;
Expand Down Expand Up @@ -122,6 +122,8 @@ public function offsetUnset($offset)
}

/**
* Sets a function that can return a promise for a resolved link.
*
* @param callable $function
* @return self
*/
Expand Down
14 changes: 2 additions & 12 deletions src/GuzzleAbstractionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,12 @@ trait GuzzleAbstractionTrait
*/
private $guzzle;

/**
* @param Request $request
* @param array $queryParams
* @return ResponseInterface
*/
private function sendRequestWithQueryParams(Request $request, array $queryParams = [])
{
return $this->guzzle->send($request, [RequestOptions::QUERY => $queryParams]);
}

/**
* @param Request $request
* @param array $queryParams
* @return PromiseInterface
*/
private function sendRequestAsync(Request $request, array $queryParams = [])
private function sendRequestWithQueryParams(Request $request, array $queryParams = [])
{
return $this->guzzle->sendAsync($request, [RequestOptions::QUERY => $queryParams]);
}
Expand Down Expand Up @@ -74,7 +64,7 @@ private function setHeaderOnRequest(Request $request, $header, $value)
}

/**
* @param \GuzzleHttp\Psr7\Response $response
* @param ResponseInterface $response
* @return array
*/
private function responseAsArrayFromJson($response)
Expand Down
Loading