@amazeelabs/silverback-gatsby 3.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/drupal/silverback_gatsby/.prettierignore +1 -0
- package/drupal/silverback_gatsby/CHANGELOG.md +1216 -0
- package/drupal/silverback_gatsby/README.md +297 -0
- package/drupal/silverback_gatsby/composer.json +15 -0
- package/drupal/silverback_gatsby/directives.gql +63 -0
- package/drupal/silverback_gatsby/directives.graphql +62 -0
- package/drupal/silverback_gatsby/drush.services.yml +9 -0
- package/drupal/silverback_gatsby/graphql/entity.directive.graphqls +2 -0
- package/drupal/silverback_gatsby/graphql/menu.directive.graphqls +17 -0
- package/drupal/silverback_gatsby/graphql/silverback_gatsby.base.graphqls +25 -0
- package/drupal/silverback_gatsby/graphql/silverback_gatsby.extension.graphqls +10 -0
- package/drupal/silverback_gatsby/graphql/stringTranslation.directive.graphqls +4 -0
- package/drupal/silverback_gatsby/graphql/translatableString.directive.graphqls +2 -0
- package/drupal/silverback_gatsby/modules/silverback_gatsby_example/directives.gql +6 -0
- package/drupal/silverback_gatsby/modules/silverback_gatsby_example/graphql/.graphqlrc.json +4 -0
- package/drupal/silverback_gatsby/modules/silverback_gatsby_example/graphql/silverback_gatsby_example.graphqls +39 -0
- package/drupal/silverback_gatsby/modules/silverback_gatsby_example/silverback_gatsby_example.info.yml +7 -0
- package/drupal/silverback_gatsby/modules/silverback_gatsby_example/silverback_gatsby_example.module +16 -0
- package/drupal/silverback_gatsby/modules/silverback_gatsby_example/src/Directives.php +24 -0
- package/drupal/silverback_gatsby/silverback_gatsby.info.yml +8 -0
- package/drupal/silverback_gatsby/silverback_gatsby.install +180 -0
- package/drupal/silverback_gatsby/silverback_gatsby.links.task.yml +6 -0
- package/drupal/silverback_gatsby/silverback_gatsby.module +119 -0
- package/drupal/silverback_gatsby/silverback_gatsby.permissions.yml +8 -0
- package/drupal/silverback_gatsby/silverback_gatsby.post_update.php +15 -0
- package/drupal/silverback_gatsby/silverback_gatsby.routing.yml +28 -0
- package/drupal/silverback_gatsby/silverback_gatsby.services.yml +50 -0
- package/drupal/silverback_gatsby/src/Annotation/GatsbyFeed.php +41 -0
- package/drupal/silverback_gatsby/src/Commands/SilverbackGatsbyCommands.php +102 -0
- package/drupal/silverback_gatsby/src/Controller/BuildController.php +45 -0
- package/drupal/silverback_gatsby/src/Controller/PublisherController.php +34 -0
- package/drupal/silverback_gatsby/src/Directives.php +51 -0
- package/drupal/silverback_gatsby/src/GatsbyBuildTrigger.php +230 -0
- package/drupal/silverback_gatsby/src/GatsbyBuildTriggerInterface.php +52 -0
- package/drupal/silverback_gatsby/src/GatsbyUpdate.php +38 -0
- package/drupal/silverback_gatsby/src/GatsbyUpdateHandler.php +181 -0
- package/drupal/silverback_gatsby/src/GatsbyUpdateTracker.php +98 -0
- package/drupal/silverback_gatsby/src/GatsbyUpdateTrackerInterface.php +59 -0
- package/drupal/silverback_gatsby/src/GatsbyUpdateTrigger.php +69 -0
- package/drupal/silverback_gatsby/src/GatsbyUpdateTriggerInterface.php +22 -0
- package/drupal/silverback_gatsby/src/GraphQL/Build.php +235 -0
- package/drupal/silverback_gatsby/src/GraphQL/ComposableSchema.php +73 -0
- package/drupal/silverback_gatsby/src/LocaleStorageDecorator.php +181 -0
- package/drupal/silverback_gatsby/src/MenuTreeStorageDecorator.php +139 -0
- package/drupal/silverback_gatsby/src/Plugin/FeedBase.php +121 -0
- package/drupal/silverback_gatsby/src/Plugin/FeedInterface.php +132 -0
- package/drupal/silverback_gatsby/src/Plugin/FeedPluginManager.php +39 -0
- package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/EntityFeed.php +252 -0
- package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/MenuFeed.php +292 -0
- package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/StringTranslationFeed.php +171 -0
- package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/TranslatableStringFeed.php +128 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/CurrentUserEntity.php +43 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/EntityQueryBase.php +40 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FetchEntity.php +371 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FetchString.php +64 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FetchTranslatableString.php +74 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FocalPoint.php +47 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/GatsbyBuildId.php +36 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/GatsbyExtractId.php +28 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/GatsbyExtractLangcode.php +28 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/ImageProps.php +149 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/ListEntities.php +88 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/ListStrings.php +87 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/StringId.php +37 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/StringTranslations.php +94 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/EntityFetch.php +51 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/EntityTranslationsWithDefault.php +30 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/FocalPoint.php +27 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/ImageProps.php +27 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/MenuLangcode.php +27 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/MenuTranslations.php +36 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/SilverbackGatsbyEntityId.php +39 -0
- package/drupal/silverback_gatsby/src/Plugin/GraphQL/SchemaExtension/SilverbackGatsbySchemaExtension.php +384 -0
- package/drupal/silverback_gatsby/src/SilverbackGatsbyServiceProvider.php +43 -0
- package/drupal/silverback_gatsby/src/SilverbackGatsbySessionConfiguration.php +30 -0
- package/drupal/silverback_gatsby/src/SilverbackReverseProxyMiddleware.php +49 -0
- package/drupal/silverback_gatsby/tests/queries/create-page-fields.gql +12 -0
- package/drupal/silverback_gatsby/tests/queries/current-user.gql +6 -0
- package/drupal/silverback_gatsby/tests/queries/feed_info.gql +12 -0
- package/drupal/silverback_gatsby/tests/queries/load-entity.gql +5 -0
- package/drupal/silverback_gatsby/tests/queries/menus.gql +31 -0
- package/drupal/silverback_gatsby/tests/queries/multilingual-menus.gql +11 -0
- package/drupal/silverback_gatsby/tests/queries/revisionable-translatable.gql +15 -0
- package/drupal/silverback_gatsby/tests/queries/revisionable.gql +8 -0
- package/drupal/silverback_gatsby/tests/queries/translatable.gql +14 -0
- package/drupal/silverback_gatsby/tests/queries/untranslatable.gql +10 -0
- package/drupal/silverback_gatsby/tests/schema/.graphqlrc.json +4 -0
- package/drupal/silverback_gatsby/tests/schema/translatable-strings.graphql +7 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/CurrentUserTest.php +37 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/EntityFeedTest.php +490 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/EntityFeedTestBase.php +178 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyBuildTriggerTest.php +155 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyFeedInfoTest.php +319 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyUpdateHandlerTest.php +131 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyUpdateTrackerTest.php +196 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyUpdateTriggerTest.php +177 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/MenuFeedTest.php +192 -0
- package/drupal/silverback_gatsby/tests/src/Kernel/TranslatableStringFeedTest.php +210 -0
- package/drupal/silverback_gatsby/tests/src/Traits/NotificationCheckTrait.php +43 -0
- package/package.json +15 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby\Plugin\GraphQL\SchemaExtension;
|
|
4
|
+
|
|
5
|
+
use Drupal\Component\Plugin\PluginManagerInterface;
|
|
6
|
+
use Drupal\Core\Entity\EntityInterface;
|
|
7
|
+
use Drupal\Core\Entity\TranslatableInterface;
|
|
8
|
+
use Drupal\Core\Extension\ModuleHandlerInterface;
|
|
9
|
+
use Drupal\graphql\GraphQL\Execution\ResolveContext;
|
|
10
|
+
use Drupal\graphql\GraphQL\Resolver\ResolverInterface;
|
|
11
|
+
use Drupal\graphql\GraphQL\ResolverBuilder;
|
|
12
|
+
use Drupal\graphql\GraphQL\ResolverRegistry;
|
|
13
|
+
use Drupal\graphql\GraphQL\ResolverRegistryInterface;
|
|
14
|
+
use Drupal\graphql_directives\DirectableSchemaExtensionPluginBase;
|
|
15
|
+
use Drupal\silverback_gatsby\Plugin\FeedInterface;
|
|
16
|
+
use GraphQL\Language\AST\DocumentNode;
|
|
17
|
+
use GraphQL\Language\AST\ListValueNode;
|
|
18
|
+
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
|
|
19
|
+
use GraphQL\Language\AST\StringValueNode;
|
|
20
|
+
use Psr\Log\LoggerInterface;
|
|
21
|
+
use Symfony\Component\DependencyInjection\ContainerInterface;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Schema extension plugin that prepares any schema to be consumed by Gatsby.
|
|
25
|
+
*
|
|
26
|
+
* @SchemaExtension(
|
|
27
|
+
* id = "silverback_gatsby",
|
|
28
|
+
* name = "Silverback Gatsby",
|
|
29
|
+
* description = "Schema extension providing default resolvers for Gatsby."
|
|
30
|
+
* )
|
|
31
|
+
*/
|
|
32
|
+
class SilverbackGatsbySchemaExtension extends DirectableSchemaExtensionPluginBase
|
|
33
|
+
{
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The list of feeds that are used by the parent schema.
|
|
37
|
+
*
|
|
38
|
+
* @var array
|
|
39
|
+
*/
|
|
40
|
+
protected array $feeds = [];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The list of fields marked with "resolve*" directives.
|
|
44
|
+
*
|
|
45
|
+
* @var array
|
|
46
|
+
* Keys are GraphQL paths, values are directive names and arguments.
|
|
47
|
+
* Example:
|
|
48
|
+
* [
|
|
49
|
+
* 'Page.path' => [
|
|
50
|
+
* 'name' => 'resolvePath',
|
|
51
|
+
* 'arguments' => [],
|
|
52
|
+
* ],
|
|
53
|
+
* 'Page.title' => [
|
|
54
|
+
* 'name' => 'resolveProperty',
|
|
55
|
+
* 'arguments' => ['path' => 'title.value'],
|
|
56
|
+
* ]
|
|
57
|
+
* ]
|
|
58
|
+
*/
|
|
59
|
+
protected array $resolvers;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @var \Drupal\Core\Plugin\DefaultPluginManager|object|null
|
|
63
|
+
*/
|
|
64
|
+
protected $feedManager;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @var \Psr\Log\LoggerInterface
|
|
68
|
+
*/
|
|
69
|
+
protected $logger;
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* {@inheritdoc}
|
|
74
|
+
*
|
|
75
|
+
* @codeCoverageIgnore
|
|
76
|
+
*/
|
|
77
|
+
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition)
|
|
78
|
+
{
|
|
79
|
+
return new static(
|
|
80
|
+
$configuration,
|
|
81
|
+
$plugin_id,
|
|
82
|
+
$plugin_definition,
|
|
83
|
+
$container->get('module_handler'),
|
|
84
|
+
$container->get('silverback_gatsby.feed_manager'),
|
|
85
|
+
$container->get('logger.factory')->get('silverback_gatsby'),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* {@inheritDoc}
|
|
91
|
+
*/
|
|
92
|
+
public function __construct(
|
|
93
|
+
array $configuration,
|
|
94
|
+
$pluginId,
|
|
95
|
+
array $pluginDefinition,
|
|
96
|
+
ModuleHandlerInterface $moduleHandler,
|
|
97
|
+
PluginManagerInterface $feedManager,
|
|
98
|
+
LoggerInterface $logger
|
|
99
|
+
) {
|
|
100
|
+
parent::__construct(
|
|
101
|
+
$configuration,
|
|
102
|
+
$pluginId,
|
|
103
|
+
$pluginDefinition,
|
|
104
|
+
$moduleHandler,
|
|
105
|
+
);
|
|
106
|
+
$this->feedManager = $feedManager;
|
|
107
|
+
$this->logger = $logger;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public function getBaseDefinition() {
|
|
111
|
+
return implode("\n", [
|
|
112
|
+
$this->getDirectiveDefinitions(),
|
|
113
|
+
parent::getBaseDefinition(),
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* {@inheritDoc}
|
|
119
|
+
*/
|
|
120
|
+
public function getDirectiveDefinitions(): string
|
|
121
|
+
{
|
|
122
|
+
$feeds = $this->feedManager->getDefinitions();
|
|
123
|
+
uasort($feeds, fn($a, $b) => strnatcasecmp($a['id'], $b['id']));
|
|
124
|
+
$directives = array_map(fn($def) => $def['directive'], $feeds);
|
|
125
|
+
return implode("\n", $directives);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Retrieve all feeds that are referenced in the host schema.
|
|
130
|
+
*
|
|
131
|
+
* @return \Drupal\silverback_gatsby\Plugin\FeedInterface[]
|
|
132
|
+
* @throws \Drupal\Component\Plugin\Exception\PluginException
|
|
133
|
+
*/
|
|
134
|
+
public function getFeeds(DocumentNode $ast): array
|
|
135
|
+
{
|
|
136
|
+
if (count($this->feeds) === 0) {
|
|
137
|
+
// Search for object type definitions ...
|
|
138
|
+
foreach ($ast->definitions->getIterator() as $definition) {
|
|
139
|
+
// ... that have directives.
|
|
140
|
+
if ($definition instanceof ObjectTypeDefinitionNode && $definition->directives) {
|
|
141
|
+
// Create feed instances for all directives that are know to the
|
|
142
|
+
// feed manager.
|
|
143
|
+
foreach ($definition->directives->getIterator() as $directive) {
|
|
144
|
+
/** @var \GraphQL\Language\AST\DirectiveNode $directive */
|
|
145
|
+
$id = $directive->name->value;
|
|
146
|
+
if (!$this->feedManager->hasDefinition($id)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Collect the type name.
|
|
151
|
+
$config = [
|
|
152
|
+
'typeName' => $definition->name->value,
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
// Collect the directive arguments.
|
|
156
|
+
foreach ($directive->arguments->getIterator() as $arg) {
|
|
157
|
+
/** @var \GraphQL\Language\AST\ArgumentNode $arg */
|
|
158
|
+
if ($arg->value instanceof ListValueNode) {
|
|
159
|
+
// If it's a list value, turn it into an array of values.
|
|
160
|
+
$config[$arg->name->value] = [];
|
|
161
|
+
for ($i = 0; $i < $arg->value->values->count(); $i++) {
|
|
162
|
+
if ($arg->value->values[$i] instanceof StringValueNode) {
|
|
163
|
+
$config[$arg->name->value][] = $arg->value->values[$i]->value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
$config[$arg->name->value] = $arg->value->value;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Collect the field directives.
|
|
172
|
+
/** @var \GraphQL\Language\AST\FieldDefinitionNode $field */
|
|
173
|
+
foreach ($definition->fields as $field) {
|
|
174
|
+
foreach ($field->directives as $fieldDirective) {
|
|
175
|
+
|
|
176
|
+
// Directives used for automatic page creation.
|
|
177
|
+
if (in_array($fieldDirective->name->value, ['isPath', 'path'], TRUE)) {
|
|
178
|
+
$config['createPageFields']['isPath'] = $field->name->value;
|
|
179
|
+
}
|
|
180
|
+
if (in_array($fieldDirective->name->value, ['isTemplate', 'template'], TRUE)) {
|
|
181
|
+
$config['createPageFields']['isTemplate'] = $field->name->value;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
$this->feeds[] = $this->feedManager->createInstance($id, $config);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return $this->feeds;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Build the automatic schema definition for a given Feed.
|
|
196
|
+
*/
|
|
197
|
+
protected function getSchemaDefinitions(DocumentNode $ast, FeedInterface $feed): string
|
|
198
|
+
{
|
|
199
|
+
$typeName = $feed->getTypeName();
|
|
200
|
+
$singleFieldName = $feed->getSingleFieldName();
|
|
201
|
+
$listFieldName = $feed->getListFieldName();
|
|
202
|
+
$schema = [
|
|
203
|
+
"extend type Query {",
|
|
204
|
+
" $singleFieldName(id: String!): $typeName @deprecated",
|
|
205
|
+
" $listFieldName(offset: Int, limit: Int): [$typeName]! @deprecated",
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
$schema[] = "}";
|
|
209
|
+
|
|
210
|
+
if ($feed->isTranslatable()) {
|
|
211
|
+
$schema[] = "extend type $typeName {";
|
|
212
|
+
$schema[] = " _id: String! @deprecated";
|
|
213
|
+
$schema[] = " _drupalId: String! @deprecated";
|
|
214
|
+
$schema[] = " _defaultTranslation: Boolean! @deprecated";
|
|
215
|
+
$schema[] = " _langcode: String! @deprecated";
|
|
216
|
+
$schema[] = " _translations: [$typeName!]! @deprecated";
|
|
217
|
+
$schema[] = "}";
|
|
218
|
+
} else {
|
|
219
|
+
$schema[] = "extend type $typeName {";
|
|
220
|
+
$schema[] = " _id: String! @deprecated";
|
|
221
|
+
$schema[] = " _drupalId: String! @deprecated";
|
|
222
|
+
$schema[] = "}";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
$schema[] = $feed->getExtensionDefinition($ast);
|
|
226
|
+
|
|
227
|
+
return implode("\n", $schema);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
protected function getDirectableExtensionDefinition(DocumentNode $ast): string {
|
|
231
|
+
// Collect all active feeds and prepend their definitions to the schema.
|
|
232
|
+
$schema = array_map(fn(FeedInterface $feed) => $this->getSchemaDefinitions($ast, $feed), $this->getFeeds($ast));
|
|
233
|
+
array_unshift($schema, $this->getOriginalTypenameDefinitions($ast));
|
|
234
|
+
return implode("\n", $schema);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
protected function registerDirectableResolvers(DocumentNode $ast, ResolverRegistryInterface $registry): void
|
|
238
|
+
{
|
|
239
|
+
$builder = new ResolverBuilder();
|
|
240
|
+
$this->addFieldResolvers($ast, $registry, $builder);
|
|
241
|
+
$this->addOriginalTypenameResolvers($ast, $registry, $builder);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Attach a _original_typename field to every type.
|
|
247
|
+
*
|
|
248
|
+
* To preserve the original type in cases where the types are namespaced and
|
|
249
|
+
* merged into a different graphql schema (e.g. Gatsby).
|
|
250
|
+
*
|
|
251
|
+
* @return string
|
|
252
|
+
*/
|
|
253
|
+
protected function getOriginalTypenameDefinitions(DocumentNode $ast): string
|
|
254
|
+
{
|
|
255
|
+
$types = [];
|
|
256
|
+
foreach ($ast->definitions->getIterator() as $definition) {
|
|
257
|
+
if ($definition instanceof ObjectTypeDefinitionNode) {
|
|
258
|
+
$name = $definition->name->value;
|
|
259
|
+
$types[] = "extend type {$name} { _original_typename: String! @deprecated }";
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return implode("\n", $types);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Attach a _original_typename resolvers.
|
|
267
|
+
*
|
|
268
|
+
* @return void
|
|
269
|
+
*/
|
|
270
|
+
protected function addOriginalTypenameResolvers(DocumentNode $ast, ResolverRegistry $registry, ResolverBuilder $builder)
|
|
271
|
+
{
|
|
272
|
+
foreach ($ast->definitions->getIterator() as $definition) {
|
|
273
|
+
if ($definition instanceof ObjectTypeDefinitionNode) {
|
|
274
|
+
$registry->addFieldResolver($definition->name->value, '_original_typename', $builder->fromValue($definition->name->value));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Implement field resolvers for this extension.
|
|
281
|
+
*/
|
|
282
|
+
protected function addFieldResolvers(DocumentNode $ast, ResolverRegistry $registry, ResolverBuilder $builder)
|
|
283
|
+
{
|
|
284
|
+
|
|
285
|
+
$registry->addFieldResolver(
|
|
286
|
+
'Query',
|
|
287
|
+
'_drupalFeedInfo',
|
|
288
|
+
$builder->fromValue(array_map(fn(FeedInterface $feed) => $feed->info(), $this->getFeeds($ast)))
|
|
289
|
+
);
|
|
290
|
+
$registry->addFieldResolver(
|
|
291
|
+
'Query',
|
|
292
|
+
'_drupalBuildId',
|
|
293
|
+
$builder->callback(function ($value, $args, ResolveContext $context) {
|
|
294
|
+
// Make sure this is never cached.
|
|
295
|
+
$context->mergeCacheMaxAge(0);
|
|
296
|
+
/** @var \Drupal\silverback_gatsby\GatsbyUpdateTrackerInterface $tracker */
|
|
297
|
+
$tracker = \Drupal::service('silverback_gatsby.update_tracker');
|
|
298
|
+
return $tracker->latestBuild($context->getServer()->id());
|
|
299
|
+
})
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
$registry->addFieldResolver('_Feed', 'changes', $builder->callback(function ($value, $args, ResolveContext $context) {
|
|
303
|
+
// Make sure this is never cached.
|
|
304
|
+
$context->mergeCacheMaxAge(0);
|
|
305
|
+
/** @var \Drupal\silverback_gatsby\GatsbyUpdateTrackerInterface $tracker */
|
|
306
|
+
$tracker = \Drupal::service('silverback_gatsby.update_tracker');
|
|
307
|
+
return array_map(
|
|
308
|
+
fn($change) => $change->id,
|
|
309
|
+
array_filter(
|
|
310
|
+
isset($args['lastBuild']) && isset($args['currentBuild'])
|
|
311
|
+
? $tracker->diff($args['lastBuild'], $args['currentBuild'], $context->getServer()->id())
|
|
312
|
+
: [],
|
|
313
|
+
fn($change) => $change->type === $value['typeName']
|
|
314
|
+
)
|
|
315
|
+
);
|
|
316
|
+
}));
|
|
317
|
+
|
|
318
|
+
foreach ($this->getFeeds($ast) as $feed) {
|
|
319
|
+
|
|
320
|
+
$idResolver = $feed->resolveId();
|
|
321
|
+
$langcodeResolver = $feed->resolveLangcode();
|
|
322
|
+
|
|
323
|
+
$registry->addFieldResolver(
|
|
324
|
+
'Query', $feed->getListFieldName(),
|
|
325
|
+
$feed->resolveItems(
|
|
326
|
+
$builder->fromArgument('limit'),
|
|
327
|
+
$builder->fromArgument('offset'),
|
|
328
|
+
)
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
$typeName = $feed->getTypeName();
|
|
332
|
+
$registry->addFieldResolver($typeName, '_drupalId', $idResolver);
|
|
333
|
+
$feed->addExtensionResolvers($registry, $builder);
|
|
334
|
+
|
|
335
|
+
if ($feed->isTranslatable()) {
|
|
336
|
+
$registry->addFieldResolver(
|
|
337
|
+
'Query', $feed->getSingleFieldName(),
|
|
338
|
+
$feed->resolveItem(
|
|
339
|
+
$builder->produce('gatsby_extract_id')
|
|
340
|
+
->map('id', $builder->fromArgument('id')),
|
|
341
|
+
$builder->produce('gatsby_extract_langcode')
|
|
342
|
+
->map('id', $builder->fromArgument('id')),
|
|
343
|
+
)
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
$registry->addFieldResolver(
|
|
347
|
+
$typeName,
|
|
348
|
+
'_id',
|
|
349
|
+
$builder->produce('gatsby_build_id')
|
|
350
|
+
->map('id', $idResolver)
|
|
351
|
+
->map('langcode', $langcodeResolver)
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
$registry->addFieldResolver($typeName, '_langcode', $langcodeResolver);
|
|
355
|
+
$registry->addFieldResolver($typeName, '_defaultTranslation', $feed->resolveDefaultTranslation());
|
|
356
|
+
$registry->addFieldResolver($typeName, '_translations', $feed->resolveTranslations());
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
$registry->addFieldResolver(
|
|
360
|
+
'Query', $feed->getSingleFieldName(),
|
|
361
|
+
$feed->resolveItem(
|
|
362
|
+
$builder->fromArgument('id')
|
|
363
|
+
)
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
$registry->addFieldResolver($typeName, '_id', $idResolver);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
$addResolver = function (string $path, ResolverInterface $resolver) use ($registry) {
|
|
371
|
+
[$type, $field] = explode('.', $path);
|
|
372
|
+
$registry->addFieldResolver($type, $field, $resolver);
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
$currentUser = $builder->produce('current_user_entity');
|
|
376
|
+
$addResolver('Query._currentUser', $currentUser);
|
|
377
|
+
|
|
378
|
+
$entityId = $builder->produce('entity_id')->map('entity', $builder->fromParent());
|
|
379
|
+
$entityLabel = $builder->callback(fn(EntityInterface $value) => $value->label());
|
|
380
|
+
$addResolver('_User.id', $entityId);
|
|
381
|
+
$addResolver('_User.name', $entityLabel);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby;
|
|
4
|
+
|
|
5
|
+
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
|
6
|
+
use Drupal\Core\DependencyInjection\ServiceProviderBase;
|
|
7
|
+
use Symfony\Component\DependencyInjection\Definition;
|
|
8
|
+
use Symfony\Component\DependencyInjection\Reference;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Service provider class for the silverback_gatsby module..
|
|
12
|
+
*/
|
|
13
|
+
class SilverbackGatsbyServiceProvider extends ServiceProviderBase {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* {@inheritDoc}
|
|
17
|
+
*/
|
|
18
|
+
public function alter(ContainerBuilder $container) {
|
|
19
|
+
// To not introduce a dependency on the locale module, we only decorate the
|
|
20
|
+
// locale.storage service if the service actually exists, so if the locale
|
|
21
|
+
// module is enabled.
|
|
22
|
+
// We also check if the StringContextInterface exists, otherwise most
|
|
23
|
+
// probably the patch from https://www.drupal.org/node/2123543 was not
|
|
24
|
+
// applied.
|
|
25
|
+
if ($container->hasDefinition('locale.storage') && interface_exists('Drupal\locale\StringContextInterface')) {
|
|
26
|
+
$localeDecoratorDefinition = new Definition();
|
|
27
|
+
$localeDecoratorDefinition->setClass(LocaleStorageDecorator::class);
|
|
28
|
+
$localeDecoratorDefinition->setDecoratedService('locale.storage');
|
|
29
|
+
$localeDecoratorDefinition->setPublic(FALSE);
|
|
30
|
+
$localeDecoratorDefinition->addArgument(new Reference('silverback_gatsby.locale.storage.inner'));
|
|
31
|
+
$definitions['silverback_gatsby.locale.storage'] = $localeDecoratorDefinition;
|
|
32
|
+
$container->addDefinitions($definitions);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
// Swap the session configuration service with a custom one.
|
|
37
|
+
if ($container->hasDefinition('session_configuration')) {
|
|
38
|
+
$definition = $container->getDefinition('session_configuration');
|
|
39
|
+
$definition->setClass('Drupal\silverback_gatsby\SilverbackGatsbySessionConfiguration');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby;
|
|
4
|
+
|
|
5
|
+
use Drupal\Core\Session\SessionConfiguration;
|
|
6
|
+
use Symfony\Component\HttpFoundation\Request;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Decorator for the core session configuration service.
|
|
10
|
+
*/
|
|
11
|
+
class SilverbackGatsbySessionConfiguration extends SessionConfiguration {
|
|
12
|
+
/**
|
|
13
|
+
* Remove X-Forwarded-* headers from the request, so they
|
|
14
|
+
* don't affect the session name. Otherwise session information
|
|
15
|
+
* is lost when using a reverse proxy and direct access simultaneously.
|
|
16
|
+
*
|
|
17
|
+
* Use case: User login-in via the backend domain and send requests from
|
|
18
|
+
* the frontend that include X-Forwarded-* headers to create image urls
|
|
19
|
+
* with the frontend domain. Without this, the dynamic request would not
|
|
20
|
+
* be authenticated any more because the session name would be different,
|
|
21
|
+
* because `$request->getHost()` would return the X-Forwarded-Host.
|
|
22
|
+
*/
|
|
23
|
+
protected function getUnprefixedName(Request $request) {
|
|
24
|
+
$cleaned = clone $request;
|
|
25
|
+
$cleaned->headers->remove('X-Forwarded-Proto');
|
|
26
|
+
$cleaned->headers->remove('X-Forwarded-Host');
|
|
27
|
+
$cleaned->headers->remove('X-Forwarded-Port');
|
|
28
|
+
return parent::getUnprefixedName($cleaned);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby;
|
|
4
|
+
|
|
5
|
+
use Symfony\Component\HttpFoundation\Request;
|
|
6
|
+
use Symfony\Component\HttpFoundation\Response;
|
|
7
|
+
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Custom reverse proxy middleweare.
|
|
11
|
+
*
|
|
12
|
+
* Rewrites custom reverse proxy headers to standard ones.
|
|
13
|
+
* Lagoon won't allow X-Forwarded-* headers from unknown proxies
|
|
14
|
+
* and Netlify does not provide an IP range. Therefore we send
|
|
15
|
+
* custom SLB-Forwarded-* headers and write them into X-Forwarded-*
|
|
16
|
+
* using this middleware.
|
|
17
|
+
*/
|
|
18
|
+
class SilverbackReverseProxyMiddleware implements HttpKernelInterface {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The inner kernel to which the request will be passed.
|
|
22
|
+
*
|
|
23
|
+
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
|
|
24
|
+
*/
|
|
25
|
+
protected $app;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Constructs a HostChanger object.
|
|
29
|
+
*
|
|
30
|
+
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $app
|
|
31
|
+
* The inner kernel to which the request will be passed.
|
|
32
|
+
*/
|
|
33
|
+
public function __construct(HttpKernelInterface $app) {
|
|
34
|
+
$this->app = $app;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* {@inheritDoc}
|
|
39
|
+
*/
|
|
40
|
+
public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUEST, $catch = TRUE): Response {
|
|
41
|
+
foreach (['Proto', 'Host', 'Port', 'For'] as $header) {
|
|
42
|
+
if ($request->headers->has('SLB-Forwarded-' . $header)) {
|
|
43
|
+
$request->headers->set('X-Forwarded-' . $header, $request->headers->get('SLB-Forwarded-' . $header));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Pass the request to the next middleware.
|
|
47
|
+
return $this->app->handle($request, $type, $catch);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
query FeedInfo($lastBuild: Int, $currentBuild: Int) {
|
|
2
|
+
_drupalBuildId
|
|
3
|
+
_drupalFeedInfo {
|
|
4
|
+
typeName
|
|
5
|
+
translatable
|
|
6
|
+
singleFieldName
|
|
7
|
+
listFieldName
|
|
8
|
+
changes(lastBuild: $lastBuild, currentBuild: $currentBuild)
|
|
9
|
+
pathFieldName
|
|
10
|
+
templateFieldName
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
query Menus {
|
|
2
|
+
_queryMainMenus(limit: 10, offset: 0) {
|
|
3
|
+
__typename
|
|
4
|
+
_id
|
|
5
|
+
_drupalId
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
_queryVisibleMainMenus(limit: 10, offset: 0) {
|
|
9
|
+
__typename
|
|
10
|
+
_id
|
|
11
|
+
_drupalId
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_loadMainMenu(id: "main") {
|
|
15
|
+
items {
|
|
16
|
+
id
|
|
17
|
+
parent
|
|
18
|
+
label
|
|
19
|
+
url
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_loadVisibleMainMenu(id: "main") {
|
|
24
|
+
items {
|
|
25
|
+
id
|
|
26
|
+
parent
|
|
27
|
+
label
|
|
28
|
+
url
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
query {
|
|
2
|
+
a: _loadPageRevision(id: "1:en", revision: "1") {
|
|
3
|
+
title
|
|
4
|
+
}
|
|
5
|
+
# This should be null, since the first revision has no german translation.
|
|
6
|
+
b: _loadPageRevision(id: "1:de", revision: "1") {
|
|
7
|
+
title
|
|
8
|
+
}
|
|
9
|
+
c: _loadPageRevision(id: "1:de", revision: "2") {
|
|
10
|
+
title
|
|
11
|
+
}
|
|
12
|
+
d: _loadPageRevision(id: "1:de", revision: "3") {
|
|
13
|
+
title
|
|
14
|
+
}
|
|
15
|
+
}
|