Extending the schema
- Adding a custom model
- Add a new class-backed type beyond DataObject
- Adding a custom operation
- Add a new operation for model types
- Adding middleware
- Add middleware to to extend query execution
- The global schema
- How to push modifications to every schema in the project
Adding a custom model
The only point of contact the silverstripe/graphql schema has with
the Silverstripe ORM specifically is through the DataObjectModel adapter
and its associated plugins. This is important, because it means you
can plug in any schema-aware class as a model, and it will be afforded
all the same features as DataObjects.
It is, however, hard to imagine a model-driven type that isn't
related to an ORM, so we'll keep this section simple and just describe
what the requirements are rather than think up an outlandish example
of what a non-DataObject model might be.
SchemaModelInterface
Models must implement the SchemaModelInterface,
which has a lot of methods to implement. Let's walk through them:
getIdentifier(): string: A unique identifier for this model type, e.g.DataObjecthasField(string $fieldName): bool: Return true if$fieldNameexists on the modelgetTypeForField(string $fieldName): ?string: Given a field name, infer the type. If the field doesn't exist, returnnullgetTypeName(): string: Get the name of the type (i.e. based on the source class)getDefaultResolver(?array $context = []): ResolverReference: Get the generic resolver that should be used for types that are built with this model.getSourceClass(): string: Get the name of the class that builds the type, e.g.MyDataObjectgetAllFields(): array: Get all available fields on the objectgetModelField(string $fieldName): ?ModelType: For nested fields. If a field resolves to another model (e.g. has_one), return that model type.
In addition, models may want to implement:
OperationProvider(if your model creates operations, like read, create, etc)DefaultFieldsProvider(if your model provides a default list of fields, e.g.id)
This is all a lot to take in out of context. A good exercise would be
to look through how DataObjectModel implements all these methods.
SchemaModelCreatorInterface
Given a class name, create an instance of SchemaModelCreatorInterface.
This layer of abstraction is necessary because we can't assume that
all implementations of SchemaModelCreatorInterface will accept a class name in their
constructors.
Implementors of this interface just need to be able to report whether they apply to a given class and create a model given a class name.
Look at the ModelCreator implementation
for a good example of how this works.
Registering your model creator
Just add it to the registry:
# app/_graphql/config.yml
modelCreators:
- 'SilverStripe\GraphQL\Schema\DataObject\ModelCreator'