From d79d5fa04cefc67e96f11621a300818947fbface Mon Sep 17 00:00:00 2001 From: Justin Levi Winter Date: Fri, 9 Feb 2018 14:32:26 -0500 Subject: [PATCH 01/16] Update CreateArticle.php --- src/Plugin/GraphQL/Mutations/CreateArticle.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Plugin/GraphQL/Mutations/CreateArticle.php b/src/Plugin/GraphQL/Mutations/CreateArticle.php index c80c320..bf3c76d 100644 --- a/src/Plugin/GraphQL/Mutations/CreateArticle.php +++ b/src/Plugin/GraphQL/Mutations/CreateArticle.php @@ -28,8 +28,8 @@ class CreateArticle extends CreateEntityBase { */ protected function extractEntityInput(array $args, ResolveInfo $info) { return [ - 'title' => $args['title'], - 'body' => $args['body'], + 'title' => $args['input']['title'], + 'body' => $args['input']['body'], ]; } From 9d9446269ea8e8d33119ca4bd0dac72fbb1f907c Mon Sep 17 00:00:00 2001 From: Justin Levi Winter Date: Fri, 9 Feb 2018 14:32:58 -0500 Subject: [PATCH 02/16] Update UpdateArticle.php --- src/Plugin/GraphQL/Mutations/UpdateArticle.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Plugin/GraphQL/Mutations/UpdateArticle.php b/src/Plugin/GraphQL/Mutations/UpdateArticle.php index cda4f33..520e4a1 100644 --- a/src/Plugin/GraphQL/Mutations/UpdateArticle.php +++ b/src/Plugin/GraphQL/Mutations/UpdateArticle.php @@ -29,8 +29,8 @@ class UpdateArticle extends UpdateEntityBase { */ protected function extractEntityInput(array $args, ResolveInfo $info) { return array_filter([ - 'title' => $args['title'], - 'body' => $args['body'], + 'title' => $args['input']['title'], + 'body' => $args['input']['body'], ]); } From c2438385b9a13293324299e72e5765071718e74a Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 09:33:56 -0500 Subject: [PATCH 03/16] graphql 3.x updates --- src/Plugin/GraphQL/InputTypes/ArticleInput.php | 0 src/Plugin/GraphQL/Mutations/CreateArticle.php | 5 +++-- src/Plugin/GraphQL/Mutations/DeleteArticle.php | 5 +++-- src/Plugin/GraphQL/Mutations/FileUpload.php | 5 +++-- src/Plugin/GraphQL/Mutations/UpdateArticle.php | 5 +++-- 5 files changed, 12 insertions(+), 8 deletions(-) mode change 100644 => 100755 src/Plugin/GraphQL/InputTypes/ArticleInput.php diff --git a/src/Plugin/GraphQL/InputTypes/ArticleInput.php b/src/Plugin/GraphQL/InputTypes/ArticleInput.php old mode 100644 new mode 100755 diff --git a/src/Plugin/GraphQL/Mutations/CreateArticle.php b/src/Plugin/GraphQL/Mutations/CreateArticle.php index bf3c76d..918aa8f 100644 --- a/src/Plugin/GraphQL/Mutations/CreateArticle.php +++ b/src/Plugin/GraphQL/Mutations/CreateArticle.php @@ -4,7 +4,8 @@ use Drupal\graphql\GraphQL\Type\InputObjectType; use Drupal\graphql_core\Plugin\GraphQL\Mutations\Entity\CreateEntityBase; -use Youshido\GraphQL\Execution\ResolveInfo; +use GraphQL\Type\Definition\ResolveInfo; +use Drupal\graphql\GraphQL\Execution\ResolveContext; /** * Simple mutation for creating a new article node. @@ -26,7 +27,7 @@ class CreateArticle extends CreateEntityBase { /** * {@inheritdoc} */ - protected function extractEntityInput(array $args, ResolveInfo $info) { + protected function extractEntityInput($value, array $args, ResolveContext $context, ResolveInfo $info) { return [ 'title' => $args['input']['title'], 'body' => $args['input']['body'], diff --git a/src/Plugin/GraphQL/Mutations/DeleteArticle.php b/src/Plugin/GraphQL/Mutations/DeleteArticle.php index 3634a1a..e7c5876 100644 --- a/src/Plugin/GraphQL/Mutations/DeleteArticle.php +++ b/src/Plugin/GraphQL/Mutations/DeleteArticle.php @@ -4,8 +4,9 @@ use Drupal\graphql_core\Plugin\GraphQL\Mutations\Entity\DeleteEntityBase; + /** - * Simple mutation for deleting an article node. + * A Simple ArticleNode mutation. * * @GraphQLMutation( * id = "delete_article", @@ -15,7 +16,7 @@ * name = "deleteArticle", * type = "EntityCrudOutput!", * arguments = { - * "id" = "String" + * "id" = "Int" * } * ) */ diff --git a/src/Plugin/GraphQL/Mutations/FileUpload.php b/src/Plugin/GraphQL/Mutations/FileUpload.php index 938de59..93ebfa2 100644 --- a/src/Plugin/GraphQL/Mutations/FileUpload.php +++ b/src/Plugin/GraphQL/Mutations/FileUpload.php @@ -12,7 +12,8 @@ use Drupal\graphql_core\GraphQL\EntityCrudOutputWrapper; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; -use Youshido\GraphQL\Execution\ResolveInfo; +use GraphQL\Type\Definition\ResolveInfo; +use Drupal\graphql\GraphQL\Execution\ResolveContext; /** * TODO: Add the whole range of file upload validations from file_save_upload(). @@ -97,7 +98,7 @@ public static function create(ContainerInterface $container, array $configuratio /** * {@inheritdoc} */ - public function resolve($value, array $args, ResolveInfo $info) { + public function resolve($value, array $args, ResolveContext $context, ResolveInfo $info) { /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */ $file = $args['file']; diff --git a/src/Plugin/GraphQL/Mutations/UpdateArticle.php b/src/Plugin/GraphQL/Mutations/UpdateArticle.php index 520e4a1..f06a9c8 100644 --- a/src/Plugin/GraphQL/Mutations/UpdateArticle.php +++ b/src/Plugin/GraphQL/Mutations/UpdateArticle.php @@ -4,7 +4,8 @@ use Drupal\graphql\GraphQL\Type\InputObjectType; use Drupal\graphql_core\Plugin\GraphQL\Mutations\Entity\UpdateEntityBase; -use Youshido\GraphQL\Execution\ResolveInfo; +use GraphQL\Type\Definition\ResolveInfo; +use Drupal\graphql\GraphQL\Execution\ResolveContext; /** * Simple mutation for updating an existing article node. @@ -27,7 +28,7 @@ class UpdateArticle extends UpdateEntityBase { /** * {@inheritdoc} */ - protected function extractEntityInput(array $args, ResolveInfo $info) { + protected function extractEntityInput($value, array $args, ResolveContext $context, ResolveInfo $info) { return array_filter([ 'title' => $args['input']['title'], 'body' => $args['input']['body'], From 78c1e4acf1df2ffe6e649ff89b5748e2084ec48e Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 09:59:26 -0500 Subject: [PATCH 04/16] Some basic documentation & composer.json --- composer.json | 13 ++++ readme.md | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 composer.json create mode 100644 readme.md diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..1432286 --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "drupal/graphql_exmaples", + "type": "drupal-module", + "description": "A GraphQL Article and File Mutation Example", + "keywords": ["Drupal"], + "license": "GPL-2.0+", + "minimum-stability": "dev", + "support": { + "issues": "https://github.com/drupal-graphql/graphql-examples", + "source": "https://github.com/drupal-graphql/graphql-examples" + }, + "require": { } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..9976f2a --- /dev/null +++ b/readme.md @@ -0,0 +1,174 @@ +# Drupal GraphQL Mutation Example + + + +CREATE ARTICLE MUTATION +```$xslt +mutation { + createArticle(input:{title: "Hey", body:"Ho"}){ + errors, + violations{ + message, + path, + code + }, + entity { + entityUuid + ...on NodeArticle { + nid + title, + body { + value + format + processed + summary + summaryProcessed + } + } + } + } +} + +``` + +RESULT + +```$xslt +{ + "data": { + "createArticle": { + "errors": [], + "violations": [], + "entity": { + "entityUuid": "f0628b9d-bb9b-452a-aeea-bfdc2000660e", + "nid": 21, + "title": "Hey", + "body": { + "value": "Ho", + "format": "null", + "processed": "

Ho

\n", + "summary": "null", + "summaryProcessed": "" + } + } + } + } +} +``` + + +--- + + +UPDATE MUTATION + +```$xslt +mutation { + updateArticle(id:"21", input:{title: "Heyo", body:"Let's go"}){ + errors, + violations{ + message, + path, + code + }, + entity { + entityUuid + ...on NodeArticle { + nid + title, + body { + value + format + processed + summary + summaryProcessed + } + } + } + } +} +``` + + +RESULT +```$xslt +{ + "data": { + "updateArticle": { + "errors": [], + "violations": [], + "entity": { + "entityUuid": "f0628b9d-bb9b-452a-aeea-bfdc2000660e", + "nid": 21, + "title": "Heyo", + "body": { + "value": "Let's go", + "format": "null", + "processed": "

Let's go

\n", + "summary": "null", + "summaryProcessed": "" + } + } + } + } +} +``` + + +--- + + +DELETE MUTATION +```$xslt +mutation { + deleteArticle(id:21){ + errors, + violations{ + message, + path, + code + }, + entity { + entityUuid + ...on NodeArticle { + nid + title, + body { + value + format + processed + summary + summaryProcessed + } + } + } + } +} + +``` + + +RESULT + +```$xslt +{ + "data": { + "deleteArticle": { + "errors": [], + "violations": [], + "entity": { + "entityUuid": "f0628b9d-bb9b-452a-aeea-bfdc2000660e", + "nid": 21, + "title": "Heyo", + "body": { + "value": "Let's go", + "format": "null", + "processed": "

Let's go

\n", + "summary": "null", + "summaryProcessed": "" + } + } + } + } +} +``` \ No newline at end of file From 17706bea990f8eec57b076595950a90834caf42e Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 14:25:18 -0500 Subject: [PATCH 05/16] WIP - Travis PHPUnit Tests --- .travis.yml | 114 ++++++++++++++++ ...tity_form_display.node.article.default.yml | 98 +++++++++++++ ...tity_view_display.node.article.default.yml | 51 +++++++ ....entity_view_display.node.article.full.yml | 52 +++++++ ...ntity_view_display.node.article.teaser.yml | 53 +++++++ .../field.field.node.article.body.yml | 24 ++++ .../field.field.node.article.field_image.yml | 40 ++++++ .../field.field.node.article.field_tags.yml | 29 ++++ .../field.storage.node.field_image.yml | 34 +++++ .../field.storage.node.field_tags.yml | 22 +++ config/optional/node.type.article.yml | 13 ++ config/optional/taxonomy.vocabulary.tags.yml | 11 ++ .../GraphQL/Mutations/CreateArticle.php | 1 - .../GraphQL/Mutations/UpdateArticle.php | 1 - tests/queries/createArticle.gql | 18 +++ tests/queries/deleteArticle.gql | 18 +++ tests/queries/updateArticle.gql | 18 +++ .../Kernel/Extension/ArticleMutationTest.php | 129 ++++++++++++++++++ .../Kernel/Framework/UploadMutationTest.php | 60 ++++++++ 19 files changed, 784 insertions(+), 2 deletions(-) create mode 100755 .travis.yml create mode 100644 config/optional/core.entity_form_display.node.article.default.yml create mode 100644 config/optional/core.entity_view_display.node.article.default.yml create mode 100644 config/optional/core.entity_view_display.node.article.full.yml create mode 100644 config/optional/core.entity_view_display.node.article.teaser.yml create mode 100644 config/optional/field.field.node.article.body.yml create mode 100644 config/optional/field.field.node.article.field_image.yml create mode 100644 config/optional/field.field.node.article.field_tags.yml create mode 100644 config/optional/field.storage.node.field_image.yml create mode 100644 config/optional/field.storage.node.field_tags.yml create mode 100644 config/optional/node.type.article.yml create mode 100644 config/optional/taxonomy.vocabulary.tags.yml create mode 100644 tests/queries/createArticle.gql create mode 100644 tests/queries/deleteArticle.gql create mode 100644 tests/queries/updateArticle.gql create mode 100644 tests/src/Kernel/Extension/ArticleMutationTest.php create mode 100644 tests/src/Kernel/Framework/UploadMutationTest.php diff --git a/.travis.yml b/.travis.yml new file mode 100755 index 0000000..08224e2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,114 @@ +language: php +sudo: false + +php: + - 7.1 + - 7 + - 5.6 + - 5.5 + +env: + global: + - DRUPAL_BUILD_DIR=$TRAVIS_BUILD_DIR/../drupal + - SIMPLETEST_DB=mysql://root:@127.0.0.1/graphql + - TRAVIS=true + matrix: + - DRUPAL_CORE=8.3.x + - DRUPAL_CORE=8.4.x + +matrix: + # Don't wait for the allowed failures to build. + fast_finish: true + include: + - php: 7.1 + env: + - DRUPAL_CORE=8.4.x + - GRAPHQL=8.x-3.x + # Only run code coverage on the latest php and drupal versions. + - WITH_PHPDBG_COVERAGE=true + allow_failures: + # Allow the code coverage report to fail. + - php: 7.1 + env: + - DRUPAL_CORE=8.4.x + - graphql=8.x-3.x + # Only run code coverage on the latest php and drupal versions. + - WITH_PHPDBG_COVERAGE=true + +mysql: + database: graphql + username: root + encoding: utf8 + +# Cache composer downloads. +cache: + directories: + - $HOME/.composer + +before_install: + # Disable xdebug. + - phpenv config-rm xdebug.ini + + # Determine the php settings file location. + - if [[ $TRAVIS_PHP_VERSION = hhvm* ]]; + then export PHPINI=/etc/hhvm/php.ini; + else export PHPINI=$HOME/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; + fi + + # PHP Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated + # and will be removed in a future version. To avoid this warning set + # 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input + # stream instead. + - if [[ "$TRAVIS_PHP_VERSION" == "5.6" ]]; + then echo always_populate_raw_post_data = -1 >> $PHPINI; + fi; + + # Disable the default memory limit. + - echo memory_limit = -1 >> $PHPINI + + # Update composer. + - composer self-update + +install: + # Create the database. + - mysql -e 'create database graphql' + + # Download Drupal 8 core from the Github mirror because it is faster. + - git clone --branch $DRUPAL_CORE --depth 1 https://github.com/drupal/drupal.git $DRUPAL_BUILD_DIR + + # Download graphql module from the Github mirror because it is faster. + - git clone --branch $GRAQHQL --depth 1 https://github.com/drupal-graphql/graphql.git $DRUPAL_BUILD_DIR/modules + + # Reference the module in the build site. + - ln -s $TRAVIS_BUILD_DIR $DRUPAL_BUILD_DIR/modules/graphql-examples + + # Copy the customized phpunit configuration file to the core directory so + # the relative paths are correct. + - cp $DRUPAL_BUILD_DIR/modules/graphql/phpunit.xml.dist $DRUPAL_BUILD_DIR/core/phpunit.xml + + # When running with phpdbg we need to replace all code occurrences that check + # for 'cli' with 'phpdbg'. Some files might be write protected, hence the + # fallback. + - if [[ "$WITH_PHPDBG_COVERAGE" == "true" ]]; + then grep -rl 'cli' $DRUPAL_BUILD_DIR/core $DRUPAL_BUILD_DIR/modules | xargs sed -i "s/'cli'/'phpdbg'/g" || true; + fi + + # Bring in the module dependencies without requiring a merge plugin. The + # require also triggers a full 'composer install'. + - composer --working-dir=$DRUPAL_BUILD_DIR require webonyx/graphql-php:^0.11.5 + +script: + # Run the unit tests using phpdbg if the environment variable is 'true'. + - if [[ "$WITH_PHPDBG_COVERAGE" == "true" ]]; + then phpdbg -qrr $DRUPAL_BUILD_DIR/vendor/bin/phpunit --configuration $DRUPAL_BUILD_DIR/core/phpunit.xml --coverage-clover $TRAVIS_BUILD_DIR/coverage.xml $TRAVIS_BUILD_DIR; + fi + + # Run the unit tests with standard php otherwise. + - if [[ "$WITH_PHPDBG_COVERAGE" != "true" ]]; + then $DRUPAL_BUILD_DIR/vendor/bin/phpunit --configuration $DRUPAL_BUILD_DIR/core/phpunit.xml $TRAVIS_BUILD_DIR; + fi + +after_success: + - if [[ "$WITH_PHPDBG_COVERAGE" == "true" ]]; + then bash <(curl -s https://codecov.io/bash); + fi \ No newline at end of file diff --git a/config/optional/core.entity_form_display.node.article.default.yml b/config/optional/core.entity_form_display.node.article.default.yml new file mode 100644 index 0000000..c8cd65d --- /dev/null +++ b/config/optional/core.entity_form_display.node.article.default.yml @@ -0,0 +1,98 @@ +uuid: c811adaa-76bb-4cae-a248-a0d9f7fb72f8 +langcode: en +status: true +dependencies: + config: + - field.field.node.article.body + - field.field.node.article.field_image + - field.field.node.article.field_tags + - image.style.thumbnail + - node.type.article + module: + - image + - path + - text +_core: + default_config_hash: 0StcaANBh8qzNkp_3-xqJlwQoLGxZeRoIwO16LG10d8 +id: node.article.default +targetEntityType: node +bundle: article +mode: default +content: + body: + type: text_textarea_with_summary + weight: 1 + region: content + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + third_party_settings: { } + created: + type: datetime_timestamp + weight: 6 + region: content + settings: { } + third_party_settings: { } + field_image: + type: image_image + weight: 3 + region: content + settings: + progress_indicator: throbber + preview_image_style: thumbnail + third_party_settings: { } + field_tags: + type: entity_reference_autocomplete_tags + weight: 2 + region: content + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + path: + type: path + weight: 9 + region: content + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 7 + region: content + third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 10 + region: content + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 8 + region: content + third_party_settings: { } + title: + type: string_textfield + weight: 0 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + region: content + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } +hidden: { } diff --git a/config/optional/core.entity_view_display.node.article.default.yml b/config/optional/core.entity_view_display.node.article.default.yml new file mode 100644 index 0000000..2028ce3 --- /dev/null +++ b/config/optional/core.entity_view_display.node.article.default.yml @@ -0,0 +1,51 @@ +uuid: 2621f24b-373d-4046-8621-d807211dc97d +langcode: en +status: true +dependencies: + config: + - field.field.node.article.body + - field.field.node.article.field_image + - field.field.node.article.field_tags + - node.type.article + - responsive_image.styles.3_2_image + module: + - responsive_image + - text + - user +_core: + default_config_hash: _L_3i_Js9-dZMLX2RRJqeryWzABKXwF4PS3Kss1kqQ0 +id: node.article.default +targetEntityType: node +bundle: article +mode: default +content: + body: + type: text_default + weight: 3 + region: content + settings: { } + third_party_settings: { } + label: hidden + field_image: + type: responsive_image + weight: 2 + region: content + settings: + responsive_image_style: 3_2_image + image_link: '' + third_party_settings: { } + label: hidden + field_tags: + type: entity_reference_label + weight: 0 + region: content + label: above + settings: + link: true + third_party_settings: { } + links: + weight: 4 + region: content + settings: { } + third_party_settings: { } +hidden: { } diff --git a/config/optional/core.entity_view_display.node.article.full.yml b/config/optional/core.entity_view_display.node.article.full.yml new file mode 100644 index 0000000..985cd1c --- /dev/null +++ b/config/optional/core.entity_view_display.node.article.full.yml @@ -0,0 +1,52 @@ +uuid: 3ddb5c20-2365-418c-9285-0e335eae728e +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.full + - field.field.node.article.body + - field.field.node.article.field_image + - field.field.node.article.field_tags + - node.type.article + - responsive_image.styles.3_2_image + module: + - responsive_image + - text + - user +_core: + default_config_hash: yVqiZUuFBTwOz9czH5sX0KFILpozm7LParHg2qjhtpU +id: node.article.full +targetEntityType: node +bundle: article +mode: full +content: + body: + type: text_default + weight: 2 + region: content + settings: { } + third_party_settings: { } + label: hidden + field_image: + type: responsive_image + weight: 1 + region: content + settings: + responsive_image_style: 3_2_image + image_link: '' + third_party_settings: { } + label: hidden + field_tags: + type: entity_reference_label + weight: 0 + region: content + label: above + settings: + link: true + third_party_settings: { } + links: + weight: 3 + region: content + settings: { } + third_party_settings: { } +hidden: { } diff --git a/config/optional/core.entity_view_display.node.article.teaser.yml b/config/optional/core.entity_view_display.node.article.teaser.yml new file mode 100644 index 0000000..e2aea26 --- /dev/null +++ b/config/optional/core.entity_view_display.node.article.teaser.yml @@ -0,0 +1,53 @@ +uuid: ea54bb73-d981-43aa-ab17-7e887c79b575 +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.article.body + - field.field.node.article.field_image + - field.field.node.article.field_tags + - node.type.article + - responsive_image.styles.3_2_image + module: + - responsive_image + - text + - user +_core: + default_config_hash: 342xrNFCgiw8mRXaCKDQGA0p8mtvEtZyQzj3DbA5F4A +id: node.article.teaser +targetEntityType: node +bundle: article +mode: teaser +content: + body: + type: text_summary_or_trimmed + weight: 0 + region: content + settings: + trim_length: 600 + third_party_settings: { } + label: hidden + field_image: + type: responsive_image + weight: -1 + region: content + settings: + responsive_image_style: 3_2_image + image_link: content + third_party_settings: { } + label: hidden + field_tags: + type: entity_reference_label + weight: 10 + region: content + settings: + link: true + third_party_settings: { } + label: above + links: + weight: 100 + region: content + settings: { } + third_party_settings: { } +hidden: { } diff --git a/config/optional/field.field.node.article.body.yml b/config/optional/field.field.node.article.body.yml new file mode 100644 index 0000000..7f0de98 --- /dev/null +++ b/config/optional/field.field.node.article.body.yml @@ -0,0 +1,24 @@ +uuid: 3f3490b0-52ab-4ff6-97ee-35730efbd0c4 +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.article + module: + - text +_core: + default_config_hash: Ay3b2hq42cpQTFB_lNu8S2ZxuVIY6-dlBsc7vLeJ-YY +id: node.article.body +field_name: body +entity_type: node +bundle: article +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true +field_type: text_with_summary diff --git a/config/optional/field.field.node.article.field_image.yml b/config/optional/field.field.node.article.field_image.yml new file mode 100644 index 0000000..b6da357 --- /dev/null +++ b/config/optional/field.field.node.article.field_image.yml @@ -0,0 +1,40 @@ +uuid: df28dc3a-5571-44af-aa93-c11a0baf890b +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_image + - node.type.article + module: + - image +_core: + default_config_hash: tgJzhA7Swh4M_gWU5FwFe5lPxPj5rebpMbvhpdNrERs +id: node.article.field_image +field_name: field_image +entity_type: node +bundle: article +label: Image +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + file_directory: '[date:custom:Y]-[date:custom:m]' + file_extensions: 'png gif jpg jpeg' + max_filesize: '' + max_resolution: '' + min_resolution: '' + alt_field: true + title_field: false + alt_field_required: true + title_field_required: false + default_image: + uuid: null + alt: '' + title: '' + width: null + height: null + handler: 'default:file' + handler_settings: { } +field_type: image diff --git a/config/optional/field.field.node.article.field_tags.yml b/config/optional/field.field.node.article.field_tags.yml new file mode 100644 index 0000000..80c0a48 --- /dev/null +++ b/config/optional/field.field.node.article.field_tags.yml @@ -0,0 +1,29 @@ +uuid: ffabf45c-045c-4805-a54d-f6439e62883c +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_tags + - node.type.article + - taxonomy.vocabulary.tags +_core: + default_config_hash: QdUgf_beeoaPiyKorFv0q1fcJpWH_uZTqe_xoVJacrw +id: node.article.field_tags +field_name: field_tags +entity_type: node +bundle: article +label: Tags +description: 'Enter a comma-separated list. For example: Amsterdam, Mexico City, "Cleveland, Ohio"' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + tags: tags + sort: + field: _none + auto_create: true +field_type: entity_reference diff --git a/config/optional/field.storage.node.field_image.yml b/config/optional/field.storage.node.field_image.yml new file mode 100644 index 0000000..9d3bb47 --- /dev/null +++ b/config/optional/field.storage.node.field_image.yml @@ -0,0 +1,34 @@ +uuid: cc2520c3-3829-49b8-b4ca-2aea88328b45 +langcode: en +status: true +dependencies: + module: + - file + - image + - node +_core: + default_config_hash: SkXIPKZYiIMMtnBmfnxk58RYfbZ8cHSw5NZPY_JByME +id: node.field_image +field_name: field_image +entity_type: node +type: image +settings: + uri_scheme: public + default_image: + uuid: null + alt: '' + title: '' + width: null + height: null + target_type: file + display_field: false + display_default: false +module: image +locked: false +cardinality: 1 +translatable: true +indexes: + target_id: + - target_id +persist_with_no_fields: false +custom_storage: false diff --git a/config/optional/field.storage.node.field_tags.yml b/config/optional/field.storage.node.field_tags.yml new file mode 100644 index 0000000..b6301dd --- /dev/null +++ b/config/optional/field.storage.node.field_tags.yml @@ -0,0 +1,22 @@ +uuid: e86da172-f349-4b99-965a-34e0a3bf38d6 +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +_core: + default_config_hash: WpOE_bs8Bs_HY2ns7n2r__de-xno0-Bxkqep5-MsHAs +id: node.field_tags +field_name: field_tags +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/optional/node.type.article.yml b/config/optional/node.type.article.yml new file mode 100644 index 0000000..de3f2fb --- /dev/null +++ b/config/optional/node.type.article.yml @@ -0,0 +1,13 @@ +uuid: 2bda1406-8136-4aad-9439-13bec16d6b1b +langcode: en +status: true +dependencies: { } +_core: + default_config_hash: AeW1SEDgb1OTQACAWGhzvMknMYAJlcZu0jljfeU3oso +name: Article +type: article +description: 'Use articles for time-sensitive content like news, press releases or blog posts.' +help: '' +new_revision: true +preview_mode: 1 +display_submitted: true diff --git a/config/optional/taxonomy.vocabulary.tags.yml b/config/optional/taxonomy.vocabulary.tags.yml new file mode 100644 index 0000000..b4b7f6d --- /dev/null +++ b/config/optional/taxonomy.vocabulary.tags.yml @@ -0,0 +1,11 @@ +uuid: f4f97885-5b25-47cf-9663-2916c6e5ae6a +langcode: en +status: true +dependencies: { } +_core: + default_config_hash: lO5ziR5dVI1PpEeHZsSOfQ-Y7NWihSDKW8-MMf6uoms +name: Tags +vid: tags +description: 'Use tags to group articles on similar topics into categories.' +hierarchy: 0 +weight: 0 diff --git a/src/Plugin/GraphQL/Mutations/CreateArticle.php b/src/Plugin/GraphQL/Mutations/CreateArticle.php index 918aa8f..e94402a 100644 --- a/src/Plugin/GraphQL/Mutations/CreateArticle.php +++ b/src/Plugin/GraphQL/Mutations/CreateArticle.php @@ -2,7 +2,6 @@ namespace Drupal\graphql_examples\Plugin\GraphQL\Mutations; -use Drupal\graphql\GraphQL\Type\InputObjectType; use Drupal\graphql_core\Plugin\GraphQL\Mutations\Entity\CreateEntityBase; use GraphQL\Type\Definition\ResolveInfo; use Drupal\graphql\GraphQL\Execution\ResolveContext; diff --git a/src/Plugin/GraphQL/Mutations/UpdateArticle.php b/src/Plugin/GraphQL/Mutations/UpdateArticle.php index f06a9c8..d71c8f9 100644 --- a/src/Plugin/GraphQL/Mutations/UpdateArticle.php +++ b/src/Plugin/GraphQL/Mutations/UpdateArticle.php @@ -2,7 +2,6 @@ namespace Drupal\graphql_examples\Plugin\GraphQL\Mutations; -use Drupal\graphql\GraphQL\Type\InputObjectType; use Drupal\graphql_core\Plugin\GraphQL\Mutations\Entity\UpdateEntityBase; use GraphQL\Type\Definition\ResolveInfo; use Drupal\graphql\GraphQL\Execution\ResolveContext; diff --git a/tests/queries/createArticle.gql b/tests/queries/createArticle.gql new file mode 100644 index 0000000..85d36dc --- /dev/null +++ b/tests/queries/createArticle.gql @@ -0,0 +1,18 @@ +mutation { + createArticle(input:{title: "Hey", body:"Ho"}){ + errors, + violations{ + message, + path, + code + }, + entity { + ...on NodeArticle { + title, + body { + value + } + } + } + } +} \ No newline at end of file diff --git a/tests/queries/deleteArticle.gql b/tests/queries/deleteArticle.gql new file mode 100644 index 0000000..856e498 --- /dev/null +++ b/tests/queries/deleteArticle.gql @@ -0,0 +1,18 @@ +mutation { + deleteArticle(id:1){ + errors, + violations{ + message, + path, + code + }, + entity { + ...on NodeArticle { + title, + body { + value + } + } + } + } +} \ No newline at end of file diff --git a/tests/queries/updateArticle.gql b/tests/queries/updateArticle.gql new file mode 100644 index 0000000..b38657d --- /dev/null +++ b/tests/queries/updateArticle.gql @@ -0,0 +1,18 @@ +mutation { + updateArticle(id:"1", input:{title: "Heyo", body:"Let's go"}){ + errors, + violations{ + message, + path, + code + }, + entity { + ...on NodeArticle { + title, + body { + value + } + } + } + } +} \ No newline at end of file diff --git a/tests/src/Kernel/Extension/ArticleMutationTest.php b/tests/src/Kernel/Extension/ArticleMutationTest.php new file mode 100644 index 0000000..f0f2c3b --- /dev/null +++ b/tests/src/Kernel/Extension/ArticleMutationTest.php @@ -0,0 +1,129 @@ +installConfig(['system', 'node', 'field', 'text', 'filter', 'file', 'image', 'taxonomy', 'graphql', 'graphql_core', 'graphql_examples']); + $this->installEntitySchema('node', 'user', 'graphql_examples'); + + $this->installEntitySchema('user'); + $this->installEntitySchema('taxonomy_vocabulary'); + $this->installEntitySchema('taxonomy_term'); + + } + + /** + * {@inheritdoc} + * + * Add the 'access content' permission to the mocked account. + */ + protected function userPermissions() { + $perms = parent::userPermissions(); + $perms[] = 'access content'; + $perms[] = 'create article content'; + $perms[] = 'delete own article content'; + $perms[] = 'edit own article content'; + $perms[] = 'execute graphql requests'; + return $perms; + } + + /** + * Test if the article is created properly. + */ + public function testCreateArticleMutation() { + + $query = $this->getQueryFromFile('createArticle.gql'); + $this->assertResults($query, [], [ + 'createArticle' => [ + 'errors' => [], + 'violations' => [], + 'entity' => [ + 'title' => 'Hey', + 'body' => [ + 'value' => 'Ho' + ] + ] + ], + ], $this->defaultMutationCacheMetaData()); + } + + + /** + * Test if the article is updated properly. + */ + public function testUpdateArticleMutation() { + + $query = $this->getQueryFromFile('updateArticle.gql'); + $this->assertResults($query, [], [ + 'updateArticle' => [ + 'errors' => [], + 'violations' => [], + 'entity' => [ + 'title' => 'Heyo', + 'body' => [ + 'value' => "Let's go" + ] + ] + ], + ], $this->defaultMutationCacheMetaData()); + } + + /** + * Test if the article is deleted properly. + */ + public function testDeleteArticleMutation() { + + $query = $this->getQueryFromFile('deleteArticle.gql'); + $this->assertResults($query, [], [ + 'deleteArticle' => [ + 'errors' => [], + 'violations' => [], + 'entity' => [ + 'title' => 'Hey', + 'body' => [ + 'value' => 'Ho' + ] + ] + ], + ], $this->defaultMutationCacheMetaData()); + } + +} diff --git a/tests/src/Kernel/Framework/UploadMutationTest.php b/tests/src/Kernel/Framework/UploadMutationTest.php new file mode 100644 index 0000000..4b99afa --- /dev/null +++ b/tests/src/Kernel/Framework/UploadMutationTest.php @@ -0,0 +1,60 @@ +mockMutation('store', [ + 'name' => 'store', + 'arguments' => ['file' => 'Upload!'], + 'type' => 'String', + ], function ($value, $args) { + /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */ + $file = $args['file']; + return $file->getClientOriginalName(); + }); + + // Create a post request with file contents. + $uploadRequest = Request::create('/graphql', 'POST', [ + 'query' => 'mutation($upload: Upload!) { store(file: $upload) }', + // The variable has to be declared null. + 'variables' => ['upload' => NULL], + // Then map the file upload name to the variable. + 'map' => [ + 'test' => ['variables.upload'], + ], + ], [], [ + 'test' => [ + 'name' => 'test.txt', + 'type' => 'text/plain', + 'size' => 42, + 'tmp_name' => $file, + 'error' => UPLOAD_ERR_OK, + ], + ]); + + $uploadRequest->headers->add(['content-type' => 'multipart/form-data']); + $response = $this->container->get('http_kernel')->handle($uploadRequest); + $result = json_decode($response->getContent()); + $this->assertEquals('test.txt', $result->data->store); + } +} From 5b1b871fc877004d1ee1e83a6bc710a79dd60723 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 14:37:36 -0500 Subject: [PATCH 06/16] removing env branch definition --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 08224e2..4a5d24f 100755 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,6 @@ matrix: - php: 7.1 env: - DRUPAL_CORE=8.4.x - - GRAPHQL=8.x-3.x # Only run code coverage on the latest php and drupal versions. - WITH_PHPDBG_COVERAGE=true allow_failures: @@ -31,7 +30,6 @@ matrix: - php: 7.1 env: - DRUPAL_CORE=8.4.x - - graphql=8.x-3.x # Only run code coverage on the latest php and drupal versions. - WITH_PHPDBG_COVERAGE=true @@ -77,7 +75,7 @@ install: - git clone --branch $DRUPAL_CORE --depth 1 https://github.com/drupal/drupal.git $DRUPAL_BUILD_DIR # Download graphql module from the Github mirror because it is faster. - - git clone --branch $GRAQHQL --depth 1 https://github.com/drupal-graphql/graphql.git $DRUPAL_BUILD_DIR/modules + - git clone --depth 1 https://github.com/drupal-graphql/graphql.git $DRUPAL_BUILD_DIR/modules # Reference the module in the build site. - ln -s $TRAVIS_BUILD_DIR $DRUPAL_BUILD_DIR/modules/graphql-examples From d963da4ddc4e2c299e21b4ef264240bddb3fd1cb Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 14:40:20 -0500 Subject: [PATCH 07/16] trial and error --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4a5d24f..cee2e9c 100755 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,7 @@ install: - git clone --branch $DRUPAL_CORE --depth 1 https://github.com/drupal/drupal.git $DRUPAL_BUILD_DIR # Download graphql module from the Github mirror because it is faster. - - git clone --depth 1 https://github.com/drupal-graphql/graphql.git $DRUPAL_BUILD_DIR/modules + - git clone --depth 1 https://github.com/drupal-graphql/graphql.git $DRUPAL_BUILD_DIR/modules/contrib/graphql # Reference the module in the build site. - ln -s $TRAVIS_BUILD_DIR $DRUPAL_BUILD_DIR/modules/graphql-examples From e87e4b4f968abf6a48c2737faec89dc253f17a2d Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 14:45:07 -0500 Subject: [PATCH 08/16] silly path issue --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cee2e9c..dce003f 100755 --- a/.travis.yml +++ b/.travis.yml @@ -82,7 +82,7 @@ install: # Copy the customized phpunit configuration file to the core directory so # the relative paths are correct. - - cp $DRUPAL_BUILD_DIR/modules/graphql/phpunit.xml.dist $DRUPAL_BUILD_DIR/core/phpunit.xml + - cp $DRUPAL_BUILD_DIR/modules/contrib/graphql/phpunit.xml.dist $DRUPAL_BUILD_DIR/core/phpunit.xml # When running with phpdbg we need to replace all code occurrences that check # for 'cli' with 'phpdbg'. Some files might be write protected, hence the From c573cb7ec9e8965fe7d5cadfccdab320159d76c5 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Fri, 9 Mar 2018 19:19:01 -0500 Subject: [PATCH 09/16] updating queries and creating node prior to testing --- .../GraphQL/Mutations/DeleteArticle.php | 2 +- tests/queries/deleteArticle.gql | 4 +- tests/queries/updateArticle.gql | 4 +- .../Kernel/Extension/ArticleMutationTest.php | 37 +++++++++++++++++-- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/Plugin/GraphQL/Mutations/DeleteArticle.php b/src/Plugin/GraphQL/Mutations/DeleteArticle.php index e7c5876..8a138d5 100644 --- a/src/Plugin/GraphQL/Mutations/DeleteArticle.php +++ b/src/Plugin/GraphQL/Mutations/DeleteArticle.php @@ -16,7 +16,7 @@ * name = "deleteArticle", * type = "EntityCrudOutput!", * arguments = { - * "id" = "Int" + * "id" = "String" * } * ) */ diff --git a/tests/queries/deleteArticle.gql b/tests/queries/deleteArticle.gql index 856e498..dd8b41d 100644 --- a/tests/queries/deleteArticle.gql +++ b/tests/queries/deleteArticle.gql @@ -1,5 +1,5 @@ -mutation { - deleteArticle(id:1){ +mutation($id: String){ + deleteArticle(id: $id){ errors, violations{ message, diff --git a/tests/queries/updateArticle.gql b/tests/queries/updateArticle.gql index b38657d..476f962 100644 --- a/tests/queries/updateArticle.gql +++ b/tests/queries/updateArticle.gql @@ -1,5 +1,5 @@ -mutation { - updateArticle(id:"1", input:{title: "Heyo", body:"Let's go"}){ +mutation($id: String, $input: ArticleInput){ + updateArticle(id:$id, input:$input){ errors, violations{ message, diff --git a/tests/src/Kernel/Extension/ArticleMutationTest.php b/tests/src/Kernel/Extension/ArticleMutationTest.php index f0f2c3b..77393a8 100644 --- a/tests/src/Kernel/Extension/ArticleMutationTest.php +++ b/tests/src/Kernel/Extension/ArticleMutationTest.php @@ -58,10 +58,13 @@ protected function setUp() { protected function userPermissions() { $perms = parent::userPermissions(); $perms[] = 'access content'; + $perms[] = 'administer nodes'; $perms[] = 'create article content'; - $perms[] = 'delete own article content'; - $perms[] = 'edit own article content'; + $perms[] = 'delete any article content'; + $perms[] = 'edit any article content'; $perms[] = 'execute graphql requests'; + $perms[] = 'administer nodes'; + $perms[] = 'bypass node access'; return $perms; } @@ -91,8 +94,23 @@ public function testCreateArticleMutation() { */ public function testUpdateArticleMutation() { + $node = $this->createNode([ + 'title' => 'Hey', + 'status' => 1, + 'type' => 'Article', + 'body' => [ + 'value' => 'Ho', + ], + ]); + $query = $this->getQueryFromFile('updateArticle.gql'); - $this->assertResults($query, [], [ + $this->assertResults($query, [ + 'id' => $node->id(), + 'input' => [ + 'title' => 'Heyo', + 'body' => "Let's go" + ] + ], [ 'updateArticle' => [ 'errors' => [], 'violations' => [], @@ -111,8 +129,19 @@ public function testUpdateArticleMutation() { */ public function testDeleteArticleMutation() { + $node = $this->createNode([ + 'title' => 'Hey', + 'status' => 1, + 'type' => 'Article', + 'body' => [ + 'value' => 'Ho', + ], + ]); + $query = $this->getQueryFromFile('deleteArticle.gql'); - $this->assertResults($query, [], [ + $this->assertResults($query, [ + 'id' => $node->id(), + ], [ 'deleteArticle' => [ 'errors' => [], 'violations' => [], From 908207cb8f8990439008e84b47a2da7b13d5284b Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Mon, 12 Mar 2018 21:22:08 -0400 Subject: [PATCH 10/16] In Progress --- ...tity_form_display.node.article.default.yml | 20 +++++-- ...tity_view_display.node.article.default.yml | 51 ------------------ ....entity_view_display.node.article.full.yml | 52 ------------------ ...ntity_view_display.node.article.teaser.yml | 53 ------------------- ...y_browser.browser.media_entity_browser.yml | 43 +++++++++++++++ .../field.field.node.article.body.yml | 3 -- .../field.field.node.article.field_image.yml | 3 -- ...d.field.node.article.field_media_image.yml | 27 ++++++++++ .../field.field.node.article.field_tags.yml | 3 -- config/optional/field.storage.node.body.yml | 18 +++++++ .../field.storage.node.field_image.yml | 3 -- .../field.storage.node.field_media_image.yml | 19 +++++++ .../field.storage.node.field_tags.yml | 3 -- config/optional/image.style.thumbnail.yml | 12 +++++ config/optional/media.type.image.yml | 12 +++++ config/optional/node.type.article.yml | 3 -- config/optional/taxonomy.vocabulary.tags.yml | 3 -- .../GraphQL/Mutations/UpdateArticle.php | 2 +- .../Kernel/Extension/ArticleMutationTest.php | 4 +- 19 files changed, 150 insertions(+), 184 deletions(-) delete mode 100644 config/optional/core.entity_view_display.node.article.default.yml delete mode 100644 config/optional/core.entity_view_display.node.article.full.yml delete mode 100644 config/optional/core.entity_view_display.node.article.teaser.yml create mode 100644 config/optional/entity_browser.browser.media_entity_browser.yml create mode 100644 config/optional/field.field.node.article.field_media_image.yml create mode 100644 config/optional/field.storage.node.body.yml create mode 100644 config/optional/field.storage.node.field_media_image.yml create mode 100644 config/optional/image.style.thumbnail.yml create mode 100644 config/optional/media.type.image.yml diff --git a/config/optional/core.entity_form_display.node.article.default.yml b/config/optional/core.entity_form_display.node.article.default.yml index c8cd65d..0198515 100644 --- a/config/optional/core.entity_form_display.node.article.default.yml +++ b/config/optional/core.entity_form_display.node.article.default.yml @@ -1,19 +1,19 @@ -uuid: c811adaa-76bb-4cae-a248-a0d9f7fb72f8 langcode: en status: true dependencies: config: + - entity_browser.browser.media_entity_browser - field.field.node.article.body - field.field.node.article.field_image + - field.field.node.article.field_media_image - field.field.node.article.field_tags - image.style.thumbnail - node.type.article module: + - entity_browser - image - path - text -_core: - default_config_hash: 0StcaANBh8qzNkp_3-xqJlwQoLGxZeRoIwO16LG10d8 id: node.article.default targetEntityType: node bundle: article @@ -42,6 +42,20 @@ content: progress_indicator: throbber preview_image_style: thumbnail third_party_settings: { } + field_media_image: + weight: 4 + settings: + entity_browser: media_entity_browser + field_widget_display: rendered_entity + field_widget_edit: true + field_widget_remove: true + open: true + selection_mode: selection_append + field_widget_display_settings: + view_mode: default + third_party_settings: { } + type: entity_browser_entity_reference + region: content field_tags: type: entity_reference_autocomplete_tags weight: 2 diff --git a/config/optional/core.entity_view_display.node.article.default.yml b/config/optional/core.entity_view_display.node.article.default.yml deleted file mode 100644 index 2028ce3..0000000 --- a/config/optional/core.entity_view_display.node.article.default.yml +++ /dev/null @@ -1,51 +0,0 @@ -uuid: 2621f24b-373d-4046-8621-d807211dc97d -langcode: en -status: true -dependencies: - config: - - field.field.node.article.body - - field.field.node.article.field_image - - field.field.node.article.field_tags - - node.type.article - - responsive_image.styles.3_2_image - module: - - responsive_image - - text - - user -_core: - default_config_hash: _L_3i_Js9-dZMLX2RRJqeryWzABKXwF4PS3Kss1kqQ0 -id: node.article.default -targetEntityType: node -bundle: article -mode: default -content: - body: - type: text_default - weight: 3 - region: content - settings: { } - third_party_settings: { } - label: hidden - field_image: - type: responsive_image - weight: 2 - region: content - settings: - responsive_image_style: 3_2_image - image_link: '' - third_party_settings: { } - label: hidden - field_tags: - type: entity_reference_label - weight: 0 - region: content - label: above - settings: - link: true - third_party_settings: { } - links: - weight: 4 - region: content - settings: { } - third_party_settings: { } -hidden: { } diff --git a/config/optional/core.entity_view_display.node.article.full.yml b/config/optional/core.entity_view_display.node.article.full.yml deleted file mode 100644 index 985cd1c..0000000 --- a/config/optional/core.entity_view_display.node.article.full.yml +++ /dev/null @@ -1,52 +0,0 @@ -uuid: 3ddb5c20-2365-418c-9285-0e335eae728e -langcode: en -status: true -dependencies: - config: - - core.entity_view_mode.node.full - - field.field.node.article.body - - field.field.node.article.field_image - - field.field.node.article.field_tags - - node.type.article - - responsive_image.styles.3_2_image - module: - - responsive_image - - text - - user -_core: - default_config_hash: yVqiZUuFBTwOz9czH5sX0KFILpozm7LParHg2qjhtpU -id: node.article.full -targetEntityType: node -bundle: article -mode: full -content: - body: - type: text_default - weight: 2 - region: content - settings: { } - third_party_settings: { } - label: hidden - field_image: - type: responsive_image - weight: 1 - region: content - settings: - responsive_image_style: 3_2_image - image_link: '' - third_party_settings: { } - label: hidden - field_tags: - type: entity_reference_label - weight: 0 - region: content - label: above - settings: - link: true - third_party_settings: { } - links: - weight: 3 - region: content - settings: { } - third_party_settings: { } -hidden: { } diff --git a/config/optional/core.entity_view_display.node.article.teaser.yml b/config/optional/core.entity_view_display.node.article.teaser.yml deleted file mode 100644 index e2aea26..0000000 --- a/config/optional/core.entity_view_display.node.article.teaser.yml +++ /dev/null @@ -1,53 +0,0 @@ -uuid: ea54bb73-d981-43aa-ab17-7e887c79b575 -langcode: en -status: true -dependencies: - config: - - core.entity_view_mode.node.teaser - - field.field.node.article.body - - field.field.node.article.field_image - - field.field.node.article.field_tags - - node.type.article - - responsive_image.styles.3_2_image - module: - - responsive_image - - text - - user -_core: - default_config_hash: 342xrNFCgiw8mRXaCKDQGA0p8mtvEtZyQzj3DbA5F4A -id: node.article.teaser -targetEntityType: node -bundle: article -mode: teaser -content: - body: - type: text_summary_or_trimmed - weight: 0 - region: content - settings: - trim_length: 600 - third_party_settings: { } - label: hidden - field_image: - type: responsive_image - weight: -1 - region: content - settings: - responsive_image_style: 3_2_image - image_link: content - third_party_settings: { } - label: hidden - field_tags: - type: entity_reference_label - weight: 10 - region: content - settings: - link: true - third_party_settings: { } - label: above - links: - weight: 100 - region: content - settings: { } - third_party_settings: { } -hidden: { } diff --git a/config/optional/entity_browser.browser.media_entity_browser.yml b/config/optional/entity_browser.browser.media_entity_browser.yml new file mode 100644 index 0000000..847ab81 --- /dev/null +++ b/config/optional/entity_browser.browser.media_entity_browser.yml @@ -0,0 +1,43 @@ +langcode: en +status: true +dependencies: + config: + - views.view.media_entity_browser + module: + - views +_core: + default_config_hash: UoGZLPH_DEy28wDjCYqiBKYsKoHlf6l6deygJjqdgPc +name: media_entity_browser +label: 'Media Entity Browser' +display: modal +display_configuration: + width: '' + height: '' + link_text: Select + auto_open: false +selection_display: no_display +selection_display_configuration: { } +widget_selector: tabs +widget_selector_configuration: { } +widgets: + 6586703a-6976-4124-8a49-cbb07ceaa3b1: + settings: + view: media_entity_browser + view_display: entity_browser_1 + submit_text: Select + auto_select: false + uuid: 6586703a-6976-4124-8a49-cbb07ceaa3b1 + weight: 1 + label: view + id: view + 18d9da69-b4e6-4be3-a8bc-bb3fa8574f15: + settings: + extensions: 'jpg jpeg png gif' + media_type: image + upload_location: 'public://' + multiple: '1' + submit_text: 'Select files' + uuid: 18d9da69-b4e6-4be3-a8bc-bb3fa8574f15 + weight: 2 + label: Upload + id: media_image_upload diff --git a/config/optional/field.field.node.article.body.yml b/config/optional/field.field.node.article.body.yml index 7f0de98..8f3681d 100644 --- a/config/optional/field.field.node.article.body.yml +++ b/config/optional/field.field.node.article.body.yml @@ -1,4 +1,3 @@ -uuid: 3f3490b0-52ab-4ff6-97ee-35730efbd0c4 langcode: en status: true dependencies: @@ -7,8 +6,6 @@ dependencies: - node.type.article module: - text -_core: - default_config_hash: Ay3b2hq42cpQTFB_lNu8S2ZxuVIY6-dlBsc7vLeJ-YY id: node.article.body field_name: body entity_type: node diff --git a/config/optional/field.field.node.article.field_image.yml b/config/optional/field.field.node.article.field_image.yml index b6da357..b4b1c14 100644 --- a/config/optional/field.field.node.article.field_image.yml +++ b/config/optional/field.field.node.article.field_image.yml @@ -1,4 +1,3 @@ -uuid: df28dc3a-5571-44af-aa93-c11a0baf890b langcode: en status: true dependencies: @@ -7,8 +6,6 @@ dependencies: - node.type.article module: - image -_core: - default_config_hash: tgJzhA7Swh4M_gWU5FwFe5lPxPj5rebpMbvhpdNrERs id: node.article.field_image field_name: field_image entity_type: node diff --git a/config/optional/field.field.node.article.field_media_image.yml b/config/optional/field.field.node.article.field_media_image.yml new file mode 100644 index 0000000..f510a1b --- /dev/null +++ b/config/optional/field.field.node.article.field_media_image.yml @@ -0,0 +1,27 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_media_image + - media.type.image + - node.type.article +id: node.article.field_media_image +field_name: field_media_image +entity_type: node +bundle: article +label: 'Media Image' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:media' + handler_settings: + target_bundles: + image: image + sort: + field: _none + auto_create: false + auto_create_bundle: '' +field_type: entity_reference diff --git a/config/optional/field.field.node.article.field_tags.yml b/config/optional/field.field.node.article.field_tags.yml index 80c0a48..1b9c4cc 100644 --- a/config/optional/field.field.node.article.field_tags.yml +++ b/config/optional/field.field.node.article.field_tags.yml @@ -1,4 +1,3 @@ -uuid: ffabf45c-045c-4805-a54d-f6439e62883c langcode: en status: true dependencies: @@ -6,8 +5,6 @@ dependencies: - field.storage.node.field_tags - node.type.article - taxonomy.vocabulary.tags -_core: - default_config_hash: QdUgf_beeoaPiyKorFv0q1fcJpWH_uZTqe_xoVJacrw id: node.article.field_tags field_name: field_tags entity_type: node diff --git a/config/optional/field.storage.node.body.yml b/config/optional/field.storage.node.body.yml new file mode 100644 index 0000000..73edd16 --- /dev/null +++ b/config/optional/field.storage.node.body.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + module: + - node + - text +id: node.body +field_name: body +entity_type: node +type: text_with_summary +settings: { } +module: text +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: true +custom_storage: false diff --git a/config/optional/field.storage.node.field_image.yml b/config/optional/field.storage.node.field_image.yml index 9d3bb47..e4da708 100644 --- a/config/optional/field.storage.node.field_image.yml +++ b/config/optional/field.storage.node.field_image.yml @@ -1,4 +1,3 @@ -uuid: cc2520c3-3829-49b8-b4ca-2aea88328b45 langcode: en status: true dependencies: @@ -6,8 +5,6 @@ dependencies: - file - image - node -_core: - default_config_hash: SkXIPKZYiIMMtnBmfnxk58RYfbZ8cHSw5NZPY_JByME id: node.field_image field_name: field_image entity_type: node diff --git a/config/optional/field.storage.node.field_media_image.yml b/config/optional/field.storage.node.field_media_image.yml new file mode 100644 index 0000000..11348eb --- /dev/null +++ b/config/optional/field.storage.node.field_media_image.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - media + - node +id: node.field_media_image +field_name: field_media_image +entity_type: node +type: entity_reference +settings: + target_type: media +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/optional/field.storage.node.field_tags.yml b/config/optional/field.storage.node.field_tags.yml index b6301dd..73f821f 100644 --- a/config/optional/field.storage.node.field_tags.yml +++ b/config/optional/field.storage.node.field_tags.yml @@ -1,12 +1,9 @@ -uuid: e86da172-f349-4b99-965a-34e0a3bf38d6 langcode: en status: true dependencies: module: - node - taxonomy -_core: - default_config_hash: WpOE_bs8Bs_HY2ns7n2r__de-xno0-Bxkqep5-MsHAs id: node.field_tags field_name: field_tags entity_type: node diff --git a/config/optional/image.style.thumbnail.yml b/config/optional/image.style.thumbnail.yml new file mode 100644 index 0000000..b275920 --- /dev/null +++ b/config/optional/image.style.thumbnail.yml @@ -0,0 +1,12 @@ +langcode: en +status: true +dependencies: { } +name: thumbnail +label: 'Thumbnail (100×100)' +effects: + id: image_scale + weight: 0 + data: + width: 100 + height: 100 + upscale: false diff --git a/config/optional/media.type.image.yml b/config/optional/media.type.image.yml new file mode 100644 index 0000000..252de4c --- /dev/null +++ b/config/optional/media.type.image.yml @@ -0,0 +1,12 @@ +langcode: en +status: true +dependencies: { } +id: image +label: Image +description: '' +source: image +queue_thumbnail_downloads: false +new_revision: false +source_configuration: + source_field: field_media_image +field_map: { } diff --git a/config/optional/node.type.article.yml b/config/optional/node.type.article.yml index de3f2fb..1fd439c 100644 --- a/config/optional/node.type.article.yml +++ b/config/optional/node.type.article.yml @@ -1,9 +1,6 @@ -uuid: 2bda1406-8136-4aad-9439-13bec16d6b1b langcode: en status: true dependencies: { } -_core: - default_config_hash: AeW1SEDgb1OTQACAWGhzvMknMYAJlcZu0jljfeU3oso name: Article type: article description: 'Use articles for time-sensitive content like news, press releases or blog posts.' diff --git a/config/optional/taxonomy.vocabulary.tags.yml b/config/optional/taxonomy.vocabulary.tags.yml index b4b7f6d..8fac8f5 100644 --- a/config/optional/taxonomy.vocabulary.tags.yml +++ b/config/optional/taxonomy.vocabulary.tags.yml @@ -1,9 +1,6 @@ -uuid: f4f97885-5b25-47cf-9663-2916c6e5ae6a langcode: en status: true dependencies: { } -_core: - default_config_hash: lO5ziR5dVI1PpEeHZsSOfQ-Y7NWihSDKW8-MMf6uoms name: Tags vid: tags description: 'Use tags to group articles on similar topics into categories.' diff --git a/src/Plugin/GraphQL/Mutations/UpdateArticle.php b/src/Plugin/GraphQL/Mutations/UpdateArticle.php index d71c8f9..004d301 100644 --- a/src/Plugin/GraphQL/Mutations/UpdateArticle.php +++ b/src/Plugin/GraphQL/Mutations/UpdateArticle.php @@ -30,7 +30,7 @@ class UpdateArticle extends UpdateEntityBase { protected function extractEntityInput($value, array $args, ResolveContext $context, ResolveInfo $info) { return array_filter([ 'title' => $args['input']['title'], - 'body' => $args['input']['body'], + 'body' => key_exists('body', $args['input']) ? $args['input']['body'] : '', ]); } diff --git a/tests/src/Kernel/Extension/ArticleMutationTest.php b/tests/src/Kernel/Extension/ArticleMutationTest.php index 77393a8..59469dc 100644 --- a/tests/src/Kernel/Extension/ArticleMutationTest.php +++ b/tests/src/Kernel/Extension/ArticleMutationTest.php @@ -42,8 +42,7 @@ protected function setUp() { parent::setUp(); $this->installConfig(['system', 'node', 'field', 'text', 'filter', 'file', 'image', 'taxonomy', 'graphql', 'graphql_core', 'graphql_examples']); - $this->installEntitySchema('node', 'user', 'graphql_examples'); - + $this->installEntitySchema('node'); $this->installEntitySchema('user'); $this->installEntitySchema('taxonomy_vocabulary'); $this->installEntitySchema('taxonomy_term'); @@ -108,7 +107,6 @@ public function testUpdateArticleMutation() { 'id' => $node->id(), 'input' => [ 'title' => 'Heyo', - 'body' => "Let's go" ] ], [ 'updateArticle' => [ From 5ec9bd8b2a4d5e5f23d9778e2f001196f0e4c588 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Mon, 12 Mar 2018 21:51:04 -0400 Subject: [PATCH 11/16] Tests passing locally --- tests/src/Kernel/Extension/ArticleMutationTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/src/Kernel/Extension/ArticleMutationTest.php b/tests/src/Kernel/Extension/ArticleMutationTest.php index 59469dc..ff22d1a 100644 --- a/tests/src/Kernel/Extension/ArticleMutationTest.php +++ b/tests/src/Kernel/Extension/ArticleMutationTest.php @@ -96,7 +96,7 @@ public function testUpdateArticleMutation() { $node = $this->createNode([ 'title' => 'Hey', 'status' => 1, - 'type' => 'Article', + 'type' => 'article', 'body' => [ 'value' => 'Ho', ], @@ -107,6 +107,7 @@ public function testUpdateArticleMutation() { 'id' => $node->id(), 'input' => [ 'title' => 'Heyo', + 'body' => "Let's go", ] ], [ 'updateArticle' => [ @@ -130,7 +131,7 @@ public function testDeleteArticleMutation() { $node = $this->createNode([ 'title' => 'Hey', 'status' => 1, - 'type' => 'Article', + 'type' => 'article', 'body' => [ 'value' => 'Ho', ], From 6bae1f49a3424b4cc249143d04feec2d1bb2a7e4 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Mon, 12 Mar 2018 21:59:49 -0400 Subject: [PATCH 12/16] Cleanup modules and permissions --- .../Kernel/Extension/ArticleMutationTest.php | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/tests/src/Kernel/Extension/ArticleMutationTest.php b/tests/src/Kernel/Extension/ArticleMutationTest.php index ff22d1a..76ea2f3 100644 --- a/tests/src/Kernel/Extension/ArticleMutationTest.php +++ b/tests/src/Kernel/Extension/ArticleMutationTest.php @@ -11,17 +11,9 @@ */ class ArticleMutationTest extends GraphQLContentTestBase { public static $modules = [ - 'system', - 'node', - 'user', - 'field', - 'filter', - 'text', 'file', 'image', 'taxonomy', - 'graphql', - 'graphql_core', 'graphql_examples', ]; @@ -41,9 +33,7 @@ protected function defaultCacheTags() { protected function setUp() { parent::setUp(); - $this->installConfig(['system', 'node', 'field', 'text', 'filter', 'file', 'image', 'taxonomy', 'graphql', 'graphql_core', 'graphql_examples']); - $this->installEntitySchema('node'); - $this->installEntitySchema('user'); + $this->installConfig(['file', 'image', 'taxonomy', 'graphql_examples']); $this->installEntitySchema('taxonomy_vocabulary'); $this->installEntitySchema('taxonomy_term'); @@ -57,13 +47,10 @@ protected function setUp() { protected function userPermissions() { $perms = parent::userPermissions(); $perms[] = 'access content'; - $perms[] = 'administer nodes'; $perms[] = 'create article content'; - $perms[] = 'delete any article content'; - $perms[] = 'edit any article content'; + $perms[] = 'delete own article content'; + $perms[] = 'edit own article content'; $perms[] = 'execute graphql requests'; - $perms[] = 'administer nodes'; - $perms[] = 'bypass node access'; return $perms; } From 344f4dfad0f7103ad014099664397b74315c0607 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Mon, 12 Mar 2018 22:02:23 -0400 Subject: [PATCH 13/16] travis 8.5.x update --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dce003f..5cdf5a9 100755 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ env: matrix: - DRUPAL_CORE=8.3.x - DRUPAL_CORE=8.4.x + - DRUPAL_CORE=8.5.x matrix: # Don't wait for the allowed failures to build. @@ -22,14 +23,14 @@ matrix: include: - php: 7.1 env: - - DRUPAL_CORE=8.4.x + - DRUPAL_CORE=8.5.x # Only run code coverage on the latest php and drupal versions. - WITH_PHPDBG_COVERAGE=true allow_failures: # Allow the code coverage report to fail. - php: 7.1 env: - - DRUPAL_CORE=8.4.x + - DRUPAL_CORE=8.5.x # Only run code coverage on the latest php and drupal versions. - WITH_PHPDBG_COVERAGE=true From f64457d658615d8717a00600a8029cf6616eb283 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Tue, 13 Mar 2018 08:30:49 -0400 Subject: [PATCH 14/16] Adding in variables for consistency --- tests/queries/createArticle.gql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/queries/createArticle.gql b/tests/queries/createArticle.gql index 85d36dc..0d20183 100644 --- a/tests/queries/createArticle.gql +++ b/tests/queries/createArticle.gql @@ -1,5 +1,5 @@ -mutation { - createArticle(input:{title: "Hey", body:"Ho"}){ +mutation($input: ArticleInput){ + createArticle(input: $input){ errors, violations{ message, From 67660d676d72713cf031a4632844e87e8e0e5c0c Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Tue, 13 Mar 2018 08:31:03 -0400 Subject: [PATCH 15/16] Refactoring and adding failing tests --- .../Kernel/Extension/ArticleMutationTest.php | 106 +++++++++++++----- 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/tests/src/Kernel/Extension/ArticleMutationTest.php b/tests/src/Kernel/Extension/ArticleMutationTest.php index 76ea2f3..8bfdc8c 100644 --- a/tests/src/Kernel/Extension/ArticleMutationTest.php +++ b/tests/src/Kernel/Extension/ArticleMutationTest.php @@ -54,13 +54,29 @@ protected function userPermissions() { return $perms; } + public function createTestArticle() { + return $this->createNode([ + 'title' => 'Hey', + 'status' => 1, + 'type' => 'article', + 'body' => [ + 'value' => 'Ho', + ], + ]); + } + /** * Test if the article is created properly. */ public function testCreateArticleMutation() { - $query = $this->getQueryFromFile('createArticle.gql'); - $this->assertResults($query, [], [ + $variables = [ + 'input' => [ + 'title' => 'Hey', + 'body' => "Ho" + ] + ]; + $expected = [ 'createArticle' => [ 'errors' => [], 'violations' => [], @@ -71,7 +87,26 @@ public function testCreateArticleMutation() { ] ] ], - ], $this->defaultMutationCacheMetaData()); + ]; + $this->assertResults($query, $variables, $expected, $this->defaultMutationCacheMetaData()); + } + + /** + * Test if the article is NOT created properly. + */ + public function testCreateArticleFailureMutation() { + $query = $this->getQueryFromFile('createArticle.gql'); + $variables = [ + 'input' => [ + 'title' => 'Hey', + 'some-non-existent-field' => "Ho" + ] + ]; + $expected = [ + "Variable \"\$input\" got invalid value {\"title\":\"Hey\",\"some-non-existent-field\":\"Ho\"}. +In field \"some-non-existent-field\": Unknown field." + ]; + $this->assertErrors($query, $variables, $expected, $this->defaultMutationCacheMetaData()); } @@ -80,23 +115,18 @@ public function testCreateArticleMutation() { */ public function testUpdateArticleMutation() { - $node = $this->createNode([ - 'title' => 'Hey', - 'status' => 1, - 'type' => 'article', - 'body' => [ - 'value' => 'Ho', - ], - ]); + // SETUP + $node = $this->createTestArticle(); $query = $this->getQueryFromFile('updateArticle.gql'); - $this->assertResults($query, [ - 'id' => $node->id(), - 'input' => [ - 'title' => 'Heyo', - 'body' => "Let's go", - ] - ], [ + $variables = [ + 'id' => $node->id(), + 'input' => [ + 'title' => 'Heyo', + 'body' => "Let's go", + ] + ]; + $expected = [ 'updateArticle' => [ 'errors' => [], 'violations' => [], @@ -107,7 +137,8 @@ public function testUpdateArticleMutation() { ] ] ], - ], $this->defaultMutationCacheMetaData()); + ]; + $this->assertResults($query, $variables, $expected, $this->defaultMutationCacheMetaData()); } /** @@ -115,19 +146,14 @@ public function testUpdateArticleMutation() { */ public function testDeleteArticleMutation() { - $node = $this->createNode([ - 'title' => 'Hey', - 'status' => 1, - 'type' => 'article', - 'body' => [ - 'value' => 'Ho', - ], - ]); + // SETUP + $node = $this->createTestArticle(); $query = $this->getQueryFromFile('deleteArticle.gql'); - $this->assertResults($query, [ + $variables = [ 'id' => $node->id(), - ], [ + ]; + $expected = [ 'deleteArticle' => [ 'errors' => [], 'violations' => [], @@ -138,7 +164,27 @@ public function testDeleteArticleMutation() { ] ] ], - ], $this->defaultMutationCacheMetaData()); + ]; + $this->assertResults($query, $variables, $expected, $this->defaultMutationCacheMetaData()); + } + + /** + * Test if the article is deleted properly. + */ + public function testDeleteNonExistentArticleMutation() { + + // SETUP + $node = $this->createTestArticle(); + + $query = $this->getQueryFromFile('deleteArticle.gql'); + $variables = [ + 'id' => 999, + ]; + // Note, the newline in the following string is required. + $expected = ["Variable \"\$id\" got invalid value 999. +Expected type \"String\", found 999."]; + $this->assertErrors($query, $variables, $expected, $this->defaultMutationCacheMetaData()); } + } From db1ed5e38bfd0f68aee369cc04fab76c877bef43 Mon Sep 17 00:00:00 2001 From: Justin Winter Date: Tue, 13 Mar 2018 09:49:25 -0400 Subject: [PATCH 16/16] mispelling --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1432286..000a269 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "drupal/graphql_exmaples", + "name": "drupal/graphql_examples", "type": "drupal-module", "description": "A GraphQL Article and File Mutation Example", "keywords": ["Drupal"],