3.7 KiB
title | summary |
---|---|
Adding a custom model | Add a new class-backed type beyond DataObject |
Extending the Schema
[CHILDREN asList]
[alert] 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 [/alert]
Adding a custom model
The only point of contact the silverstripe-graphql
schema has with
Silverstripe 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 some
hefty requirements. Let's walk through them:
getIdentifier(): string
: A unique identifier for this model type, e.g. 'DataObject'hasField(string $fieldName): bool
: Return true if$fieldName
exists on the modelgetTypeForField(string $fieldName): ?string
: Given a field name, infer the type. If the field doesn't exist, returnnull
getTypeName(): 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.MyDataObject
getAllFields(): array
: Get all availble 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
)DefaultPluginProvider
(if your model can supply a default set of plugins, e.g.default_plugins
onDataObjectModel
)
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 SchemaModelInterface
.
This layer of abstraction is necessary because we can't assume that
all SchemaModelInterfaces
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 DataObjectModel implementation:
class ModelCreator implements SchemaModelCreatorInterface
{
use Injectable;
/**
* @param string $class
* @return bool
*/
public function appliesTo(string $class): bool
{
return is_subclass_of($class, DataObject::class);
}
/**
* @param string $class
* @return SchemaModelInterface
*/
public function createModel(string $class): SchemaModelInterface
{
return DataObjectModel::create($class);
}
}
Registering your model creator
Just add it to the registry:
**app/_graphql/config.yml
modelCreators:
- 'SilverStripe\GraphQL\Schema\DataObject\ModelCreator'
Further reading
[CHILDREN]