mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
DOCS: Bulk loader graphql docs (#10203)
* DOCS: Bulk loader graphql docs * Add code example, add module syntax
This commit is contained in:
parent
fc707cc10d
commit
5bb203e16a
@ -118,6 +118,8 @@ types:
|
|||||||
# your generic types here
|
# your generic types here
|
||||||
models:
|
models:
|
||||||
# your dataobjects here
|
# your dataobjects here
|
||||||
|
bulkLoad:
|
||||||
|
# your bulk loader directives here
|
||||||
queries:
|
queries:
|
||||||
# your queries here
|
# your queries here
|
||||||
mutations:
|
mutations:
|
||||||
@ -154,6 +156,11 @@ be implicitly placed in the corresponding section of the schema.
|
|||||||
# my type definitions here
|
# my type definitions here
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**app/_graphql/bulkLoad/bulkLoad.yml**
|
||||||
|
```yaml
|
||||||
|
# my bulk loader directives here
|
||||||
|
```
|
||||||
|
|
||||||
##### Namespacing by filename
|
##### Namespacing by filename
|
||||||
|
|
||||||
If the filename is named one of the four keywords above, it will be implicitly placed
|
If the filename is named one of the four keywords above, it will be implicitly placed
|
||||||
@ -168,6 +175,12 @@ in the corresponding section of the schema. **This only works in the root source
|
|||||||
```yaml
|
```yaml
|
||||||
# my models here
|
# my models here
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**app/_graphql/bulkLoad.yml**
|
||||||
|
```yaml
|
||||||
|
# my bulk loader directives here
|
||||||
|
```
|
||||||
|
|
||||||
#### Going even more granular
|
#### Going even more granular
|
||||||
|
|
||||||
These special directories can contain multiple files that will all merge together, so you can even
|
These special directories can contain multiple files that will all merge together, so you can even
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: The DataObject model type
|
title: Adding DataObjects to the schema
|
||||||
summary: An overview of how the DataObject model can influence the creation of types, queries, and mutations
|
summary: An overview of how the DataObject model can influence the creation of types, queries, and mutations
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -199,6 +199,132 @@ convention in GraphQL APIs to use lowerCamelCase fields, so this is given by def
|
|||||||
|
|
||||||
[/notice]
|
[/notice]
|
||||||
|
|
||||||
|
### Bulk loading models
|
||||||
|
|
||||||
|
It's likely that in your application, you have a whole collection of classes you want exposed to the API, with roughly
|
||||||
|
the same fields and operations exposed on them. It can be really tedious to write a new declaration for every single
|
||||||
|
dataobject in your project, and as you add new ones, there's a bit of overhead in remembering to add it to the
|
||||||
|
GraphQL schema.
|
||||||
|
|
||||||
|
Common use cases might be:
|
||||||
|
|
||||||
|
* Add everything in `App\Models`
|
||||||
|
* Add every implementation of `BaseElement`
|
||||||
|
* Add anything with the `Versioned` extension
|
||||||
|
* Add everything that matches `src/*Model.php`
|
||||||
|
|
||||||
|
You can create logic like this using the `bulkLoad` configuration file, which allows you to specify groups of directives
|
||||||
|
that load a bundle of classes and apply the same set of configuration to all of them.
|
||||||
|
|
||||||
|
|
||||||
|
**_graphql/bulkLoad.yml**
|
||||||
|
```yaml
|
||||||
|
elemental: # An arbitrary key to define what these directives are doing
|
||||||
|
# Load all content blocks
|
||||||
|
load:
|
||||||
|
inheritanceLoader:
|
||||||
|
include:
|
||||||
|
- DNADesign\Elemental\Models\BaseElement
|
||||||
|
exclude:
|
||||||
|
- MyApp\Elements\MySecretElement
|
||||||
|
# Add all fields and read operations
|
||||||
|
apply:
|
||||||
|
fields:
|
||||||
|
'*': true
|
||||||
|
operations:
|
||||||
|
read: true
|
||||||
|
readOne: true
|
||||||
|
app:
|
||||||
|
# Load everything in our app that has the Versioned extension
|
||||||
|
load:
|
||||||
|
namespaceLoader:
|
||||||
|
include:
|
||||||
|
- MyApp\Models\*
|
||||||
|
extensionLoader:
|
||||||
|
include:
|
||||||
|
- SilverStripe\Versioned\Versioned
|
||||||
|
filepathLoader:
|
||||||
|
exclude:
|
||||||
|
- app/src/Models/*.secret.php
|
||||||
|
apply:
|
||||||
|
fields:
|
||||||
|
'*': true
|
||||||
|
operations:
|
||||||
|
'*': true
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, four loaders are provided to you to help gather specific classnames:
|
||||||
|
|
||||||
|
#### By namespace
|
||||||
|
* **Identifier**: `namespaceLoader`
|
||||||
|
* **Description**: Include or exclude classes based on their namespace
|
||||||
|
* **Example**: `include: [MyApp\Models\*]`
|
||||||
|
|
||||||
|
#### By inheritance
|
||||||
|
|
||||||
|
* **Identifier**: `inheritanceLoader`
|
||||||
|
* **Description**: Include or exclude everything that matches or extends a given base class
|
||||||
|
* **Example**: `include: [DNADesign\Elemental\Models\BaseElement]`
|
||||||
|
|
||||||
|
#### By applied extension
|
||||||
|
|
||||||
|
* **Identifier**: `extensionLoader`
|
||||||
|
* **Description**: Include or exclude any class that has a given extension applied
|
||||||
|
* **Example**: `include: [SilverStripe\Versioned\Versioned]`
|
||||||
|
|
||||||
|
#### By filepath
|
||||||
|
|
||||||
|
* **Identifier**: `filepathLoader`
|
||||||
|
* **Description**: Include or exclude any classes in files matching a given glob expression, relative to the base path. Module syntax is allowed.
|
||||||
|
* **Examples**:
|
||||||
|
- `include: [ 'src/models/*.model.php' ]`
|
||||||
|
- `include: [ 'somevendor/somemodule: src/Models/*.php' ]`
|
||||||
|
|
||||||
|
Each block starts with a collection of all classes that gets filtered as each loader runs. The primary job
|
||||||
|
of a loader is to _remove_ classes from the entire collection, not add them in.
|
||||||
|
|
||||||
|
[info]
|
||||||
|
`exclude` directives will always supersede `include` directives.
|
||||||
|
[/info]
|
||||||
|
|
||||||
|
[info]
|
||||||
|
If you find that this paints with too big a brush, you can always override individual models explicitly in `models.yml`.
|
||||||
|
The bulk loaders run _before_ the models.yml config is loaded.
|
||||||
|
[/info]
|
||||||
|
|
||||||
|
#### DataObjects subclasses are the default starting point
|
||||||
|
|
||||||
|
Because this is Silverstripe CMS, and it's likely that you're using dataobject models only, the bulk loaders start with an
|
||||||
|
initial filter, which is defined as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
inheritanceLoader:
|
||||||
|
include:
|
||||||
|
- SilverStripe\ORM\DataObject
|
||||||
|
```
|
||||||
|
|
||||||
|
This ensures that at a bare minimum, you're always filtering by dataobject classes only. If, for some reason, you
|
||||||
|
have a non-dataobject class in `App\Models\*`, it will automatically be filtered out due to this default setting.
|
||||||
|
|
||||||
|
This default is configured in the `defaultBulkLoad` setting in your schema config. Should you ever want to disable
|
||||||
|
that, just set it to `false`.
|
||||||
|
|
||||||
|
**_graphql/config.yml**
|
||||||
|
```
|
||||||
|
defaultBulkLoad: false
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Creating your own bulk loader
|
||||||
|
|
||||||
|
Bulk loaders must extend `SilverStripe\GraphQL\Schema\BulkLoader\AbstractBulkLoader`. They need to declare an
|
||||||
|
identifier (e.g. `namespaceLoader`) to be referenced in the config, and they must provide a
|
||||||
|
`collect(Collection $collection): Collection` which returns a new `Collection` instance once the loader has done its
|
||||||
|
work parsing through the `include` and `exclude` directives.
|
||||||
|
|
||||||
|
Bulk loaders are automatically registered. Just creating the class is all you need to do to have it available for use
|
||||||
|
in your `bulkLoad.yml` file.
|
||||||
|
|
||||||
|
|
||||||
### Customising model fields
|
### Customising model fields
|
||||||
|
|
||||||
You don't have to rely on the model to tell you how fields should resolve. Just like
|
You don't have to rely on the model to tell you how fields should resolve. Just like
|
||||||
@ -241,9 +367,9 @@ Page:
|
|||||||
paginateList: false # don't paginate the read operation
|
paginateList: false # don't paginate the read operation
|
||||||
```
|
```
|
||||||
|
|
||||||
### Blacklisted fields {#blacklisted-fields}
|
### Disallowed fields {#disallowed-fields}
|
||||||
|
|
||||||
While selecting all fields via `*` is usedful, there are some fields that you
|
While selecting all fields via `*` is useful, there are some fields that you
|
||||||
don't want to accidentally expose, especially if you're a module author
|
don't want to accidentally expose, especially if you're a module author
|
||||||
and expect models within this code to be used through custom GraphQL endpoints.
|
and expect models within this code to be used through custom GraphQL endpoints.
|
||||||
For example, a module might add a secret "preview token" to each `SiteTree`.
|
For example, a module might add a secret "preview token" to each `SiteTree`.
|
||||||
@ -251,8 +377,8 @@ A custom GraphQL endpoint might have used `fields: '*'` on `SiteTree` to list pa
|
|||||||
on the public site, which now includes a sensitive field.
|
on the public site, which now includes a sensitive field.
|
||||||
|
|
||||||
The `graphql_blacklisted_fields` property on `DataObject` allows you to
|
The `graphql_blacklisted_fields` property on `DataObject` allows you to
|
||||||
blacklist fields globally for all GraphQL schemas.
|
disallow fields globally for all GraphQL schemas.
|
||||||
This blacklist applies for all operations (read, update, etc).
|
This block list applies for all operations (read, update, etc).
|
||||||
|
|
||||||
**app/_config/graphql.yml**
|
**app/_config/graphql.yml**
|
||||||
```yaml
|
```yaml
|
Loading…
Reference in New Issue
Block a user