graphql_compose-1.0.0-beta20/modules/graphql_compose_routes/src/GraphQL/Buffers/SubrequestBuffer.php
modules/graphql_compose_routes/src/GraphQL/Buffers/SubrequestBuffer.php
<?php
declare(strict_types=1);
namespace Drupal\graphql_compose_routes\GraphQL\Buffers;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Routing\LocalRedirectResponse;
use Drupal\Core\Url;
use Drupal\graphql\GraphQL\Buffers\BufferBase;
use Drupal\graphql\SubRequestResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* SubrequestBuffer class provided a buffer for sub-requests.
*/
class SubrequestBuffer extends BufferBase {
/**
* Constructs a SubrequestBuffer object.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel
* The http kernel service.
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
* The request stack service.
*/
public function __construct(
protected HttpKernelInterface $httpKernel,
protected RequestStack $requestStack,
) {}
/**
* Add an item to the buffer.
*
* @param \Drupal\Core\Url $url
* The url object to run the sub-request on.
* @param callable $extract
* The callback to run within the sub-request.
*
* @return \Closure
* The callback to invoke to load the result for this buffer item.
*/
public function add(Url $url, callable $extract) {
$item = new \ArrayObject([
'url' => $url,
'extract' => $extract,
]);
return $this->createBufferResolver($item);
}
/**
* {@inheritdoc}
*/
protected function getBufferId($item): string {
/** @var \Drupal\Core\GeneratedUrl $url */
$url = $item['url']->toString(TRUE);
return hash('sha256', json_encode([
'url' => $url->getGeneratedUrl(),
'tags' => $url->getCacheTags(),
'contexts' => $url->getCacheContexts(),
'age' => $url->getCacheMaxAge(),
]));
}
/**
* Create a sub-request for the given url.
*
* @param \Symfony\Component\HttpFoundation\Request $current
* The current main request.
* @param array $buffer
* The buffer.
* @param string $url
* The url to run the sub-request on.
*
* @return \Symfony\Component\HttpFoundation\Request
* The request object.
*/
protected function createRequest(Request $current, array $buffer, string $url) {
$request = Request::create(
$url,
'GET',
$current->query->all(),
$current->cookies->all(),
$current->files->all(),
$current->server->all()
);
if ($session = $current->getSession()) {
$request->setSession($session);
}
$sub_request = function () use ($buffer) {
return array_map(
fn ($item) => $item['extract']($item['url']),
$buffer
);
};
$request->attributes->set('_graphql_subrequest', $sub_request);
return $request;
}
/**
* {@inheritdoc}
*/
public function resolveBufferArray(array $buffer): array {
/** @var \Drupal\Core\GeneratedUrl $url */
$url = reset($buffer)['url']->toString(TRUE);
$current = $this->requestStack->getCurrentRequest();
$target = $url->getGeneratedUrl();
$request = $this->createRequest($current, $buffer, $target);
/** @var \Drupal\graphql\SubRequestResponse|\Drupal\Core\Routing\LocalRedirectResponse $response */
$response = $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST);
while ($response instanceof LocalRedirectResponse) {
$target = $response->getTargetUrl();
$request = $this->createRequest($current, $buffer, $target);
$response = $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST);
}
if (!($response instanceof SubRequestResponse)) {
return array_fill_keys(array_keys($buffer), NULL);
}
// @todo Remove the request stack manipulation once the core issue described at
// https://www.drupal.org/node/2613044 is resolved.
while ($this->requestStack->getCurrentRequest() !== $current) {
$this->requestStack->pop();
}
if ($url instanceof CacheableDependencyInterface) {
$response->addCacheableDependency($url);
}
return $response->getResult();
}
}
