-
Notifications
You must be signed in to change notification settings - Fork 201
/
Copy pathSubRequestBuffer.php
156 lines (134 loc) · 4.34 KB
/
SubRequestBuffer.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?php
namespace Drupal\graphql\GraphQL\Buffers;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Url;
use Drupal\Core\Routing\LocalRedirectResponse;
use Drupal\graphql\SubRequestResponse;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
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 {
/**
* The http kernel service.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $httpKernel;
/**
* The request stack service.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* SubrequestBuffer constructor.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel
* The http kernel service.
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
* The request stack service.
*/
public function __construct(HttpKernelInterface $httpKernel, RequestStack $requestStack) {
$this->httpKernel = $httpKernel;
$this->requestStack = $requestStack;
}
/**
* Add an item to the buffer.
*
* @param \Drupal\Core\Url $url
* The url object to run the subrequest 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) {
/** @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 subrequest 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()
);
$request->attributes->set('_graphql_subrequest', function () use ($buffer) {
return array_map(function ($item) {
return $item['extract']($item['url']);
}, $buffer);
});
// Pass the current session to the sub request if it exists.
try {
$request->setSession($current->getSession());
}
catch (SessionNotFoundException) {
}
return $request;
}
/**
* {@inheritdoc}
*/
public function resolveBufferArray(array $buffer) {
/** @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 $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();
}
}