mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-09-16 22:46:20 +02:00
118 lines
3.8 KiB
Markdown
118 lines
3.8 KiB
Markdown
|
---
|
||
|
title: Adding a custom model
|
||
|
summary: 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](https://www.silverstripe.org/blog/community-slack-channel/),
|
||
|
and report any issues at [github.com/silverstripe/silverstripe-graphql](https://github.com/silverstripe/silverstripe-graphql).
|
||
|
Docs for the current stable version (3.x) can be found
|
||
|
[here](https://github.com/silverstripe/silverstripe-graphql/tree/3)
|
||
|
[/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 model
|
||
|
* `getTypeForField(string $fieldName): ?string`: Given a field name,
|
||
|
infer the type. If the field doesn't exist, return `null`
|
||
|
* `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 object
|
||
|
* `getModelField(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` on `DataObjectModel`)
|
||
|
|
||
|
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:
|
||
|
|
||
|
```php
|
||
|
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:
|
||
|
|
||
|
```yaml
|
||
|
SilverStripe\Core\Injector\Injector:
|
||
|
SilverStripe\GraphQL\Schema\Registry\SchemaModelCreatorRegistry:
|
||
|
constructor:
|
||
|
dataobject: '%$SilverStripe\GraphQL\Schema\DataObject\ModelCreator'
|
||
|
```
|
||
|
|
||
|
### Further reading
|
||
|
|
||
|
[CHILDREN]
|