Skip to content

Commit

Permalink
DOCS: improve graphql inheritance docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Carlino committed Jun 30, 2021
1 parent 0537e76 commit 2932084
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 70 deletions.
47 changes: 0 additions & 47 deletions .idea/workspace.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ But what about when we want more than `title` and `content`? In some cases, we'l
query {
readPages {
nodes {
title
content
title # Common field
content # Common field
... on HomePage {
heroImage {
url
Expand All @@ -98,22 +98,23 @@ that only appear on some types, we need to be explicit.
But let's take this a step further. What if there's another class in between? Imagine this ancestry:

```
Page:
EventPage:
ConferencePage
WebinarPage
Page
-> EventPage
-> ConferencePage
-> WebinarPage
```

We can use the intermediary interface `EventPageInterface` to consolidate fields that are unique to
`ConferencePage` and `WebinarPage`.

```
```graphql
query {
readPages {
nodes {
title
content
title # Common to all types
content # Common to all types
... on EventPageInterface {
# Common fields for WebinarPage, ConferencePage, EventPage
numberOfTickets
featuredSpeaker {
firstName
Expand Down Expand Up @@ -147,10 +148,12 @@ which is usually the parent class with the "Interface" suffix.

### Inheritance: A deep dive

There are two components to the way inheritance is handled at build time:
There are several ways inheritance is handled at build time:

* Implicit field / type exposure
* Interface generation and assignment to types
* Interface generation
* Assignment of generated interfaces to types
* Assignment of generated interfaces to queries

We'll look at each of these in detail.

Expand Down Expand Up @@ -180,7 +183,7 @@ GalleryPage:

This results in these two types being exposed with the fields as shown, but also results in a `Page` type:

```
```graphql
type Page {
id: ID! # always exposed
title: String
Expand All @@ -189,7 +192,7 @@ type Page {
}
```

#### Interface generation and assignment to types
#### Interface generation

Any type that's part of an inheritance chain will generate interfaces. Each applicable ancestral interface is added
to the type. Like the type inheritance pattern shown above, interfaces duplicate fields from their ancestors as well.
Expand All @@ -202,16 +205,16 @@ All of this is serviced by: `SilverStripe\GraphQL\Schema\DataObject\InterfaceBui
##### Example

```
Page:
BlogPage extends Page
EventsPage extends Page
ConferencePage extends EventsPage
WebinarPage extends EventsPage
Page
-> BlogPage extends Page
-> EventsPage extends Page
-> ConferencePage extends EventsPage
-> WebinarPage extends EventsPage
```

This will create the following interfaces:

```
```graphql
interface PageInterface {
title: String
content: String
Expand Down Expand Up @@ -249,9 +252,11 @@ interface WebinarPageInterface {
}
```

Types then get these interfaces applied, like so:
#### Interface assignment to types

```
The generated interfaces then get applied to the appropriate types, like so:

```graphql
type Page implements PageInterface {}
type BlogPage implements BlogPageInterface & PageInterface {}
type EventsPage implements EventsPageInterface & PageInterface {}
Expand All @@ -261,17 +266,46 @@ type WebinarPage implements WebinarPageInterface & EventsPageInterface & PageInt

Lastly, for good measure, we create a `DataObjectInterface` that applies to everything.

```
```graphql
interface DataObjectInterface {
id: ID!
# Any other fields you've explicitly exposed in config.modelConfig.DataObject.base_fields
}
```

```
```graphql
type Page implements PageInterface & DataObjectInterface {}
```

#### Interface assignment to queries

Queries, both at the root, and nested as fields on types, will have their types
updated if they refer to a type that has had any generated interfaces added to it.

```graphql
type Query {
readPages: [Page]
}

type BlogPage {
download: File
}
```

Becomes:

```graphql
type Query {
readPages: [PageInterface]
}

type BlogPage {
download: FileInterface
}
```

All of this is serviced by: `SilverStripe\GraphQL\Schema\DataObject\InterfaceBuilder`

#### Elemental

Almost by definition, content blocks are always abstractions. You're never going to query for a `BaseElement` type
Expand Down

0 comments on commit 2932084

Please sign in to comment.