@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,139 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby;
|
|
4
|
+
|
|
5
|
+
use Drupal\Core\Menu\MenuTreeParameters;
|
|
6
|
+
use Drupal\Core\Menu\MenuTreeStorageInterface;
|
|
7
|
+
use Drupal\silverback_gatsby\Plugin\Gatsby\Feed\MenuFeed;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Decorates the menu tree storage and sends updates to Gatsby on modifications.
|
|
11
|
+
*/
|
|
12
|
+
class MenuTreeStorageDecorator implements MenuTreeStorageInterface {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @var \Drupal\Core\Menu\MenuTreeStorageInterface
|
|
16
|
+
*/
|
|
17
|
+
protected MenuTreeStorageInterface $subject;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @var \Drupal\silverback_gatsby\GatsbyUpdateHandler
|
|
21
|
+
*/
|
|
22
|
+
protected GatsbyUpdateHandler $updateHandler;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param \Drupal\Core\Menu\MenuTreeStorageInterface $subject
|
|
26
|
+
* The decorated menu tree storage service.
|
|
27
|
+
* @param \Drupal\silverback_gatsby\GatsbyUpdateHandler $updateHandler
|
|
28
|
+
* A Gatsby update handler to send events to.
|
|
29
|
+
*/
|
|
30
|
+
public function __construct(
|
|
31
|
+
MenuTreeStorageInterface $subject,
|
|
32
|
+
GatsbyUpdateHandler $updateHandler
|
|
33
|
+
) {
|
|
34
|
+
$this->subject = $subject;
|
|
35
|
+
$this->updateHandler = $updateHandler;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Send updates after updating a menu item.
|
|
40
|
+
* {@inheritDoc}
|
|
41
|
+
*/
|
|
42
|
+
public function save(array $definition) {
|
|
43
|
+
// Emit change events before save to detect if the menu item moved out of
|
|
44
|
+
// a certain level range.
|
|
45
|
+
$this->updateHandler->handle(MenuFeed::class, $definition['id']);
|
|
46
|
+
$this->subject->save($definition);
|
|
47
|
+
// Emit change events after save to update the range it is now in.
|
|
48
|
+
$this->updateHandler->handle(MenuFeed::class, $definition['id']);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Send updates before deleting a menu item.
|
|
53
|
+
* {@inheritDoc}
|
|
54
|
+
*/
|
|
55
|
+
public function delete($id) {
|
|
56
|
+
// Delete update handler has to run before the actual delete operation,
|
|
57
|
+
// because afterwards its position in the tree is lost, and it's not possible
|
|
58
|
+
// to determine which layers are affected.
|
|
59
|
+
$this->updateHandler->handle(MenuFeed::class, $id);
|
|
60
|
+
$this->subject->delete($id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ======================================================================
|
|
64
|
+
// Untouched public interface.
|
|
65
|
+
// ======================================================================
|
|
66
|
+
|
|
67
|
+
public function maxDepth() {
|
|
68
|
+
return $this->subject->maxDepth();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public function resetDefinitions() {
|
|
72
|
+
return $this->subject->resetDefinitions();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public function rebuild(array $definitions) {
|
|
76
|
+
return $this->subject->rebuild($definitions);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public function load($id) {
|
|
80
|
+
return $this->subject->load($id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public function loadMultiple(array $ids) {
|
|
84
|
+
return $this->subject->loadMultiple($ids);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public function loadByProperties(array $properties) {
|
|
88
|
+
return $this->subject->loadByProperties($properties);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public function loadByRoute(
|
|
92
|
+
$route_name,
|
|
93
|
+
array $route_parameters = [],
|
|
94
|
+
$menu_name = NULL
|
|
95
|
+
) {
|
|
96
|
+
return $this->subject->loadByRoute($route_name, $route_parameters, $menu_name);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public function loadTreeData($menu_name, MenuTreeParameters $parameters) {
|
|
100
|
+
return $this->subject->loadTreeData($menu_name, $parameters);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public function loadAllChildren($id, $max_relative_depth = NULL) {
|
|
104
|
+
return $this->subject->loadAllChildren($id, $max_relative_depth);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public function getAllChildIds($id) {
|
|
108
|
+
return $this->subject->getAllChildIds($id);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public function loadSubtreeData($id, $max_relative_depth = NULL) {
|
|
112
|
+
return $this->subject->loadSubtreeData($id, $max_relative_depth);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public function getRootPathIds($id) {
|
|
116
|
+
return $this->subject->getRootPathIds($id);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public function getExpanded($menu_name, array $parents) {
|
|
120
|
+
return $this->subject->getExpanded($menu_name, $parents);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public function getSubtreeHeight($id) {
|
|
124
|
+
return $this->subject->getSubtreeHeight($id);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public function menuNameInUse($menu_name) {
|
|
128
|
+
return $this->subject->menuNameInUse($menu_name);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public function getMenuNames() {
|
|
132
|
+
return $this->subject->getMenuNames();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public function countMenuLinks($menu_name = NULL) {
|
|
136
|
+
return $this->subject->countMenuLinks($menu_name);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby\Plugin;
|
|
4
|
+
|
|
5
|
+
use Drupal\Component\Plugin\PluginBase;
|
|
6
|
+
use Drupal\Core\Session\AccountInterface;
|
|
7
|
+
use Drupal\graphql\GraphQL\ResolverBuilder;
|
|
8
|
+
use Drupal\graphql\GraphQL\ResolverRegistryInterface;
|
|
9
|
+
use Drupal\silverback_gatsby\GatsbyUpdate;
|
|
10
|
+
use GraphQL\Language\AST\DocumentNode;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Base class for Gatsby Data feeds.
|
|
14
|
+
*/
|
|
15
|
+
abstract class FeedBase extends PluginBase implements FeedInterface {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The GraphQL type this feed generates.
|
|
19
|
+
*
|
|
20
|
+
* @var string|mixed
|
|
21
|
+
*/
|
|
22
|
+
protected string $typeName;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The name of a GraphQL field containing the URL path of a node.
|
|
26
|
+
*
|
|
27
|
+
* @var string|null
|
|
28
|
+
*/
|
|
29
|
+
protected ?string $pathFieldName;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The name of a GraphQL field containing the template name for a node.
|
|
33
|
+
*
|
|
34
|
+
* @var string|null
|
|
35
|
+
*/
|
|
36
|
+
protected ?string $templateFieldName;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Instance of a ResolverBuilder.
|
|
40
|
+
*
|
|
41
|
+
* @var \Drupal\graphql\GraphQL\ResolverBuilder
|
|
42
|
+
*/
|
|
43
|
+
protected ResolverBuilder $builder;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* FeedBase constructor.
|
|
47
|
+
*
|
|
48
|
+
* @param $config
|
|
49
|
+
* @param $plugin_id
|
|
50
|
+
* @param $plugin_definition
|
|
51
|
+
*/
|
|
52
|
+
public function __construct($config, $plugin_id, $plugin_definition) {
|
|
53
|
+
parent::__construct($config, $plugin_id, $plugin_definition);
|
|
54
|
+
$this->builder = new ResolverBuilder();
|
|
55
|
+
$this->typeName = $config['typeName'];
|
|
56
|
+
$this->pathFieldName = $config['createPageFields']['isPath'] ?? NULL;
|
|
57
|
+
$this->templateFieldName = $config['createPageFields']['isTemplate'] ?? NULL;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* {@inheritDoc}
|
|
62
|
+
*/
|
|
63
|
+
public function getExtensionDefinition(DocumentNode $parentAst): string {
|
|
64
|
+
return '';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* {@inheritDoc}
|
|
69
|
+
*/
|
|
70
|
+
public function addExtensionResolvers(
|
|
71
|
+
ResolverRegistryInterface $registry,
|
|
72
|
+
ResolverBuilder $builder
|
|
73
|
+
): void {}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
public function getTypeName() : string {
|
|
77
|
+
return $this->typeName;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public function getSingleFieldName(): string {
|
|
81
|
+
return '_load' . $this->typeName;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public function getListFieldName(): string {
|
|
85
|
+
return '_query' . $this->typeName . 's';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public function info(): array {
|
|
89
|
+
return [
|
|
90
|
+
'typeName' => $this->getTypeName(),
|
|
91
|
+
'translatable' => $this->isTranslatable(),
|
|
92
|
+
'singleFieldName' => $this->getSingleFieldName(),
|
|
93
|
+
'listFieldName' => $this->getListFieldName(),
|
|
94
|
+
'pathFieldName' => $this->pathFieldName,
|
|
95
|
+
'templateFieldName' => $this->templateFieldName,
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Investigate the context of an update event and return its id if
|
|
101
|
+
* applicable.
|
|
102
|
+
*
|
|
103
|
+
* @param mixed $context
|
|
104
|
+
* @param \Drupal\Core\Session\AccountInterface|null $account
|
|
105
|
+
*
|
|
106
|
+
* @return string[]
|
|
107
|
+
* A list of string id's to update.
|
|
108
|
+
*/
|
|
109
|
+
abstract function getUpdateIds($context, ?AccountInterface $account): array;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* {@inheritDoc}
|
|
113
|
+
*/
|
|
114
|
+
public function investigateUpdate($context, ?AccountInterface $account) : array {
|
|
115
|
+
return array_map(
|
|
116
|
+
fn ($id) => new GatsbyUpdate($this->getTypeName(), $id),
|
|
117
|
+
$this->getUpdateIds($context, $account)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby\Plugin;
|
|
4
|
+
|
|
5
|
+
use Drupal\Core\Session\AccountInterface;
|
|
6
|
+
use Drupal\graphql\GraphQL\Resolver\ResolverInterface;
|
|
7
|
+
use Drupal\graphql\GraphQL\ResolverBuilder;
|
|
8
|
+
use Drupal\graphql\GraphQL\ResolverRegistryInterface;
|
|
9
|
+
use GraphQL\Language\AST\DocumentNode;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Interface FeedInterface
|
|
13
|
+
*
|
|
14
|
+
* Describes a single data-feed that is sent to Gatsby.
|
|
15
|
+
*
|
|
16
|
+
* @package Drupal\silverback_gatsby
|
|
17
|
+
*/
|
|
18
|
+
interface FeedInterface {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Retrieve feed meta information used by the GraphQL schema.
|
|
22
|
+
*
|
|
23
|
+
* @return array
|
|
24
|
+
*/
|
|
25
|
+
public function info() : array;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Define extension schema definitions this Feed provides.
|
|
29
|
+
*
|
|
30
|
+
* @param \GraphQL\Language\AST\DocumentNode $parentAst
|
|
31
|
+
*
|
|
32
|
+
* @return string
|
|
33
|
+
*/
|
|
34
|
+
public function getExtensionDefinition(DocumentNode $parentAst) : string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Build resolvers for the defined schema definitions.
|
|
38
|
+
*
|
|
39
|
+
* @param \Drupal\graphql\GraphQL\ResolverRegistryInterface $registry
|
|
40
|
+
* @param \Drupal\graphql\GraphQL\ResolverBuilder $builder
|
|
41
|
+
*/
|
|
42
|
+
public function addExtensionResolvers(ResolverRegistryInterface $registry, ResolverBuilder $builder) : void;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Decide if a type is translatable or not.
|
|
46
|
+
*
|
|
47
|
+
* @return bool
|
|
48
|
+
*/
|
|
49
|
+
public function isTranslatable() : bool;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Investigate an arbitrary context value and produce a GatsbyUpdate if
|
|
53
|
+
* applicable.
|
|
54
|
+
*
|
|
55
|
+
* @param $context
|
|
56
|
+
* @param \Drupal\Core\Session\AccountInterface|null $account
|
|
57
|
+
*
|
|
58
|
+
* @return \Drupal\silverback_gatsby\GatsbyUpdate[]
|
|
59
|
+
*/
|
|
60
|
+
public function investigateUpdate($context, ?AccountInterface $account) : array;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the parent value's "id" attribute.
|
|
64
|
+
*
|
|
65
|
+
* @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface
|
|
66
|
+
*/
|
|
67
|
+
public function resolveId() : ResolverInterface;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolve the parent value's language association.
|
|
71
|
+
*
|
|
72
|
+
* @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface
|
|
73
|
+
*/
|
|
74
|
+
public function resolveLangcode() : ResolverInterface;
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Determine if the item is the default translation.
|
|
79
|
+
*
|
|
80
|
+
* @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface
|
|
81
|
+
*/
|
|
82
|
+
public function resolveDefaultTranslation() : ResolverInterface;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Resolve a list of all available translations.
|
|
86
|
+
*
|
|
87
|
+
* @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface
|
|
88
|
+
*/
|
|
89
|
+
public function resolveTranslations() : ResolverInterface;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Resolve a paginated list of all items of this type.
|
|
93
|
+
*
|
|
94
|
+
* @param \Drupal\graphql\GraphQL\Resolver\ResolverInterface $limit
|
|
95
|
+
* @param \Drupal\graphql\GraphQL\Resolver\ResolverInterface $offset
|
|
96
|
+
*
|
|
97
|
+
* @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface
|
|
98
|
+
*/
|
|
99
|
+
public function resolveItems(ResolverInterface $limit, ResolverInterface $offset) : ResolverInterface;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Load a single item by ID.
|
|
103
|
+
*
|
|
104
|
+
* @param \Drupal\graphql\GraphQL\Resolver\ResolverInterface $id
|
|
105
|
+
* @param \Drupal\graphql\GraphQL\Resolver\ResolverInterface|null $langcode
|
|
106
|
+
*
|
|
107
|
+
* @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface
|
|
108
|
+
*/
|
|
109
|
+
public function resolveItem(ResolverInterface $id, ?ResolverInterface $langcode = null) : ResolverInterface;
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Retrieve the GraphQL type name this feed emits.
|
|
114
|
+
*
|
|
115
|
+
* @return string
|
|
116
|
+
*/
|
|
117
|
+
public function getTypeName() : string;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Retrieve the field name to load a single item.
|
|
121
|
+
*
|
|
122
|
+
* @return string
|
|
123
|
+
*/
|
|
124
|
+
public function getSingleFieldName() : string;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Retrieve the field name to fetch multiple items via pagination.
|
|
128
|
+
*
|
|
129
|
+
* @return string
|
|
130
|
+
*/
|
|
131
|
+
public function getListFieldName() : string;
|
|
132
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby\Plugin;
|
|
4
|
+
|
|
5
|
+
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
|
|
6
|
+
use Drupal\Core\Plugin\DefaultPluginManager;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Class FeedPluginManager
|
|
10
|
+
*
|
|
11
|
+
* @package Drupal\silverback_gatsby\Plugin
|
|
12
|
+
*/
|
|
13
|
+
class FeedPluginManager extends DefaultPluginManager {
|
|
14
|
+
|
|
15
|
+
protected function findDefinitions() {
|
|
16
|
+
$definitions = parent::findDefinitions();
|
|
17
|
+
|
|
18
|
+
// Attach the directive definition for each feed plugin so it is available
|
|
19
|
+
// along with the plugin definition.
|
|
20
|
+
foreach ($definitions as $id => $def) {
|
|
21
|
+
$module = \Drupal::moduleHandler()->getModule($def['provider']);
|
|
22
|
+
$path = 'graphql/' . $id . '.directive.graphqls';
|
|
23
|
+
$file = $module->getPath() . '/' . $path;
|
|
24
|
+
|
|
25
|
+
if (!file_exists($file)) {
|
|
26
|
+
throw new InvalidPluginDefinitionException(
|
|
27
|
+
$id,
|
|
28
|
+
sprintf('The module "%s" needs to have a directive definition "%s" in its folder for "%s" to be valid.',
|
|
29
|
+
$module->getName(), $path, $id));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
$definitions[$id]['directive'] = file_get_contents($file);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return $definitions;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Drupal\silverback_gatsby\Plugin\Gatsby\Feed;
|
|
4
|
+
|
|
5
|
+
use Drupal\content_translation\ContentTranslationManagerInterface;
|
|
6
|
+
use Drupal\Core\Entity\EntityInterface;
|
|
7
|
+
use Drupal\Core\Entity\TranslatableInterface;
|
|
8
|
+
use Drupal\Core\Language\LanguageInterface;
|
|
9
|
+
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
|
10
|
+
use Drupal\Core\Session\AccountInterface;
|
|
11
|
+
use Drupal\graphql\GraphQL\Resolver\ResolverInterface;
|
|
12
|
+
use Drupal\graphql\GraphQL\ResolverBuilder;
|
|
13
|
+
use Drupal\graphql\GraphQL\ResolverRegistryInterface;
|
|
14
|
+
use Drupal\node\Entity\Node;
|
|
15
|
+
use Drupal\path_alias\AliasManagerInterface;
|
|
16
|
+
use Drupal\path_alias\Entity\PathAlias;
|
|
17
|
+
use Drupal\silverback_gatsby\Plugin\FeedBase;
|
|
18
|
+
use Drupal\silverback_gatsby\Plugin\GraphQL\DataProducer\GatsbyBuildId;
|
|
19
|
+
use GraphQL\Language\AST\DocumentNode;
|
|
20
|
+
use Symfony\Component\DependencyInjection\ContainerInterface;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Feed plugin that creates Gatsby feeds based on Drupal entities.
|
|
24
|
+
*
|
|
25
|
+
* @GatsbyFeed(
|
|
26
|
+
* id = "entity"
|
|
27
|
+
* )
|
|
28
|
+
*/
|
|
29
|
+
class EntityFeed extends FeedBase implements ContainerFactoryPluginInterface {
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The target entity type.
|
|
33
|
+
*
|
|
34
|
+
* @var string
|
|
35
|
+
*/
|
|
36
|
+
protected string $type;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The target entity bundle.
|
|
40
|
+
*
|
|
41
|
+
* @var string|null
|
|
42
|
+
*/
|
|
43
|
+
protected ?string $bundle;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Indicates if Drupal access restrictions should be respected.
|
|
47
|
+
*
|
|
48
|
+
* Defaults to true.
|
|
49
|
+
*
|
|
50
|
+
* @var bool
|
|
51
|
+
*/
|
|
52
|
+
protected bool $access;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @var \Drupal\content_translation\ContentTranslationManagerInterface|null
|
|
56
|
+
*/
|
|
57
|
+
protected ?ContentTranslationManagerInterface $contentTranslationManager;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The path alias manager.
|
|
61
|
+
*
|
|
62
|
+
* @var \Drupal\path_alias\AliasManagerInterface
|
|
63
|
+
*/
|
|
64
|
+
protected $pathAliasManager;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* {@inheritDoc}
|
|
68
|
+
*/
|
|
69
|
+
public static function create(
|
|
70
|
+
ContainerInterface $container,
|
|
71
|
+
array $configuration,
|
|
72
|
+
$plugin_id,
|
|
73
|
+
$plugin_definition
|
|
74
|
+
) {
|
|
75
|
+
return new static(
|
|
76
|
+
$configuration,
|
|
77
|
+
$plugin_id,
|
|
78
|
+
$plugin_definition,
|
|
79
|
+
$container->has('content_translation.manager') ? $container->get('content_translation.manager') : NULL,
|
|
80
|
+
$container->get('path_alias.manager')
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public function __construct(
|
|
85
|
+
$config,
|
|
86
|
+
$plugin_id,
|
|
87
|
+
$plugin_definition,
|
|
88
|
+
?ContentTranslationManagerInterface $contentTranslationManager,
|
|
89
|
+
AliasManagerInterface $path_alias_manager
|
|
90
|
+
) {
|
|
91
|
+
$this->type = $config['type'];
|
|
92
|
+
$this->bundle = $config['bundle'] ?? NULL;
|
|
93
|
+
$this->access = $config['access'] ?? TRUE;
|
|
94
|
+
$this->contentTranslationManager = $contentTranslationManager;
|
|
95
|
+
$this->pathAliasManager = $path_alias_manager;
|
|
96
|
+
|
|
97
|
+
parent::__construct(
|
|
98
|
+
$config,
|
|
99
|
+
$plugin_id,
|
|
100
|
+
$plugin_definition
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* {@inheritDoc}
|
|
106
|
+
*/
|
|
107
|
+
public function isTranslatable(): bool {
|
|
108
|
+
return $this->contentTranslationManager &&
|
|
109
|
+
$this->contentTranslationManager->isEnabled($this->type, $this->bundle);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* {@inheritDoc}
|
|
114
|
+
*/
|
|
115
|
+
public function getUpdateIds($context, ?AccountInterface $account) : array {
|
|
116
|
+
|
|
117
|
+
// Special case for path alias.
|
|
118
|
+
if ($context instanceof PathAlias) {
|
|
119
|
+
$path = $this->pathAliasManager->getPathByAlias($context->alias->value);
|
|
120
|
+
if (preg_match('/node\/(\d+)/', $path, $matches)) {
|
|
121
|
+
$node = isset($matches[1]) ? Node::load($matches[1]) : NULL;
|
|
122
|
+
if ($node) {
|
|
123
|
+
// See SLB-281 for details.
|
|
124
|
+
$context = $node;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (
|
|
130
|
+
$context instanceof EntityInterface
|
|
131
|
+
&& $context->getEntityTypeId() === $this->type
|
|
132
|
+
&& ($this->bundle !== NULL && $context->bundle() === $this->bundle)
|
|
133
|
+
&& (!$account || $context->access('view', $account))
|
|
134
|
+
) {
|
|
135
|
+
if ($this->isTranslatable() && $context instanceof TranslatableInterface) {
|
|
136
|
+
return array_map(function (LanguageInterface $lang) use ($context) {
|
|
137
|
+
$translation = $context->getTranslation($lang->getId());
|
|
138
|
+
return GatsbyBuildId::build($context->uuid(), $translation->language()->getId());
|
|
139
|
+
}, $context->getTranslationLanguages());
|
|
140
|
+
}
|
|
141
|
+
return [$context->uuid()];
|
|
142
|
+
}
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* {@inheritDoc}
|
|
148
|
+
*/
|
|
149
|
+
public function resolveItem(ResolverInterface $id, ?ResolverInterface $langcode = NULL): ResolverInterface {
|
|
150
|
+
$resolver = $this->builder->produce('fetch_entity')
|
|
151
|
+
->map('type', $this->builder->fromValue($this->type))
|
|
152
|
+
->map('bundles', $this->builder->fromValue($this->bundle === NULL ? NULL : [$this->bundle]))
|
|
153
|
+
->map('access', $this->builder->fromValue($this->access))
|
|
154
|
+
->map('id', $id);
|
|
155
|
+
if ($this->isTranslatable() && $langcode) {
|
|
156
|
+
$resolver->map('language', $langcode);
|
|
157
|
+
}
|
|
158
|
+
return $resolver;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* {@inheritDoc}
|
|
163
|
+
*/
|
|
164
|
+
public function resolveItems(ResolverInterface $limit, ResolverInterface $offset): ResolverInterface {
|
|
165
|
+
return $this->builder->produce('list_entities')
|
|
166
|
+
->map('type', $this->builder->fromValue($this->type))
|
|
167
|
+
->map('bundle', $this->builder->fromValue($this->bundle))
|
|
168
|
+
->map('access', $this->builder->fromValue($this->access))
|
|
169
|
+
->map('offset', $this->builder->defaultValue(
|
|
170
|
+
$this->builder->fromArgument('offset'),
|
|
171
|
+
$this->builder->fromValue(0)
|
|
172
|
+
))
|
|
173
|
+
->map('limit', $this->builder->defaultValue(
|
|
174
|
+
$this->builder->fromArgument('limit'),
|
|
175
|
+
$this->builder->fromValue(10),
|
|
176
|
+
));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* {@inheritDoc}
|
|
181
|
+
*/
|
|
182
|
+
public function resolveId(): ResolverInterface {
|
|
183
|
+
return $this->builder->produce('entity_uuid')
|
|
184
|
+
->map('entity', $this->builder->fromParent());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* {@inheritDoc}
|
|
189
|
+
*/
|
|
190
|
+
public function resolveLangcode(): ResolverInterface {
|
|
191
|
+
return $this->builder->callback(
|
|
192
|
+
fn(TranslatableInterface $value) => $value->language()->getId()
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* {@inheritDoc}
|
|
198
|
+
*/
|
|
199
|
+
public function resolveDefaultTranslation(): ResolverInterface {
|
|
200
|
+
return $this->builder->callback(
|
|
201
|
+
fn(TranslatableInterface $value) => $value->isDefaultTranslation()
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* {@inheritDoc}
|
|
207
|
+
*/
|
|
208
|
+
public function resolveTranslations(): ResolverInterface {
|
|
209
|
+
return $this->builder->defaultValue(
|
|
210
|
+
$this->builder->compose(
|
|
211
|
+
$this->builder->produce('entity_translations')->map('entity', $this->builder->fromParent()),
|
|
212
|
+
// entity_translations returns nulls for inaccessible translations. This
|
|
213
|
+
// does not match our schema. Filter nulls out.
|
|
214
|
+
$this->builder->callback(fn ($entities) => $entities ? array_filter($entities) : NULL)
|
|
215
|
+
),
|
|
216
|
+
$this->builder->callback(fn ($value) => [$value])
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
*
|
|
222
|
+
*/
|
|
223
|
+
public function getExtensionDefinition(DocumentNode $parentAst): string {
|
|
224
|
+
$type = $this->typeName;
|
|
225
|
+
return "\nextend type Query { _load{$type}Revision(id: String!, revision: String!) : $type @deprecated }";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
*
|
|
230
|
+
*/
|
|
231
|
+
public function addExtensionResolvers(
|
|
232
|
+
ResolverRegistryInterface $registry,
|
|
233
|
+
ResolverBuilder $builder
|
|
234
|
+
): void {
|
|
235
|
+
$type = $this->typeName;
|
|
236
|
+
$idResolver = $this->isTranslatable()
|
|
237
|
+
? $builder->produce('gatsby_extract_id')->map('id', $builder->fromArgument('id'))
|
|
238
|
+
: $builder->fromArgument('id');
|
|
239
|
+
$langResolver = $this->isTranslatable()
|
|
240
|
+
? $builder->produce('gatsby_extract_langcode')->map('id', $builder->fromArgument('id'))
|
|
241
|
+
: $builder->fromValue(NULL);
|
|
242
|
+
$resolver = $this->builder->produce('fetch_entity')
|
|
243
|
+
->map('type', $this->builder->fromValue($this->type))
|
|
244
|
+
->map('bundles', $this->builder->fromValue($this->bundle === NULL ? NULL : [$this->bundle]))
|
|
245
|
+
->map('access', $this->builder->fromValue($this->access))
|
|
246
|
+
->map('id', $idResolver)
|
|
247
|
+
->map('language', $langResolver)
|
|
248
|
+
->map('revision_id', $builder->fromArgument('revision'));
|
|
249
|
+
$registry->addFieldResolver("Query", "_load{$type}Revision", $resolver);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
}
|