Skip to content

Commit

Permalink
NEW: GraphQL 4 Compatibility (#308)
Browse files Browse the repository at this point in the history
* First pass at graphql 4 compat

* It works kinda

* Remove conflict composer

* Replace graphql3 legacy

* Fix ApplyVersionFilters conflict

* Fix paginate plugin bfore

* Compatability with flushless schema

* Throw if versioned used on nested query

* Versioned readone

* NEW schema defaults

* Compliance with new modelConfig

* Fix exlcusion rule

* Remove old classes

* Proper sort for versions field

* Compatability with field formatting API

* New graphql 3 compat

* compliance with new modeltype constructor

* Operations tests for v4'

* new composer constraint for graphql

* Add shims for graphql branches

* Fix git branch

* Update admin requirement

* Clean up travis

* Remove admin depdendency

* Add graphql dependency

* Clean up tests

* Tests should work now

* Fix linting

* BC tests fixed

* Add missing versioned fields

* Linting

* use stageTable

* API Mark GraphQL v3 usage as deprecated

* Fixed draft table alias regression

Co-authored-by: Ingo Schommer <[email protected]>
  • Loading branch information
Aaron Carlino and chillu authored Nov 13, 2020
1 parent cdf24ea commit 4a42ca7
Show file tree
Hide file tree
Showing 53 changed files with 2,167 additions and 62 deletions.
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:
env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1
- php: 7.4
env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1
- php: 7.4
env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1 BACKWARD_COMPAT=1
- php: nightly
env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1 COMPOSER_ARG=--ignore-platform-reqs

Expand All @@ -37,12 +39,20 @@ before_script:

# Install composer
- composer validate
- composer require silverstripe/recipe-cms:$RECIPE_VERSION --no-update
- composer require silverstripe/recipe-cms:$RECIPE_VERSION --no-update --prefer-dist
# Fix for running phpunit 5 on php 7.4+
- composer require --no-update sminnee/phpunit-mock-objects:^3

######## Remove once GraphQL 4 is merged #########
- composer require silverstripe/admin:"dev-pulls/1/schemageddon as 1.x-dev" silverstripe/asset-admin:"dev-pulls/1/schemageddon as 1.x-dev" silverstripe/versioned-admin:"dev-pulls/1/schemageddon as 1.x-dev" silverstripe/cms:"dev-pulls/4/schemageddon as 4.x-dev" silverstripe/graphql:"4.x-dev as 3.x-dev" --no-update
##################################################
- 'if [[ $BACKWARD_COMPAT ]]; then composer require silverstripe/graphql:"dev-pulls/3/schemageddon-compat as 3.x-dev" --no-update; fi'


- if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:^2 --no-update; fi
- composer update --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile $COMPOSER_ARG


script:
- if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit tests/php; fi
- if [[ $PHPCS_TEST ]]; then composer run-script lint; fi
Expand Down
2 changes: 2 additions & 0 deletions _config/graphql.yml → _config/graphql-legacy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Name: versioned-graphql
Only:
moduleexists: 'silverstripe/graphql'
Except:
classexists: 'SilverStripe\GraphQL\Schema\Schema'
---
SilverStripe\GraphQL\Scaffolding\Scaffolders\CRUD\Read:
extensions:
Expand Down
12 changes: 12 additions & 0 deletions _config/graphql_operations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
Name: versioned-graphql-dataobject
Only:
moduleexists: 'silverstripe/graphql'
classexists: 'SilverStripe\GraphQL\Schema\Schema'
---
SilverStripe\GraphQL\Schema\DataObject\DataObjectModel:
operations:
copyToStage: 'SilverStripe\Versioned\GraphQL\Operations\CopyToStageCreator'
publish: 'SilverStripe\Versioned\GraphQL\Operations\PublishCreator'
unpublish: 'SilverStripe\Versioned\GraphQL\Operations\UnpublishCreator'
rollback: 'SilverStripe\Versioned\GraphQL\Operations\RollbackCreator'
12 changes: 12 additions & 0 deletions _config/graphql_plugins.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
Name: versioned-graphql-plugins
Only:
moduleexists: 'silverstripe/graphql'
classexists: 'SilverStripe\GraphQL\Schema\Schema'
---
SilverStripe\Core\Injector\Injector:
SilverStripe\GraphQL\Schema\Registry\PluginRegistry:
constructor:
versionedDataobject: '%$SilverStripe\Versioned\GraphQL\Plugins\VersionedDataObject'
unpublishOnDelete: '%$SilverStripe\Versioned\GraphQL\Plugins\UnpublishOnDelete'
readVersionedDataObject: '%$SilverStripe\Versioned\GraphQL\Plugins\VersionedRead'
11 changes: 11 additions & 0 deletions _config/graphql_schema.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
Name: versioned-graphql-schema
Only:
moduleexists: 'silverstripe/graphql'
classexists: 'SilverStripe\GraphQL\Schema\Schema'
---
SilverStripe\GraphQL\Schema\Schema:
schemas:
'*':
src:
versionedSrc: 'silverstripe/versioned: _graphql'
50 changes: 50 additions & 0 deletions _graphql/enums.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
VersionedStage:
description: The stage to read from or write to
values:
DRAFT:
value: Stage
description: The draft stage
LIVE:
value: Live
description: The live stage

VersionedQueryMode:
description: The versioned mode to use
values:
ARCHIVE:
value: archive
description: Read from a specific date of the archive
LATEST:
value: latest_versions
description: Read the latest version
ALL_VERSIONS:
value: all_versions
description: Reads all versionse
DRAFT:
value: Stage
description: Read from the draft stage
LIVE:
value: Live
description: Read from the live stage
STATUS:
value: status
description: Read only records with a specific status
VERSION:
value: version
description: Read a specific version

VersionedStatus:
description: The stage to read from or write to
values:
PUBLISHED:
value: published
description: Only published records
DRAFT:
value: draft
description: Only draft records
ARCHIVED:
value: archived
description: Only records that have been archived
MODIFIED:
value: modified
description: Only records that have unpublished changes
15 changes: 15 additions & 0 deletions _graphql/modelConfig.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
DataObject:
plugins:
versioning: true
operations:
read:
plugins:
readVersion:
before: paginateList
readOne:
plugins:
readVersion:
before: firstResult
delete:
plugins:
unpublishOnDelete: true
27 changes: 27 additions & 0 deletions _graphql/types.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
CopyToStageInputType:
input: true
fields:
id:
type: ID!
description: The ID of the record to copy
fromVersion:
type: Int
description: The source version number to copy
fromStage:
type: VersionedStage
description: The source stage to copy
toStage:
type: VersionedStage
description: The destination state to copy to

VersionedInputType:
input: true
fields:
mode: VersionedQueryMode = Stage
archiveDate:
type: String
description: The date to use for archive
status:
type: '[VersionedStatus]'
description: If mode is STATUS, specify which versioned statuses
version: Int
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
},
"require-dev": {
"sminnee/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^3",
"silverstripe/graphql": "^3"
"silverstripe/graphql": "3.x-dev || 4.x-dev",
"squizlabs/php_codesniffer": "^3"
},
"extra": [],
"autoload": {
"psr-4": {
"SilverStripe\\Versioned\\": "src/",
"SilverStripe\\Versioned\\Tests\\": "tests/php/"
}
},
"classmap": ["src/GraphQL/_legacy"]
},
"scripts": {
"lint": "vendor/bin/phpcs src/ tests/php/",
Expand Down
75 changes: 75 additions & 0 deletions src/GraphQL/Operations/AbstractPublishOperationCreator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace SilverStripe\Versioned\GraphQL\Operations;

use Exception;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\GraphQL\Manager;
use SilverStripe\GraphQL\OperationResolver;
use SilverStripe\GraphQL\Scaffolding\Scaffolders\MutationScaffolder;
use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException;
use SilverStripe\GraphQL\Schema\Field\ModelMutation;
use SilverStripe\GraphQL\Schema\Interfaces\ModelOperation;
use SilverStripe\GraphQL\Schema\Interfaces\OperationCreator;
use SilverStripe\GraphQL\Schema\Interfaces\SchemaModelInterface;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Member;
use SilverStripe\Versioned\GraphQL\Resolvers\VersionedResolver;
use SilverStripe\Versioned\Versioned;

if (!interface_exists(OperationCreator::class)) {
return;
}

/**
* Scaffolds a generic update operation for DataObjects.
*/
abstract class AbstractPublishOperationCreator implements OperationCreator
{
use Configurable;
use Injectable;

const ACTION_PUBLISH = 'publish';
const ACTION_UNPUBLISH = 'unpublish';

/**
* @param SchemaModelInterface $model
* @param string $typeName
* @param array $config
* @return ModelOperation|null
* @throws SchemaBuilderException
*/
public function createOperation(
SchemaModelInterface $model,
string $typeName,
array $config = []
): ?ModelOperation {
if (!Extensible::has_extension($model->getSourceClass(), Versioned::class)) {
return null;
}

$plugins = $config['plugins'] ?? [];
$name = $config['name'] ?? null;
if (!$name) {
$name = $this->createOperationName($typeName);
}
return ModelMutation::create($model, $name)
->setPlugins($plugins)
->setType($typeName)
->setResolver([VersionedResolver::class, 'resolvePublishOperation'])
->addResolverContext('action', $this->getAction())
->addResolverContext('dataClass', $model->getSourceClass())
->addArg('id', 'ID!');
}

abstract protected function createOperationName(string $typeName): string;

abstract protected function getAction(): string;
}
66 changes: 66 additions & 0 deletions src/GraphQL/Operations/CopyToStageCreator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace SilverStripe\Versioned\GraphQL\Operations;

use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException;
use SilverStripe\GraphQL\Schema\Field\ModelMutation;
use SilverStripe\GraphQL\Schema\Interfaces\ModelOperation;
use SilverStripe\GraphQL\Schema\Interfaces\OperationCreator;
use SilverStripe\GraphQL\Schema\Interfaces\SchemaModelInterface;
use SilverStripe\Versioned\GraphQL\Resolvers\VersionedResolver;
use SilverStripe\Versioned\Versioned;

if (!interface_exists(OperationCreator::class)) {
return;
}

/**
* Scaffolds a "copy to stage" operation for DataObjects.
*
* copy[TypeName]ToStage(ID!, FromVersion!, FromStage!, ToStage!)
*
*/
class CopyToStageCreator implements OperationCreator
{
use Configurable;
use Injectable;

/**
* @var array
* @config
*/
private static $default_plugins = [];

/**
* @param SchemaModelInterface $model
* @param string $typeName
* @param array $config
* @return ModelOperation|null
* @throws SchemaBuilderException
*/
public function createOperation(
SchemaModelInterface $model,
string $typeName,
array $config = []
): ?ModelOperation {
if (!Extensible::has_extension($model->getSourceClass(), Versioned::class)) {
return null;
}

$plugins = $config['plugins'] ?? [];
$mutationName = $config['name'] ?? null;
if (!$mutationName) {
$mutationName = 'copy' . ucfirst($typeName) . 'ToStage';
}

return ModelMutation::create($model, $mutationName)
->setType($typeName)
->setPlugins($plugins)
->setDefaultResolver([VersionedResolver::class, 'resolveCopyToStage'])
->addResolverContext('dataClass', $model->getSourceClass())
->addArg('input', 'CopyToStageInputType!');
}
}
33 changes: 33 additions & 0 deletions src/GraphQL/Operations/PublishCreator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace SilverStripe\Versioned\GraphQL\Operations;

use SilverStripe\GraphQL\Schema\Interfaces\OperationCreator;

if (!interface_exists(OperationCreator::class)) {
return;
}

/**
* Scaffolds a generic update operation for DataObjects.
*/
class PublishCreator extends AbstractPublishOperationCreator
{

/**
* @param string $typeName
* @return string
*/
protected function createOperationName(string $typeName): string
{
return 'publish' . ucfirst($typeName);
}

/**
* @return string
*/
protected function getAction(): string
{
return AbstractPublishOperationCreator::ACTION_PUBLISH;
}
}
Loading

0 comments on commit 4a42ca7

Please sign in to comment.