Extending the schema

Adding a custom model
Add a new class-backed type beyond DataObject
Adding middleware
Add middleware to to extend query execution
Adding a custom operation
Add a new operation for model types
The global schema
How to push modifications to every schema in the project
You are viewing docs for a pre-release version of silverstripe/graphql (4.x). Help us improve it by joining #graphql on the Community Slack, and report any issues at github.com/silverstripe/silverstripe-graphql. Docs for the current stable version (3.x) can be found here

Adding a custom operation

By default, we get basic operations for our models, like read, create, update, and delete, but we can add to this list by creating an implementation of OperationProvider and registering it.

Let's build a new operation that duplicates DataObjects.

class DuplicateCreator implements OperationCreator
{
    public function createOperation(
        SchemaModelInterface $model,
        string $typeName,
        array $config = []
    ): ?ModelOperation
    {
        $mutationName = 'duplicate' . ucfirst(Schema::pluralise($typeName));

        return ModelMutation::create($model, $mutationName)
            ->setType($typeName)
            ->addArg('id', 'ID!')
            ->setDefaultResolver([static::class, 'resolve'])
            ->setResolverContext([
                'dataClass' => $model->getSourceClass(),
            ]);
    }

We add resolver context to the mutation because we need to know what class to duplicate, but we need to make sure we still have a static function.

The signature for resolvers with context is:

public static function (array $context): Closure;

We use the context to pass to a function that we'll create dynamically. Let's add that now.

public static function resolve(array $resolverContext = []): Closure
{
    $dataClass = $resolverContext['dataClass'] ?? null;
    return function ($obj, array $args) use ($dataClass) {
        if (!$dataClass) {
            return null;
        }
        return DataObject::get_by_id($dataClass, $args['id'])
        	->duplicate();
    };
}

Now, just add the operation to the DataObjectModel configuration to make it available to all DataObject types.

app/_graphql/config.yml

modelConfig:
  DataObject:
    operations:
      duplicate:
        class: 'MyProject\Operations\DuplicateCreator'

And use it:

app/_graphql/models.yml

MyProject\Models\MyDataObject:
  fields: '*'
  operations:
    read: true
    duplicate: true

Further reading

Adding a custom model
Add a new class-backed type beyond DataObject
Adding middleware
Add middleware to to extend query execution
Adding a custom operation
Add a new operation for model types
The global schema
How to push modifications to every schema in the project