From 2071a99ca228434cf31260a848cb5c07d6df12a4 Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Wed, 9 Dec 2020 22:55:16 +0100 Subject: [PATCH] added working graphql 4 module and started materio_graphql --- composer.json | 2 +- composer.lock | 118 +++++++++++--- config/sync/core.extension.yml | 3 +- .../sync/graphql.graphql_servers.materio.yml | 16 ++ .../sync/string_translation_ui.settings.yml | 1 + config/sync/user.role.anonymous.yml | 2 + config/sync/user.role.authenticated.yml | 2 + config/sync/user.role.unverified.yml | 3 +- .../graphql/materio_extension.base.graphqls | 40 +++++ .../materio_extension.extension.graphqls | 7 + .../materio_graphql/materio_graphql.info.yml | 9 ++ .../src/GraphQL/Response/MateriauResponse.php | 40 +++++ .../GraphQL/DataProducer/CreateMateriau.php | 98 +++++++++++ .../Plugin/GraphQL/Schema/MaterioSchema.php | 16 ++ .../MaterioSchemaExtension.php | 153 ++++++++++++++++++ .../Wrappers/Response/MateriauResponse.php | 42 +++++ 16 files changed, 525 insertions(+), 27 deletions(-) create mode 100644 config/sync/graphql.graphql_servers.materio.yml create mode 100644 config/sync/string_translation_ui.settings.yml create mode 100644 web/modules/custom/materio_graphql/graphql/materio_extension.base.graphqls create mode 100644 web/modules/custom/materio_graphql/graphql/materio_extension.extension.graphqls create mode 100644 web/modules/custom/materio_graphql/materio_graphql.info.yml create mode 100644 web/modules/custom/materio_graphql/src/GraphQL/Response/MateriauResponse.php create mode 100644 web/modules/custom/materio_graphql/src/Plugin/GraphQL/DataProducer/CreateMateriau.php create mode 100644 web/modules/custom/materio_graphql/src/Plugin/GraphQL/Schema/MaterioSchema.php create mode 100644 web/modules/custom/materio_graphql/src/Plugin/GraphQL/SchemaExtension/MaterioSchemaExtension.php create mode 100644 web/modules/custom/materio_graphql/src/Wrappers/Response/MateriauResponse.php diff --git a/composer.json b/composer.json index dbcfb44..1bffb70 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "drupal/field_permissions": "^1.0", "drupal/flag_lists": "^4.0@beta", "drupal/genpass": "^1.x-dev", - "drupal/graphql": "^3.1", + "drupal/graphql": "4.x-dev@dev", "drupal/image_delta_formatter": "^1.x-dev", "drupal/image_effects": "3.x-dev@dev", "drupal/jsonapi_extras": "^3.7", diff --git a/composer.lock b/composer.lock index fd8792b..d7daf66 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4de458a514e6c8847c1a5d2ca4c0187d", + "content-hash": "d537c65dd030c043b106fe27f25a754a", "packages": [ { "name": "alchemy/zippy", @@ -7211,30 +7211,32 @@ }, { "name": "drupal/graphql", - "version": "3.1.0", + "version": "dev-4.x", "source": { "type": "git", "url": "https://git.drupalcode.org/project/graphql.git", - "reference": "8.x-3.1" - }, - "dist": { - "type": "zip", - "url": "https://ftp.drupal.org/files/projects/graphql-8.x-3.1.zip", - "reference": "8.x-3.1", - "shasum": "088430befbf13f2c8dadf1d9d14d01487e6f52bc" + "reference": "47bd0ddafc2bc6f0177ff0b3e75d64890610f086" }, "require": { - "drupal/core": "^8.8 || ^9", - "webonyx/graphql-php": "^0.12.5" + "drupal/core": "^8 || ^9", + "drupal/typed_data": "*", + "php": ">=7.2", + "webonyx/graphql-php": "^14.3.0" + }, + "require-dev": { + "drupal/node-node": "*" }, "type": "drupal-module", "extra": { + "branch-alias": { + "dev-4.x": "4.x-dev" + }, "drupal": { - "version": "8.x-3.1", - "datestamp": "1603962169", + "version": "8.x-4.0-beta3+12-dev", + "datestamp": "1606548247", "security-coverage": { - "status": "covered", - "message": "Covered by Drupal's security advisory policy" + "status": "not-covered", + "message": "Dev releases are not covered by Drupal security advisories." } } }, @@ -7264,7 +7266,8 @@ "homepage": "http://drupal.org/project/graphql", "support": { "source": "https://git.drupalcode.org/project/graphql" - } + }, + "time": "2020-12-05T14:12:52+00:00" }, { "name": "drupal/honeypot", @@ -11244,6 +11247,55 @@ }, "time": "2020-09-06T12:45:51+00:00" }, + { + "name": "drupal/typed_data", + "version": "1.0.0-alpha5", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/typed_data.git", + "reference": "8.x-1.0-alpha5" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/typed_data-8.x-1.0-alpha5.zip", + "reference": "8.x-1.0-alpha5", + "shasum": "44cfaf8f6d6bc0b876e88a8b9d473799818d395f" + }, + "require": { + "drupal/core": "^8.7.7 || ^9" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "8.x-1.0-alpha5", + "datestamp": "1591397037", + "security-coverage": { + "status": "not-covered", + "message": "Alpha releases are not covered by Drupal security advisories." + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "TR", + "homepage": "https://www.drupal.org/user/202830" + }, + { + "name": "fago", + "homepage": "https://www.drupal.org/user/16747" + } + ], + "description": "Extends the core Typed Data API with new APIs and features.", + "homepage": "https://www.drupal.org/project/typed_data", + "support": { + "source": "https://git.drupalcode.org/project/typed_data", + "issues": "https://www.drupal.org/project/issues/typed_data" + } + }, { "name": "drupal/ultimate_cron", "version": "dev-2.x", @@ -17636,26 +17688,37 @@ }, { "name": "webonyx/graphql-php", - "version": "v0.12.6", + "version": "v14.4.0", "source": { "type": "git", "url": "https://github.com/webonyx/graphql-php.git", - "reference": "4c545e5ec4fc37f6eb36c19f5a0e7feaf5979c95" + "reference": "aab3d49181467db064b41429cde117a7589625fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/4c545e5ec4fc37f6eb36c19f5a0e7feaf5979c95", - "reference": "4c545e5ec4fc37f6eb36c19f5a0e7feaf5979c95", + "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/aab3d49181467db064b41429cde117a7589625fc", + "reference": "aab3d49181467db064b41429cde117a7589625fc", "shasum": "" }, "require": { + "ext-json": "*", "ext-mbstring": "*", - "php": ">=5.6" + "php": "^7.1||^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8", + "amphp/amp": "^2.3", + "doctrine/coding-standard": "^6.0", + "nyholm/psr7": "^1.2", + "phpbench/phpbench": "^0.16.10", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "0.12.32", + "phpstan/phpstan-phpunit": "0.12.11", + "phpstan/phpstan-strict-rules": "0.12.2", + "phpunit/phpunit": "^7.2|^8.5", "psr/http-message": "^1.0", - "react/promise": "2.*" + "react/promise": "2.*", + "simpod/php-coveralls-mirror": "^3.0", + "squizlabs/php_codesniffer": "3.5.4" }, "suggest": { "psr/http-message": "To use standard GraphQL server", @@ -17677,7 +17740,13 @@ "api", "graphql" ], - "time": "2018-09-02T14:59:54+00:00" + "funding": [ + { + "url": "https://opencollective.com/webonyx-graphql-php", + "type": "open_collective" + } + ], + "time": "2020-12-03T16:05:21+00:00" }, { "name": "wikimedia/composer-merge-plugin", @@ -17792,6 +17861,7 @@ "drupal/content_sync": 20, "drupal/flag_lists": 10, "drupal/genpass": 20, + "drupal/graphql": 20, "drupal/image_delta_formatter": 20, "drupal/image_effects": 20, "drupal/jsonrpc": 20, diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index c59b4f0..df83a4c 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -83,7 +83,6 @@ module: flag_lists: 0 genpass: 0 graphql: 0 - graphql_core: 0 help: 0 honeypot: 0 image: 0 @@ -110,6 +109,7 @@ module: mailsystem: 0 materio_decoupled: 0 materio_flag: 0 + materio_graphql: 0 materio_home: 0 materio_jsonapi: 0 materio_migrate: 0 @@ -172,6 +172,7 @@ module: toolbar: 0 toolbar_themes: 0 translation_views: 0 + typed_data: 0 ultimate_cron: 0 update: 0 url_to_video_filter: 0 diff --git a/config/sync/graphql.graphql_servers.materio.yml b/config/sync/graphql.graphql_servers.materio.yml new file mode 100644 index 0000000..8400ddf --- /dev/null +++ b/config/sync/graphql.graphql_servers.materio.yml @@ -0,0 +1,16 @@ +uuid: 459392ea-9948-4df3-bf5d-64905bafea0d +langcode: en +status: true +dependencies: { } +name: materio +label: materio +schema: materio +schema_configuration: + materio: + extensions: + materio_extension: materio_extension +persisted_queries_settings: { } +endpoint: /mgq +debug_flag: 0 +caching: false +batching: false diff --git a/config/sync/string_translation_ui.settings.yml b/config/sync/string_translation_ui.settings.yml new file mode 100644 index 0000000..d75a434 --- /dev/null +++ b/config/sync/string_translation_ui.settings.yml @@ -0,0 +1 @@ +contexts_used: '["materio","stringTranslationUi"]' diff --git a/config/sync/user.role.anonymous.yml b/config/sync/user.role.anonymous.yml index 1d3df44..e2b68c7 100644 --- a/config/sync/user.role.anonymous.yml +++ b/config/sync/user.role.anonymous.yml @@ -21,6 +21,8 @@ permissions: - 'create generique workflow_transition' - 'create migration workflow_transition' - 'create workflow workflow_transition' + - 'execute materio arbitrary graphql requests' + - 'execute materio persisted graphql requests' - 'issue subrequests' - 'restful get config_rest_resource' - 'restful post user_registration' diff --git a/config/sync/user.role.authenticated.yml b/config/sync/user.role.authenticated.yml index 3e8b2c6..d176038 100644 --- a/config/sync/user.role.authenticated.yml +++ b/config/sync/user.role.authenticated.yml @@ -27,6 +27,8 @@ permissions: - 'edit own chutier entities' - 'edit own composition entities' - 'edit own fil entities' + - 'execute materio arbitrary graphql requests' + - 'execute materio persisted graphql requests' - 'issue subrequests' - 'manage own commerce_payment_method' - 'materio_jsonapi ownroles' diff --git a/config/sync/user.role.unverified.yml b/config/sync/user.role.unverified.yml index f2ef8df..f2f75d5 100644 --- a/config/sync/user.role.unverified.yml +++ b/config/sync/user.role.unverified.yml @@ -6,4 +6,5 @@ id: unverified label: Unverified weight: -10 is_admin: null -permissions: { } +permissions: + - 'execute materio persisted graphql requests' diff --git a/web/modules/custom/materio_graphql/graphql/materio_extension.base.graphqls b/web/modules/custom/materio_graphql/graphql/materio_extension.base.graphqls new file mode 100644 index 0000000..5196dee --- /dev/null +++ b/web/modules/custom/materio_graphql/graphql/materio_extension.base.graphqls @@ -0,0 +1,40 @@ +type Mutation + +scalar Violation + +type Materiau { + id: Int! + uuid: String! + title: String! + author: String + memo: String + linked_materials: [Materiau] + images: [Image] +} + +type MateriauResponse implements Response { + errors: [Violation] + materiau: Materiau +} + +interface Response { + errors: [Violation] +} + +input MateriauInput { + title: String! + description: String +} + +type Image { + id: Int! + url: String! + alt: String + style_minicard: ImageStyle +} + +type ImageStyle { + width: Int + height: Int + url: String +} diff --git a/web/modules/custom/materio_graphql/graphql/materio_extension.extension.graphqls b/web/modules/custom/materio_graphql/graphql/materio_extension.extension.graphqls new file mode 100644 index 0000000..abf06af --- /dev/null +++ b/web/modules/custom/materio_graphql/graphql/materio_extension.extension.graphqls @@ -0,0 +1,7 @@ +extend type Query { + materiau(id: Int!): Materiau +} + +extend type Mutation { + createMateriau(data: MateriauInput): MateriauResponse +} diff --git a/web/modules/custom/materio_graphql/materio_graphql.info.yml b/web/modules/custom/materio_graphql/materio_graphql.info.yml new file mode 100644 index 0000000..ca9987b --- /dev/null +++ b/web/modules/custom/materio_graphql/materio_graphql.info.yml @@ -0,0 +1,9 @@ +name: Materio GraphQL +type: module +description: 'Materio GraphQL schema.' +package: Materio +core: 8.x +dependencies: + - graphql:graphql + - node:node +core_version_requirement: ^8 || ^9 diff --git a/web/modules/custom/materio_graphql/src/GraphQL/Response/MateriauResponse.php b/web/modules/custom/materio_graphql/src/GraphQL/Response/MateriauResponse.php new file mode 100644 index 0000000..b9fe93c --- /dev/null +++ b/web/modules/custom/materio_graphql/src/GraphQL/Response/MateriauResponse.php @@ -0,0 +1,40 @@ +materiau = $materiau; + } + + /** + * Gets the materiau to be served. + * + * @return \Drupal\Core\Entity\EntityInterface|null + * The materiau to be served. + */ + public function materiau(): ?EntityInterface { + return $this->materiau; + } + +} diff --git a/web/modules/custom/materio_graphql/src/Plugin/GraphQL/DataProducer/CreateMateriau.php b/web/modules/custom/materio_graphql/src/Plugin/GraphQL/DataProducer/CreateMateriau.php new file mode 100644 index 0000000..7f7b582 --- /dev/null +++ b/web/modules/custom/materio_graphql/src/Plugin/GraphQL/DataProducer/CreateMateriau.php @@ -0,0 +1,98 @@ +get('current_user') + ); + } + + /** + * CreateMateriau constructor. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param array $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Session\AccountInterface $current_user + * The current user. + */ + public function __construct(array $configuration, string $plugin_id, array $plugin_definition, AccountInterface $current_user) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->currentUser = $current_user; + } + + /** + * Creates an materiau. + * + * @param array $data + * The submitted values for the materiau. + * + * @return \Drupal\graphql_composable\GraphQL\Response\MateriauResponse + * The newly created materiau. + * + * @throws \Exception + */ + public function resolve(array $data) { + $response = new MateriauResponse(); + if ($this->currentUser->hasPermission("create materiau content")) { + $values = [ + 'type' => 'materiau', + 'title' => $data['title'], + 'body' => $data['description'], + ]; + $node = Node::create($values); + $node->save(); + $response->setMateriau($node); + } + else { + $response->addViolation( + $this->t('You do not have permissions to create materiaus.') + ); + } + return $response; + } + +} diff --git a/web/modules/custom/materio_graphql/src/Plugin/GraphQL/Schema/MaterioSchema.php b/web/modules/custom/materio_graphql/src/Plugin/GraphQL/Schema/MaterioSchema.php new file mode 100644 index 0000000..3e89ff3 --- /dev/null +++ b/web/modules/custom/materio_graphql/src/Plugin/GraphQL/Schema/MaterioSchema.php @@ -0,0 +1,16 @@ +addFieldResolver('Query', 'materiau', + $builder->produce('entity_load') + ->map('type', $builder->fromValue('node')) + ->map('bundles', $builder->fromValue(['materiau'])) + ->map('id', $builder->fromArgument('id')) + ); + + // Create materiau mutation. + $registry->addFieldResolver('Mutation', 'createMateriau', + $builder->produce('create_materiau') + ->map('data', $builder->fromArgument('data')) + ); + + $registry->addFieldResolver('MateriauResponse', 'materiau', + $builder->callback(function (MateriauResponse $response) { + return $response->materiau(); + }) + ); + + $registry->addFieldResolver('MateriauResponse', 'errors', + $builder->callback(function (MateriauResponse $response) { + return $response->getViolations(); + }) + ); + + $registry->addFieldResolver('Materiau', 'id', + $builder->produce('entity_id') + ->map('entity', $builder->fromParent()) + ); + + $registry->addFieldResolver('Materiau', 'uuid', + $builder->produce('entity_uuid') + ->map('entity', $builder->fromParent()) + ); + + $registry->addFieldResolver('Materiau', 'title', + $builder->compose( + $builder->produce('entity_label') + ->map('entity', $builder->fromParent()) + ) + ); + + $registry->addFieldResolver('Materiau', 'author', + $builder->compose( + $builder->produce('entity_owner') + ->map('entity', $builder->fromParent()), + $builder->produce('entity_label') + ->map('entity', $builder->fromParent()) + ) + ); + + // https://github.com/drupal-graphql/graphql/blob/8.x-4.x/doc/SUMMARY.md + // https://blog.chrismitchellonline.com/posts/custom_graphql_data/ + + $registry->addFieldResolver('Materiau', 'linked_materials', + $builder->compose( + $builder->produce('entity_reference') + ->map('entity', $builder->fromParent()) + ->map('field', $builder->fromValue('field_linked_materials')) + ) + ); + + $registry->addFieldResolver('Materiau', 'memo', + $builder->produce('property_path') + ->map('type', $builder->fromValue('entity:node')) + ->map('value', $builder->fromParent()) + ->map('path', $builder->fromValue('field_memo.value')) + ); + + $registry->addFieldResolver('Materiau', 'images', + $builder->produce('entity_reference') + ->map('entity', $builder->fromParent()) + ->map('field', $builder->fromValue('field_materiau_images')) + ); + + $registry->addFieldResolver('Image', 'id', + $builder->produce('entity_id') + ->map('entity', $builder->fromParent()) + ); + + $registry->addFieldResolver('Image', 'url', + $builder->produce('image_url') + ->map('entity', $builder->fromParent()) + ); + + $registry->addFieldResolver('Image', 'alt', + $builder->produce('property_path') + ->map('type', $builder->fromValue('entity:node')) + ->map('value', $builder->fromParent()) + ->map('path', $builder->fromValue('field_image.alt')) + ); + + $registry->addFieldResolver('Image', 'style_minicard', + $builder->produce('image_derivative') + ->map('entity', $builder->fromParent()) + ->map('style', $builder->fromValue('card_medium_half')) + ); + + + // Response type resolver. + $registry->addTypeResolver('Response', [ + __CLASS__, + 'resolveResponse', + ]); + } + + /** + * Resolves the response type. + * + * @param \Drupal\graphql\GraphQL\Response\ResponseInterface $response + * Response object. + * + * @return string + * Response type. + * + * @throws \Exception + * Invalid response type. + */ + public static function resolveResponse(ResponseInterface $response): string { + // Resolve content response. + if ($response instanceof MateriauResponse) { + return 'MateriauResponse'; + } + throw new \Exception('Invalid response type.'); + } + +} diff --git a/web/modules/custom/materio_graphql/src/Wrappers/Response/MateriauResponse.php b/web/modules/custom/materio_graphql/src/Wrappers/Response/MateriauResponse.php new file mode 100644 index 0000000..50f2eba --- /dev/null +++ b/web/modules/custom/materio_graphql/src/Wrappers/Response/MateriauResponse.php @@ -0,0 +1,42 @@ +materiau = $materiau; + } + + /** + * Gets the materiau to be served. + * + * @return \Drupal\Core\Entity\EntityInterface|null + * The materiau to be served. + */ + public function materiau(): ?EntityInterface { + return $this->materiau; + } + +}