Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOC Document multi-reciprocal has_one relations #417

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions en/02_Developer_Guides/00_Model/02_Relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,70 @@ be necessary. For example additional parent classes for each respective relation
duplication of code.
[/warning]

### Multi-relational `has_one` {#multi-relational-has-one}

A single `has_one` relation can be allowed to manage multiple `has_many` relations - this is especially useful
in situations like adding multiple lists of links to a [`SiteConfig`](api:SilverStripe\SiteConfig\SiteConfig) to build a menu.

An additional column is created called `<relationship-name>Relation`, along with the `<relationship-name>Class`
and `<relationship-name>ID` columns of a normal polymorphic `has_one` relation.

[warning]
If you save records into the `has_one` relation programatically, you must set the relation in the
`<relationship-name>Relation` field, or it won't be included when you fetch the `has_many` relation list.

Generally it is better to instead add the record with the `has_one` relation into its corresponding `has_many` relation
directly - see [adding relations](#adding-relations).
[/warning]

To specify that a `has_one` relation is multi-relational define the relation like so:

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectSchema;

class Fan extends DataObject
{
// ...

private static array $has_one = [
'FanOf' => [
// The class here is the class for the has_one - it must be polymorphic.
'class' => DataObject::class,
// Setting this to true is what defines this has_one relation as multi-relational
DataObjectSchema::HAS_ONE_MULTI_RELATIONAL => true,
],
];
}
```

[hint]
Multi-relational `has_one` relations *must* be [polymorphic](#polymorphic-has-one).
[/hint]

It is best practice for your `has_many` relations to indicate which relation they're pointing at using dot notation. For example:

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;

class Team extends DataObject
{
// ...

private static array $has_many = [
// Notice that these are both pointing at the same has_one relation!
'CheapFans' => Fan::class . '.FanOf',
'VipFans' => Fan::class . '.FanOf',
];
}
```

See [`has_many`](#has_many) below for more details about `has_many` relations.

### `belongs_to`

Defines a one-to-one relationship with another object, which declares the other end of the relationship with a
Expand Down Expand Up @@ -215,6 +279,8 @@ SilverStripe\Assets\Image:
Team: App\Model\Team
```
You can point multiple `has_many` relations at a single `has_one` relation if you use a [multi-relational `has_one`](#multi-relational-has-one).

Note that in some cases you may be better off using a `many_many` relation instead. Carefully consider whether you are defining a "one-to-many" or a "many-to-many" relationship.
[/alert]

Expand Down
41 changes: 41 additions & 0 deletions en/04_Changelogs/5.2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,47 @@ title: 5.2.0 (unreleased)

This release comes jampacked with new ORM features, granting you access to some new abstractions for more powerful and efficient queries.

#### Multi-relational `has_one` relations

Traditionally, if you wanted to have multiple `has_many` relations for the same class, you would have to include a separate `has_one` relation for *each* `has_many` relation.

This release includes a new `has_one` syntax to declare that your `has_one` should be allowed to handle multiple reciprocal `has_many` relations. The syntax for that is as follows:

[hint]
Multi-relational `has_one` relations *must* be polymorphic.
[/hint]

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectSchema;

class MyExample extends DataObject
{
// ...

private static array $has_one = [
'MyMultiRelationalRelation' => [
// The class here is the class for the has_one - it must be polymorphic.
'class' => DataObject::class,
// Setting this to true is what defines this has_one relation as multi-relational
DataObjectSchema::HAS_ONE_MULTI_RELATIONAL => true,
],
];
}
```

Multiple `has_many` relations on a single class can point to the above `has_one` relation, and they will be correctly saved and resolved when you get the relation list.

[warning]
This new feature means sometimes the value in the associative `has_one` configuration array will be an array, rather than a class name.
If you are relying on fetching this configuration to find the class names of `has_one` relations, consider using
[`DataObject::hasOne()`](api:SilverStripe\ORM\DataObject::hasOne()) or [`DataObjectSchema::hasOneComponent()`](api:SilverStripe\ORM\DataObjectSchema::hasOneComponent()) instead.
[/warning]

See [multi-relational `has_one` in the relations docs](/developer_guides/model/relations/#multi-relational-has-one) for more details about this relation type.

#### UNION clause {#orm-union-clause}

Abstractions for the SQL `UNION` clause have been added to `SQLSelect` and `DataQuery`.
Expand Down