Skip to content

Commit

Permalink
chore: release version 1.15.0
Browse files Browse the repository at this point in the history
  • Loading branch information
K.I.T.T committed Jan 25, 2022
1 parent 4f370bf commit e857dc8
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 31 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [1.15.0](https://github.com/AmazeeLabs/silverback-mono/compare/@-amazeelabs/silverback_gatsby@1.14.2...@-amazeelabs/silverback_gatsby@1.15.0) (2022-01-25)


### Features

* introduce new directives and rename existing ones ([c9255ca](https://github.com/AmazeeLabs/silverback-mono/commit/c9255ca6c3bdd8ad954be00013c6f2f0faae4eaf))





## [1.14.2](https://github.com/AmazeeLabs/silverback-mono/compare/@-amazeelabs/silverback_gatsby@1.14.1...@-amazeelabs/silverback_gatsby@1.14.2) (2022-01-19)


Expand Down
51 changes: 48 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,23 +89,23 @@ now.

## Automatic creation of Gatsby pages

Available using `@path` and `@template` field directives. See
Available using `@isPath` and `@isTemplate` field directives. See
[`@amazeelabs/gatsby-source-silverback`](../../../npm/@amazeelabs/gatsby-source-silverback)
plugin README for details.

## Automatic resolvers

There are directives which create GraphQL resolvers automatically.

### @property
### @resolveProperty

This field directive is a shortcut for `property_path` data producer.

For example, this schema

```graphql
type Page @entity(type: "node", bundle: "page") {
body: String @property(path: "field_body.0.processed")
body: String @resolveProperty(path: "field_body.0.processed")
}
```

Expand All @@ -119,6 +119,51 @@ $builder->produce('property_path', [
])
```

### @resolveEntityPath

Resolves the relative path to an entity. A shortcut for `entity_url`+`url_path`
data producers.

Example:

```graphql
type Page @entity(type: "node", bundle: "page") {
path: String! @resolveEntityPath
}
```

### @resolveEntityReference

Resolves the references entities. A shortcut for `entity_reference` data
producer.

Example:

<!-- prettier-ignore-start -->
```graphql
type Page @entity(type: "node", bundle: "page") {
relatedArticles: [Article]! @resolveEntityReference(field: "field_related_articles", single: false)
parentPage: Page @resolveEntityReference(field: "field_related_articles", single: true)
}
```
<!-- prettier-ignore-end -->

### @resolveEntityReferenceRevisions

Resolves the entity reference revisions fields, e.g. Paragraphs. A shortcut for
`entity_reference_revisions` data producer.

Example:

<!-- prettier-ignore-start -->
```graphql
type Page @entity(type: "node", bundle: "page") {
paragraphs: [PageParagraphs!]! @resolveEntityReferenceRevisions(field: "field_paragraphs", single: false)
singleParagraph: ParagraphText @resolveEntityReferenceRevisions(field: "field_single_paragraph", single: true)
}
```
<!-- prettier-ignore-end -->

## Menus

To expose Drupal menus to Gatsby, one can use the `@menu` directive. It takes a
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "amazeelabs/silverback_gatsby",
"type": "drupal-module",
"version": "1.14.2",
"version": "1.15.0",
"description": "Bridge module between Gatsby and Drupal.",
"homepage": "https://silverback.netlify.app",
"license": "GPL-2.0+",
Expand Down
4 changes: 4 additions & 0 deletions graphql/.graphqlconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "Silverback Gatsby Schema Extensions",
"schemaPath": "*.graphqls"
}
33 changes: 33 additions & 0 deletions graphql/silverback_gatsby.base.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,44 @@ type Feed {
templateFieldName: String
}

################################################################################
# Directives for the automatic Gatsby pages creation.
################################################################################

directive @isPath on FIELD_DEFINITION
"""
DEPRECATED, use @isPath
"""
directive @path on FIELD_DEFINITION

directive @isTemplate on FIELD_DEFINITION
"""
DEPRECATED, use @isTemplate
"""
directive @template on FIELD_DEFINITION

################################################################################
# Directives for automatic resolvers.
################################################################################

directive @resolveEntityPath on FIELD_DEFINITION

directive @resolveProperty(
path: String!
) on FIELD_DEFINITION
"""
DEPRECATED, use @resolveProperty
"""
directive @property(
path: String!
) on FIELD_DEFINITION

directive @resolveEntityReference(
field: String!
single: Boolean!
) on FIELD_DEFINITION

directive @resolveEntityReferenceRevisions(
field: String!
single: Boolean!
) on FIELD_DEFINITION
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@-amazeelabs/silverback_gatsby",
"version": "1.14.2",
"version": "1.15.0",
"main": "index.js",
"scripts": {
"version": "sync-composer-version",
Expand All @@ -16,5 +16,5 @@
"repository": "git@github.com:AmazeeLabs/silverback_gatsby.git",
"branch": "main"
},
"gitHead": "47f18d66214a736ee8d9a191163abd5245ef4bc4"
"gitHead": "d37f09b7d6e69736f853480e9f42738143a69519"
}
4 changes: 2 additions & 2 deletions src/Plugin/FeedBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ public function __construct($config, $plugin_id, $plugin_definition) {
parent::__construct($config, $plugin_id, $plugin_definition);
$this->builder = new ResolverBuilder();
$this->typeName = $config['typeName'];
$this->pathFieldName = $config['createPageFields']['path'] ?? NULL;
$this->templateFieldName = $config['createPageFields']['template'] ?? NULL;
$this->pathFieldName = $config['createPageFields']['isPath'] ?? NULL;
$this->templateFieldName = $config['createPageFields']['isTemplate'] ?? NULL;
}

/**
Expand Down
147 changes: 124 additions & 23 deletions src/Plugin/GraphQL/SchemaExtension/SilverbackGatsbySchemaExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\graphql\GraphQL\Execution\ResolveContext;
use Drupal\graphql\GraphQL\Resolver\ResolverInterface;
use Drupal\graphql\GraphQL\ResolverBuilder;
use Drupal\graphql\GraphQL\ResolverRegistry;
use Drupal\graphql\GraphQL\ResolverRegistryInterface;
Expand Down Expand Up @@ -45,13 +47,23 @@ class SilverbackGatsbySchemaExtension extends SdlSchemaExtensionPluginBase
protected array $feeds = [];

/**
* The list of fields marked with "property" directive.
* The list of fields marked with "resolve*" directives.
*
* @var array
* Keys are GraphQL paths, values are directive arguments.
* Example: ['Page.title' => ['path' => 'title.value']]
* Keys are GraphQL paths, values are directive names and arguments.
* Example:
* [
* 'Page.path' => [
* 'name' => 'resolvePath',
* 'arguments' => [],
* ],
* 'Page.title' => [
* 'name' => 'resolveProperty',
* 'arguments' => ['path' => 'title.value'],
* ]
* ]
*/
protected array $properties = [];
protected array $resolvers;

/**
* @var \Drupal\Core\Plugin\DefaultPluginManager|object|null
Expand Down Expand Up @@ -149,17 +161,11 @@ public function getFeeds(): array {
foreach ($field->directives as $fieldDirective) {

// Directives used for automatic page creation.
if (in_array($fieldDirective->name->value, ['path', 'template'], TRUE)) {
$config['createPageFields'][$fieldDirective->name->value] = $field->name->value;
if (in_array($fieldDirective->name->value, ['isPath', 'path'], TRUE)) {
$config['createPageFields']['isPath'] = $field->name->value;
}

// The @property directive.
if ($fieldDirective->name->value === 'property') {
$graphQlPath = $definition->name->value . '.' . $field->name->value;
foreach ($fieldDirective->arguments->getIterator() as $arg) {
/** @var \GraphQL\Language\AST\ArgumentNode $arg */
$this->properties[$graphQlPath][$arg->name->value] = $arg->value->value;
}
if (in_array($fieldDirective->name->value, ['isTemplate', 'template'], TRUE)) {
$config['createPageFields']['isTemplate'] = $field->name->value;
}
}
}
Expand All @@ -172,6 +178,47 @@ public function getFeeds(): array {
return $this->feeds;
}

/**
* @see SilverbackGatsbySchemaExtension::$resolvers
*/
protected function getResolveDirectives(): array {
if (isset($this->resolvers)) {
return $this->resolvers;
}
$this->resolvers = [];
foreach ($this->parentAst->definitions->getIterator() as $definition) {
if (!($definition instanceof ObjectTypeDefinitionNode)) {
continue;
}
foreach ($definition->fields as $field) {
foreach ($field->directives as $fieldDirective) {
$list = [
'resolveEntityPath',
'resolveProperty',
'property',
'resolveEntityReference',
'resolveEntityReferenceRevisions',
];
if (in_array($fieldDirective->name->value, $list, TRUE)) {
$graphQlPath = $definition->name->value . '.' . $field->name->value;
$name = $fieldDirective->name->value === 'property'
? 'resolveProperty'
: $fieldDirective->name->value;
$this->resolvers[$graphQlPath] = [
'name' => $name,
'arguments' => [],
];
foreach ($fieldDirective->arguments->getIterator() as $arg) {
/** @var \GraphQL\Language\AST\ArgumentNode $arg */
$this->resolvers[$graphQlPath]['arguments'][$arg->name->value] = $arg->value->value;
}
}
}
}
}
return $this->resolvers;
}

/**
* Build the automatic schema definition for a given Feed.
*/
Expand Down Expand Up @@ -301,15 +348,69 @@ protected function addFieldResolvers(ResolverRegistry $registry, ResolverBuilder
}
}

foreach ($this->properties as $path => $args) {
[$typeName, $fieldName] = explode('.', $path);
$registry->addFieldResolver($typeName, $fieldName, $builder->produce('property_path', [
'path' => $builder->fromValue($args['path']),
'value' => $builder->fromParent(),
'type' => $builder->callback(
fn(EntityInterface $entity) => $entity->getTypedData()->getDataDefinition()->getDataType()
),
]));
$addResolver = function(string $path, ResolverInterface $resolver) use ($registry) {
[$type, $field] = explode('.', $path);
$registry->addFieldResolver($type, $field, $resolver);
};
foreach ($this->getResolveDirectives() as $path => $definition) {
switch ($definition['name']) {

case 'resolveEntityPath':
$addResolver($path, $builder->compose(
$builder->produce('entity_url')->map('entity', $builder->fromParent()),
$builder->produce('url_path')->map('url', $builder->fromParent())
));
break;

case 'resolveProperty':
$addResolver($path, $builder->produce('property_path', [
'path' => $builder->fromValue($definition['arguments']['path']),
'value' => $builder->fromParent(),
'type' => $builder->callback(
fn(EntityInterface $entity) => $entity->getTypedData()->getDataDefinition()->getDataType()
),
]));
break;

case 'resolveEntityReference':
$resolverMultiple = $builder->defaultValue(
$builder->produce('entity_reference')
->map('entity', $builder->fromParent())
->map('language', $builder->callback(
fn(TranslatableInterface $value) => $value->language()->getId()
))
->map('field', $builder->fromValue($definition['arguments']['field'])),
$builder->fromValue([])
);
if ($definition['arguments']['single']) {
$addResolver($path, $builder->compose(
$resolverMultiple,
$builder->callback(fn(array $values) => reset($values) ?: NULL)
));
}
else {
$addResolver($path, $resolverMultiple);
}
break;

case 'resolveEntityReferenceRevisions':
$resolverMultiple = $builder->defaultValue(
$builder->produce('entity_reference_revisions')
->map('entity', $builder->fromParent())
->map('field', $builder->fromValue($definition['arguments']['field'])),
$builder->fromValue([])
);
if ($definition['arguments']['single']) {
$addResolver($path, $builder->compose(
$resolverMultiple,
$builder->callback(fn(array $values) => reset($values) ?: NULL)
));
}
else {
$addResolver($path, $resolverMultiple);
}
break;
}
}
}

Expand Down

0 comments on commit e857dc8

Please sign in to comment.