Browse Source

added working graphql 4 module and started materio_graphql

Bachir Soussi Chiadmi 3 years ago
parent
commit
2071a99ca2

+ 1 - 1
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",

+ 94 - 24
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,

+ 2 - 1
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

+ 16 - 0
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

+ 1 - 0
config/sync/string_translation_ui.settings.yml

@@ -0,0 +1 @@
+contexts_used: '["materio","stringTranslationUi"]'

+ 2 - 0
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'

+ 2 - 0
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'

+ 2 - 1
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'

+ 40 - 0
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
+}

+ 7 - 0
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
+}

+ 9 - 0
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

+ 40 - 0
web/modules/custom/materio_graphql/src/GraphQL/Response/MateriauResponse.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\materio_graphql\GraphQL\Response;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\graphql\GraphQL\Response\Response;
+
+/**
+ * Type of response used when an materiau is returned.
+ */
+class MateriauResponse extends Response {
+
+  /**
+   * The materiau to be served.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface|null
+   */
+  protected $materiau;
+
+  /**
+   * Sets the content.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface|null $materiau
+   *   The materiau to be served.
+   */
+  public function setMateriau(?EntityInterface $materiau): void {
+    $this->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;
+  }
+
+}

+ 98 - 0
web/modules/custom/materio_graphql/src/Plugin/GraphQL/DataProducer/CreateMateriau.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace Drupal\materio_graphql\Plugin\GraphQL\DataProducer;
+
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase;
+use Drupal\materio_graphql\GraphQL\Response\MateriauResponse;
+use Drupal\node\Entity\Node;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Creates a new materiau entity.
+ *
+ * @DataProducer(
+ *   id = "create_materiau",
+ *   name = @Translation("Create Materiau"),
+ *   description = @Translation("Creates a new materiau."),
+ *   produces = @ContextDefinition("any",
+ *     label = @Translation("Materiau")
+ *   ),
+ *   consumes = {
+ *     "data" = @ContextDefinition("any",
+ *       label = @Translation("Materiau data")
+ *     )
+ *   }
+ * )
+ */
+class CreateMateriau extends DataProducerPluginBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $currentUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->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;
+  }
+
+}

+ 16 - 0
web/modules/custom/materio_graphql/src/Plugin/GraphQL/Schema/MaterioSchema.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace Drupal\materio_graphql\Plugin\GraphQL\Schema;
+
+use Drupal\graphql\Plugin\GraphQL\Schema\ComposableSchema;
+
+/**
+ * @Schema(
+ *   id = "materio",
+ *   name = "Materio schema",
+ *   extensions = "materio",
+ * )
+ */
+class MaterioSchema extends ComposableSchema {
+
+}

+ 153 - 0
web/modules/custom/materio_graphql/src/Plugin/GraphQL/SchemaExtension/MaterioSchemaExtension.php

@@ -0,0 +1,153 @@
+<?php
+
+namespace Drupal\materio_graphql\Plugin\GraphQL\SchemaExtension;
+
+use Drupal\graphql\GraphQL\ResolverBuilder;
+use Drupal\graphql\GraphQL\ResolverRegistryInterface;
+use Drupal\graphql\GraphQL\Response\ResponseInterface;
+use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase;
+use Drupal\materio_graphql\GraphQL\Response\MaterioResponse;
+
+/**
+ * @SchemaExtension(
+ *   id = "materio_extension",
+ *   name = "Materio extension",
+ *   description = "Materio extension.",
+ *   schema = "materio"
+ * )
+ */
+class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function registerResolvers(ResolverRegistryInterface $registry) {
+    $builder = new ResolverBuilder();
+
+    $registry->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.');
+  }
+
+}

+ 42 - 0
web/modules/custom/materio_graphql/src/Wrappers/Response/MateriauResponse.php

@@ -0,0 +1,42 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\materio_graphql\Wrappers\Response;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\graphql\GraphQL\Response\Response;
+
+/**
+ * Type of response used when an materiau is returned.
+ */
+class MateriauResponse extends Response {
+
+  /**
+   * The materiau to be served.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface|null
+   */
+  protected $materiau;
+
+  /**
+   * Sets the content.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface|null $materiau
+   *   The materiau to be served.
+   */
+  public function setMateriau(?EntityInterface $materiau): void {
+    $this->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;
+  }
+
+}