1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Drupal\graphql\GraphQL\Buffers; |
4
|
|
|
|
5
|
|
|
use Drupal\Core\Cache\CacheableDependencyInterface; |
6
|
|
|
use Drupal\Core\Url; |
7
|
|
|
use Drupal\graphql\GraphQL\Cache\CacheableValue; |
8
|
|
|
use Symfony\Component\HttpFoundation\Request; |
9
|
|
|
use Symfony\Component\HttpFoundation\RequestStack; |
10
|
|
|
use Symfony\Component\HttpKernel\HttpKernelInterface; |
11
|
|
|
use Symfony\Component\HttpFoundation\RedirectResponse; |
12
|
|
|
|
13
|
|
|
class SubRequestBuffer extends BufferBase { |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* The http kernel service. |
17
|
|
|
* |
18
|
|
|
* @var \Symfony\Component\HttpKernel\HttpKernelInterface |
19
|
|
|
*/ |
20
|
|
|
protected $httpKernel; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* The request stack service. |
24
|
|
|
* |
25
|
|
|
* @var \Symfony\Component\HttpFoundation\RequestStack |
26
|
|
|
*/ |
27
|
|
|
protected $requestStack; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* SubrequestBuffer constructor. |
31
|
|
|
* |
32
|
|
|
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel |
33
|
|
|
* The http kernel service. |
34
|
|
|
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack |
35
|
|
|
* The request stack service. |
36
|
|
|
*/ |
37
|
|
|
public function __construct(HttpKernelInterface $httpKernel, RequestStack $requestStack) { |
38
|
|
|
$this->httpKernel = $httpKernel; |
39
|
|
|
$this->requestStack = $requestStack; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Add an item to the buffer. |
44
|
|
|
* |
45
|
|
|
* @param \Drupal\Core\Url $url |
46
|
|
|
* The url object to run the subrequest on. |
47
|
|
|
* @param callable $extract |
48
|
|
|
* The callback to run within the sub-request. |
49
|
|
|
* |
50
|
|
|
* @return \Closure |
51
|
|
|
* The callback to invoke to load the result for this buffer item. |
52
|
|
|
*/ |
53
|
|
|
public function add(Url $url, callable $extract) { |
54
|
|
|
$item = new \ArrayObject([ |
55
|
|
|
'url' => $url, |
56
|
|
|
'extract' => $extract, |
57
|
|
|
]); |
58
|
|
|
|
59
|
|
|
return $this->createBufferResolver($item); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* {@inheritdoc} |
64
|
|
|
*/ |
65
|
|
|
protected function getBufferId($item) { |
66
|
|
|
/** @var \Drupal\Core\GeneratedUrl $url */ |
67
|
|
|
$url = $item['url']->toString(TRUE); |
68
|
|
|
|
69
|
|
|
return hash('sha256', json_encode([ |
70
|
|
|
'url' => $url->getGeneratedUrl(), |
71
|
|
|
'tags' => $url->getCacheTags(), |
72
|
|
|
'contexts' => $url->getCacheContexts(), |
73
|
|
|
'age' => $url->getCacheMaxAge(), |
74
|
|
|
])); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
protected function createRequest(Request $current, array $buffer, $url) { |
78
|
|
|
$request = Request::create( |
79
|
|
|
$url, |
80
|
|
|
'GET', |
81
|
|
|
$current->query->all(), |
82
|
|
|
$current->cookies->all(), |
83
|
|
|
$current->files->all(), |
84
|
|
|
$current->server->all() |
85
|
|
|
); |
86
|
|
|
|
87
|
|
|
$request->attributes->set('_graphql_subrequest', function () use ($buffer) { |
88
|
|
|
return array_map(function ($item) { |
89
|
|
|
return $item['extract']($item['url']); |
90
|
|
|
}, $buffer); |
91
|
|
|
}); |
92
|
|
|
|
93
|
|
|
$request->setRequestFormat('_graphql_subrequest'); |
94
|
|
|
if ($session = $current->getSession()) { |
95
|
|
|
$request->setSession($session); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
return $request; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* {@inheritdoc} |
103
|
|
|
*/ |
104
|
|
|
public function resolveBufferArray(array $buffer) { |
105
|
|
|
/** @var \Drupal\Core\GeneratedUrl $url */ |
106
|
|
|
$url = reset($buffer)['url']->toString(TRUE); |
107
|
|
|
|
108
|
|
|
$current = $this->requestStack->getCurrentRequest(); |
109
|
|
|
$target = $url->getGeneratedUrl(); |
110
|
|
|
$request = $this->createRequest($current, $buffer, $target); |
111
|
|
|
|
112
|
|
|
/** @var \Drupal\graphql\GraphQL\Buffers\SubRequestResponse $response */ |
113
|
|
|
$response = $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST); |
114
|
|
|
while ($response instanceof RedirectResponse) { |
|
|
|
|
115
|
|
|
$target = $response->getTargetUrl(); |
116
|
|
|
$request = $this->createRequest($current, $buffer, $target); |
117
|
|
|
$response = $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
// TODO: |
121
|
|
|
// Remove the request stack manipulation once the core issue described at |
122
|
|
|
// https://www.drupal.org/node/2613044 is resolved. |
123
|
|
|
while ($this->requestStack->getCurrentRequest() !== $current) { |
124
|
|
|
$this->requestStack->pop(); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
if ($url instanceof CacheableDependencyInterface) { |
|
|
|
|
128
|
|
|
$response->addCacheableDependency($url); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
return array_map(function ($value) use ($response) { |
132
|
|
|
return new CacheableValue($value, [$response]); |
133
|
|
|
}, $response->getResult()); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
} |
137
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.