silverstripe-framework/docs/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/01_dataobject_model_type.md

291 lines
7.7 KiB
Markdown
Raw Normal View History

WIP: Add new graphql 4 docs (#9652) * DOCS: Add new graphql 4 docs * Reorganise docs * Docs done * Basic graphql index page * TOC for getting started * show folders on graphql index page * Add middleware note * Docs update * Update docs to reflect flushless schema * Docs updates * Docs for getByLink * Query caching docs * Docs on nested operations * update docs for new graphql dev admin * Docs for configurable operations * Replace readSiteTrees with readPages * Schema defaults docs * Docs for inherited plugins * Docs for customising * * Docs for field whitelisting * Change whitelist word * New docs on modelConfig * Document dev/build extension * Document default/global plugins * Document new input type fields config * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Note about when procedural schema gets built * Fix link * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Note about plugins in custom queries * DOCS Note about filter and custom resolvers * DOCS Note about canview paging * DOCS Updated guidance on _extend See https://github.com/silverstripe/silverstripe-graphql/issues/296 * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Pre-release warning Co-authored-by: Ingo Schommer <ingo@silverstripe.com> Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> Co-authored-by: Ingo Schommer <me@chillu.com>
2020-10-19 23:56:17 +02:00
---
title: The DataObject model type
summary: An overview of how the DataObject model can influence the creation of types, queries, and mutations
---
# Working with DataObjects
[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]
## The DataObject model type
In Silverstripe CMS projects, our data tends to be contained in dataobjects almost exclusively,
and the silverstripe-graphql schema API is designed to make adding dataobject content fast and simple.
### Using model types
While it is possible to add dataobjects to your schema as generic types under the `types`
section of the configuration, and their associated queries and mutations under `queries` and
`mutations`, this will lead to a lot of boilerplate code and repetition. Unless you have some
really custom needs, a much better approach is to embrace _convention over configuration_
and use the `models` section of the config.
**Model types** are types that rely on external classes to tell them who they are and what
they can and cannot do. The model can define and resolve fields, auto-generate queries
and mutations, and more.
Naturally, this module comes bundled with a model type for subclasses of `DataObject`.
Let's use the `models` config to expose some content.
**app/_graphql/models.yml**
```
Page:
fields: '*'
operations: '*'
```
The class `Page` is a subclass of `DataObject`, so the bundled model
type will kick in here and provide a lot of assistance in building out this part of our API.
Case in point, by supplying a value of `*` for `fields` , we're saying that we want _all_ of the fields
on site tree. This includes the first level of relationships, as well, as defined on `has_one`, `has_many`,
or `many_many`.
[notice]
Fields on relationships will not inherit the `*` fields selector, and will only expose their ID by default.
[/notice]
The `*` value on `operations` tells the schema to create all available queries and mutations
for the dataobject, including:
* `read`
* `readOne`
* `create`
* `update`
* `delete`
Now that we've changed our schema, we need to build it using the `build-schema` task:
`$ vendor/bin/sake dev/graphql/build schema=default`
Now, we can access our schema on the default graphql endpoint, `/graphql`.
Test it out!
A query:
```graphql
query {
readPages {
nodes {
title
}
}
```
A mutation:
```graphql
mutation {
createPage(input: {
title: "my page"
}) {
title
id
}
}
```
[info]
Did you get a permissions error? Make sure you're authenticated as someone with appropriate access.
[/info]
### Configuring operations
You may not always want to add _all_ operations with the `*` wildcard. You can allow those you
want by setting them to `true` (or `false` to remove them).
**app/_graphql/models.yml**
```
Page:
fields: '*'
operations:
read: true
create: true
```
Operations are also configurable, and accept a nested map of config.
**app/_graphql/models.yml**
```
Page:
fields: '*'
operations:
create: true
read:
name: getAllThePages
```
#### Customising the input types
The input types, specifically in `create` and `update` can be customised with a whitelist
and/or blacklist of fields.
**app/_graphql/models.yml**
```
Page:
fields: '*'
operations:
create:
fields:
title: true
content: true
update:
exclude:
sensitiveField: true
```
### Adding more fields
Let's add some more dataobjects, but this time, we'll only add a subset of fields and operations.
*app/_graphql/models.yml*
```yaml
Page:
fields: '*'
operations: '*'
MyProject\Models\Product:
fields:
onSale: true
title: true
price: true
operations:
delete: true
MyProject\Models\ProductCategory:
fields:
title: true
featured: true
```
[notice]
A couple things to note here:
* By assigning a value of `true` to the field, we defer to the model to infer the type for the field. To override that, we can always add a `type` property:
```yaml
onSale:
type: Boolean
```
* The mapping of our field names to the DataObject property is case-insensitive. It is a
convention in GraphQL APIs to use lowerCamelCase fields, so this is given by default.
[/notice]
### Customising model fields
You don't have to rely on the model to tell you how fields should resolve. Just like
generic types, you can customise them with arguments and resolvers.
*app/_graphql/models.yml*
```yaml
MyProject\Models\Product:
fields:
title:
type: String
resolver: [ 'MyProject\Resolver', 'resolveSpecialTitle' ]
'price(currency: String = "NZD")': true
```
For more information on custom arguments and resolvers, see the [adding arguments](../working_with_generic_types/adding_arguments) and [resolver discovery](../working_with_generic_types/resolver_discovery) documentation.
### Excluding or customising "*" declarations
You can use the `*` as a field or operation, and anything that follows it will override the
all-inclusive collection. This is almost like a spread operator in Javascript:
```js
const newObj = {...oldObj, someProperty: 'custom' }
```
Here's an example:
**app/_graphql/models.yml**
```yaml
Page:
fields:
'*': true # Get everything
sensitiveData: false # hide this field
'content(summaryLength: Int)': true # add an argument to this field
operations:
'*': true
read:
plugins:
paginateList: false # don't paginate the read operation
```
### Model configuration
There are several settings you can apply to your model class (typically `DataObjectModel`),
but because they can have distinct values _per schema_, the standard `_config` layer is not
an option. Model configuration has to be done within the schema config in the `modelConfig`
subsection.
WIP: Add new graphql 4 docs (#9652) * DOCS: Add new graphql 4 docs * Reorganise docs * Docs done * Basic graphql index page * TOC for getting started * show folders on graphql index page * Add middleware note * Docs update * Update docs to reflect flushless schema * Docs updates * Docs for getByLink * Query caching docs * Docs on nested operations * update docs for new graphql dev admin * Docs for configurable operations * Replace readSiteTrees with readPages * Schema defaults docs * Docs for inherited plugins * Docs for customising * * Docs for field whitelisting * Change whitelist word * New docs on modelConfig * Document dev/build extension * Document default/global plugins * Document new input type fields config * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Note about when procedural schema gets built * Fix link * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Note about plugins in custom queries * DOCS Note about filter and custom resolvers * DOCS Note about canview paging * DOCS Updated guidance on _extend See https://github.com/silverstripe/silverstripe-graphql/issues/296 * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Pre-release warning Co-authored-by: Ingo Schommer <ingo@silverstripe.com> Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> Co-authored-by: Ingo Schommer <me@chillu.com>
2020-10-19 23:56:17 +02:00
### Customising the type name
Most DataObject classes are namespaced, so converting them to a type name ends up
being very verbose. As a default, the `DataObjectModel` class will use the "short name"
of your DataObject as its typename (see: `ClassInfo::shortName()`). That is,
`MyProject\Models\Product` becomes `Product`.
Given the brevity of these type names, it's not inconceivable that you could run into naming
collisions, particularly if you use feature-based namespacing. Fortunately, there are
hooks you have available to help influence the typename.
#### The type formatter
The `type_formatter` is a callable that can be set on the `DataObjectModel` config. It takes
the `$className` as a parameter.
Let's turn `MyProject\Models\Product` into the more specific `MyProjectProduct`
*app/_graphql/config.yml*
WIP: Add new graphql 4 docs (#9652) * DOCS: Add new graphql 4 docs * Reorganise docs * Docs done * Basic graphql index page * TOC for getting started * show folders on graphql index page * Add middleware note * Docs update * Update docs to reflect flushless schema * Docs updates * Docs for getByLink * Query caching docs * Docs on nested operations * update docs for new graphql dev admin * Docs for configurable operations * Replace readSiteTrees with readPages * Schema defaults docs * Docs for inherited plugins * Docs for customising * * Docs for field whitelisting * Change whitelist word * New docs on modelConfig * Document dev/build extension * Document default/global plugins * Document new input type fields config * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Note about when procedural schema gets built * Fix link * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Note about plugins in custom queries * DOCS Note about filter and custom resolvers * DOCS Note about canview paging * DOCS Updated guidance on _extend See https://github.com/silverstripe/silverstripe-graphql/issues/296 * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Pre-release warning Co-authored-by: Ingo Schommer <ingo@silverstripe.com> Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> Co-authored-by: Ingo Schommer <me@chillu.com>
2020-10-19 23:56:17 +02:00
```yaml
modelConfig:
DataObject:
type_formatter: ['MyProject\Formatters', 'formatType' ]
WIP: Add new graphql 4 docs (#9652) * DOCS: Add new graphql 4 docs * Reorganise docs * Docs done * Basic graphql index page * TOC for getting started * show folders on graphql index page * Add middleware note * Docs update * Update docs to reflect flushless schema * Docs updates * Docs for getByLink * Query caching docs * Docs on nested operations * update docs for new graphql dev admin * Docs for configurable operations * Replace readSiteTrees with readPages * Schema defaults docs * Docs for inherited plugins * Docs for customising * * Docs for field whitelisting * Change whitelist word * New docs on modelConfig * Document dev/build extension * Document default/global plugins * Document new input type fields config * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Note about when procedural schema gets built * Fix link * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Note about plugins in custom queries * DOCS Note about filter and custom resolvers * DOCS Note about canview paging * DOCS Updated guidance on _extend See https://github.com/silverstripe/silverstripe-graphql/issues/296 * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Pre-release warning Co-authored-by: Ingo Schommer <ingo@silverstripe.com> Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> Co-authored-by: Ingo Schommer <me@chillu.com>
2020-10-19 23:56:17 +02:00
```
[info]
In the above example, `DataObject` is the result of the `DataObjectModel::getIdentifier()`. Each
model class must declare one of these.
[/info]
Your formatting function could look something like:
```php
public static function formatType(string $className): string
{
$parts = explode('\\', $className);
if (count($parts) === 1) {
return $className;
}
$first = reset($parts);
$last = end($parts);
return $first . $last;
}
```
#### The type prefix
You can also add prefixes to all your DataObject types. This can be a scalar value or a callable,
using the same signature as `type_formatter`.
*app/_graphql/config.yml*
WIP: Add new graphql 4 docs (#9652) * DOCS: Add new graphql 4 docs * Reorganise docs * Docs done * Basic graphql index page * TOC for getting started * show folders on graphql index page * Add middleware note * Docs update * Update docs to reflect flushless schema * Docs updates * Docs for getByLink * Query caching docs * Docs on nested operations * update docs for new graphql dev admin * Docs for configurable operations * Replace readSiteTrees with readPages * Schema defaults docs * Docs for inherited plugins * Docs for customising * * Docs for field whitelisting * Change whitelist word * New docs on modelConfig * Document dev/build extension * Document default/global plugins * Document new input type fields config * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Note about when procedural schema gets built * Fix link * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Note about plugins in custom queries * DOCS Note about filter and custom resolvers * DOCS Note about canview paging * DOCS Updated guidance on _extend See https://github.com/silverstripe/silverstripe-graphql/issues/296 * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Pre-release warning Co-authored-by: Ingo Schommer <ingo@silverstripe.com> Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> Co-authored-by: Ingo Schommer <me@chillu.com>
2020-10-19 23:56:17 +02:00
```yaml
modelConfig:
DataObject
type_prefix: 'MyProject'
WIP: Add new graphql 4 docs (#9652) * DOCS: Add new graphql 4 docs * Reorganise docs * Docs done * Basic graphql index page * TOC for getting started * show folders on graphql index page * Add middleware note * Docs update * Update docs to reflect flushless schema * Docs updates * Docs for getByLink * Query caching docs * Docs on nested operations * update docs for new graphql dev admin * Docs for configurable operations * Replace readSiteTrees with readPages * Schema defaults docs * Docs for inherited plugins * Docs for customising * * Docs for field whitelisting * Change whitelist word * New docs on modelConfig * Document dev/build extension * Document default/global plugins * Document new input type fields config * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Note about when procedural schema gets built * Fix link * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Note about plugins in custom queries * DOCS Note about filter and custom resolvers * DOCS Note about canview paging * DOCS Updated guidance on _extend See https://github.com/silverstripe/silverstripe-graphql/issues/296 * Apply suggestions from code review Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> * DOCS Pre-release warning Co-authored-by: Ingo Schommer <ingo@silverstripe.com> Co-authored-by: Andre Kiste <bergice@users.noreply.github.com> Co-authored-by: Ingo Schommer <me@chillu.com>
2020-10-19 23:56:17 +02:00
```
### Further reading
[CHILDREN]