@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.
Files changed (101) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/drupal/silverback_gatsby/.prettierignore +1 -0
  3. package/drupal/silverback_gatsby/CHANGELOG.md +1216 -0
  4. package/drupal/silverback_gatsby/README.md +297 -0
  5. package/drupal/silverback_gatsby/composer.json +15 -0
  6. package/drupal/silverback_gatsby/directives.gql +63 -0
  7. package/drupal/silverback_gatsby/directives.graphql +62 -0
  8. package/drupal/silverback_gatsby/drush.services.yml +9 -0
  9. package/drupal/silverback_gatsby/graphql/entity.directive.graphqls +2 -0
  10. package/drupal/silverback_gatsby/graphql/menu.directive.graphqls +17 -0
  11. package/drupal/silverback_gatsby/graphql/silverback_gatsby.base.graphqls +25 -0
  12. package/drupal/silverback_gatsby/graphql/silverback_gatsby.extension.graphqls +10 -0
  13. package/drupal/silverback_gatsby/graphql/stringTranslation.directive.graphqls +4 -0
  14. package/drupal/silverback_gatsby/graphql/translatableString.directive.graphqls +2 -0
  15. package/drupal/silverback_gatsby/modules/silverback_gatsby_example/directives.gql +6 -0
  16. package/drupal/silverback_gatsby/modules/silverback_gatsby_example/graphql/.graphqlrc.json +4 -0
  17. package/drupal/silverback_gatsby/modules/silverback_gatsby_example/graphql/silverback_gatsby_example.graphqls +39 -0
  18. package/drupal/silverback_gatsby/modules/silverback_gatsby_example/silverback_gatsby_example.info.yml +7 -0
  19. package/drupal/silverback_gatsby/modules/silverback_gatsby_example/silverback_gatsby_example.module +16 -0
  20. package/drupal/silverback_gatsby/modules/silverback_gatsby_example/src/Directives.php +24 -0
  21. package/drupal/silverback_gatsby/silverback_gatsby.info.yml +8 -0
  22. package/drupal/silverback_gatsby/silverback_gatsby.install +180 -0
  23. package/drupal/silverback_gatsby/silverback_gatsby.links.task.yml +6 -0
  24. package/drupal/silverback_gatsby/silverback_gatsby.module +119 -0
  25. package/drupal/silverback_gatsby/silverback_gatsby.permissions.yml +8 -0
  26. package/drupal/silverback_gatsby/silverback_gatsby.post_update.php +15 -0
  27. package/drupal/silverback_gatsby/silverback_gatsby.routing.yml +28 -0
  28. package/drupal/silverback_gatsby/silverback_gatsby.services.yml +50 -0
  29. package/drupal/silverback_gatsby/src/Annotation/GatsbyFeed.php +41 -0
  30. package/drupal/silverback_gatsby/src/Commands/SilverbackGatsbyCommands.php +102 -0
  31. package/drupal/silverback_gatsby/src/Controller/BuildController.php +45 -0
  32. package/drupal/silverback_gatsby/src/Controller/PublisherController.php +34 -0
  33. package/drupal/silverback_gatsby/src/Directives.php +51 -0
  34. package/drupal/silverback_gatsby/src/GatsbyBuildTrigger.php +230 -0
  35. package/drupal/silverback_gatsby/src/GatsbyBuildTriggerInterface.php +52 -0
  36. package/drupal/silverback_gatsby/src/GatsbyUpdate.php +38 -0
  37. package/drupal/silverback_gatsby/src/GatsbyUpdateHandler.php +181 -0
  38. package/drupal/silverback_gatsby/src/GatsbyUpdateTracker.php +98 -0
  39. package/drupal/silverback_gatsby/src/GatsbyUpdateTrackerInterface.php +59 -0
  40. package/drupal/silverback_gatsby/src/GatsbyUpdateTrigger.php +69 -0
  41. package/drupal/silverback_gatsby/src/GatsbyUpdateTriggerInterface.php +22 -0
  42. package/drupal/silverback_gatsby/src/GraphQL/Build.php +235 -0
  43. package/drupal/silverback_gatsby/src/GraphQL/ComposableSchema.php +73 -0
  44. package/drupal/silverback_gatsby/src/LocaleStorageDecorator.php +181 -0
  45. package/drupal/silverback_gatsby/src/MenuTreeStorageDecorator.php +139 -0
  46. package/drupal/silverback_gatsby/src/Plugin/FeedBase.php +121 -0
  47. package/drupal/silverback_gatsby/src/Plugin/FeedInterface.php +132 -0
  48. package/drupal/silverback_gatsby/src/Plugin/FeedPluginManager.php +39 -0
  49. package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/EntityFeed.php +252 -0
  50. package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/MenuFeed.php +292 -0
  51. package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/StringTranslationFeed.php +171 -0
  52. package/drupal/silverback_gatsby/src/Plugin/Gatsby/Feed/TranslatableStringFeed.php +128 -0
  53. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/CurrentUserEntity.php +43 -0
  54. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/EntityQueryBase.php +40 -0
  55. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FetchEntity.php +371 -0
  56. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FetchString.php +64 -0
  57. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FetchTranslatableString.php +74 -0
  58. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/FocalPoint.php +47 -0
  59. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/GatsbyBuildId.php +36 -0
  60. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/GatsbyExtractId.php +28 -0
  61. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/GatsbyExtractLangcode.php +28 -0
  62. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/ImageProps.php +149 -0
  63. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/ListEntities.php +88 -0
  64. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/ListStrings.php +87 -0
  65. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/StringId.php +37 -0
  66. package/drupal/silverback_gatsby/src/Plugin/GraphQL/DataProducer/StringTranslations.php +94 -0
  67. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/EntityFetch.php +51 -0
  68. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/EntityTranslationsWithDefault.php +30 -0
  69. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/FocalPoint.php +27 -0
  70. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/ImageProps.php +27 -0
  71. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/MenuLangcode.php +27 -0
  72. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/MenuTranslations.php +36 -0
  73. package/drupal/silverback_gatsby/src/Plugin/GraphQL/Directive/SilverbackGatsbyEntityId.php +39 -0
  74. package/drupal/silverback_gatsby/src/Plugin/GraphQL/SchemaExtension/SilverbackGatsbySchemaExtension.php +384 -0
  75. package/drupal/silverback_gatsby/src/SilverbackGatsbyServiceProvider.php +43 -0
  76. package/drupal/silverback_gatsby/src/SilverbackGatsbySessionConfiguration.php +30 -0
  77. package/drupal/silverback_gatsby/src/SilverbackReverseProxyMiddleware.php +49 -0
  78. package/drupal/silverback_gatsby/tests/queries/create-page-fields.gql +12 -0
  79. package/drupal/silverback_gatsby/tests/queries/current-user.gql +6 -0
  80. package/drupal/silverback_gatsby/tests/queries/feed_info.gql +12 -0
  81. package/drupal/silverback_gatsby/tests/queries/load-entity.gql +5 -0
  82. package/drupal/silverback_gatsby/tests/queries/menus.gql +31 -0
  83. package/drupal/silverback_gatsby/tests/queries/multilingual-menus.gql +11 -0
  84. package/drupal/silverback_gatsby/tests/queries/revisionable-translatable.gql +15 -0
  85. package/drupal/silverback_gatsby/tests/queries/revisionable.gql +8 -0
  86. package/drupal/silverback_gatsby/tests/queries/translatable.gql +14 -0
  87. package/drupal/silverback_gatsby/tests/queries/untranslatable.gql +10 -0
  88. package/drupal/silverback_gatsby/tests/schema/.graphqlrc.json +4 -0
  89. package/drupal/silverback_gatsby/tests/schema/translatable-strings.graphql +7 -0
  90. package/drupal/silverback_gatsby/tests/src/Kernel/CurrentUserTest.php +37 -0
  91. package/drupal/silverback_gatsby/tests/src/Kernel/EntityFeedTest.php +490 -0
  92. package/drupal/silverback_gatsby/tests/src/Kernel/EntityFeedTestBase.php +178 -0
  93. package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyBuildTriggerTest.php +155 -0
  94. package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyFeedInfoTest.php +319 -0
  95. package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyUpdateHandlerTest.php +131 -0
  96. package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyUpdateTrackerTest.php +196 -0
  97. package/drupal/silverback_gatsby/tests/src/Kernel/GatsbyUpdateTriggerTest.php +177 -0
  98. package/drupal/silverback_gatsby/tests/src/Kernel/MenuFeedTest.php +192 -0
  99. package/drupal/silverback_gatsby/tests/src/Kernel/TranslatableStringFeedTest.php +210 -0
  100. package/drupal/silverback_gatsby/tests/src/Traits/NotificationCheckTrait.php +43 -0
  101. 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 {
2
+ regular: _loadPost(id: "1") {
3
+ title
4
+ path
5
+ template
6
+ }
7
+ promoted: _loadPost(id: "2") {
8
+ title
9
+ path
10
+ template
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ _currentUser {
3
+ id
4
+ name
5
+ }
6
+ }
@@ -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,5 @@
1
+ query ($input: String!) {
2
+ _loadPage(id: $input) {
3
+ title
4
+ }
5
+ }
@@ -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,11 @@
1
+ query MultilingualMenus {
2
+ noLanguageDefined: _loadMainMenu(id: "main") {
3
+ _id
4
+ }
5
+ en: _loadMainMenu(id: "main:en") {
6
+ _id
7
+ }
8
+ de: _loadMainMenu(id: "main:de") {
9
+ _id
10
+ }
11
+ }
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ query {
2
+ a: _loadPostRevision(id: "1", revision: "1") {
3
+ title
4
+ }
5
+ b: _loadPostRevision(id: "1", revision: "2") {
6
+ title
7
+ }
8
+ }
@@ -0,0 +1,14 @@
1
+ query ($id: String!) {
2
+ _loadPage(id: $id) {
3
+ title
4
+ }
5
+ _queryPages {
6
+ _id
7
+ _drupalId
8
+ _translations {
9
+ _defaultTranslation
10
+ _langcode
11
+ title
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,10 @@
1
+ query {
2
+ _loadPost(id: "1") {
3
+ title
4
+ }
5
+ _queryPosts(limit: 10, offset: 0) {
6
+ _id
7
+ _drupalId
8
+ title
9
+ }
10
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/graphql-config@5.0.3/config-schema.json",
3
+ "schema": []
4
+ }
@@ -0,0 +1,7 @@
1
+ type Query
2
+
3
+ type TranslatableString @translatableString(contextPrefix: "gatsby") {
4
+ source: String!
5
+ language: String!
6
+ translation: String
7
+ }