Skip to content

Commit

Permalink
DOC Document scaffolding formfields for model relations
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Jun 5, 2024
1 parent 1fc1f50 commit f5767a5
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
2 changes: 2 additions & 0 deletions en/02_Developer_Guides/00_Model/02_Relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@ class Company extends DataObject
}
```
For more information see [scaffolding for relations](/developer_guides/model/scaffolding/#scaffolding-for-relations).
## Dot notation {#dot-notation}
To specify multiple `has_many`, `many_many`, `belongs_to`, or `belongs_many_many` relationships to the same model class (and as a general best practice) you can use dot notation to distinguish them like below:
Expand Down
85 changes: 85 additions & 0 deletions en/02_Developer_Guides/00_Model/11_Scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,91 @@ You can also alter the fields of built-in and module `DataObject` classes by imp
> [!NOTE]
> `FormField` scaffolding takes [`$field_labels` config](#field-labels) into account as well.
## Scaffolding for relations

Form fields are also automatically scaffolded for `has_one`, `has_many`, and `many_many` relations. These have sensible default implementations, but you can customise what form field will be used for any given `DataObject` model.

> [!NOTE]
> Polymorphic `has_one` relations do not have scaffolded form fields. Usually these are managed via a `has_many` relation.
With the below example, the following form fields will be scaffolded:

|relation|form field|
|---|---|
|`Child`|`MyCustomField`|
|`HasManyChildren`|`SearchableMultiDropdownField`|
|`ManyManyChildren`|`GridField`|

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
{
// ...
private static array $has_one = [
'Child' => MyChild::class,
];

private static array $has_many = [
'HasManyChildren' => MyChild::class . '.Parent',
];

private static array $many_many = [
'ManyManyChildren' => MyChild::class,
];
}
```

```php
namespace App\Model;

use App\Form\MyCustomField;
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
use SilverStripe\Forms\SearchableMultiDropdownField;
use SilverStripe\ORM\DataObject;

class MyChild extends DataObject
{
// ...
public function scaffoldFormFieldForHasOne(
string $fieldName,
?string $fieldTitle,
string $relationName,
DataObject $ownerRecord
): FormField {
// Return a form field that should be used for selecting this model type for has_one relations.
return MyCustomField::create($fieldName, $fieldTitle);
}

public function scaffoldFormFieldForHasMany(
string $relationName,
?string $fieldTitle,
DataObject $ownerRecord,
bool &$includeInOwnTab
): FormField {
// If this should be in its own tab, set $includeInOwnTab to true, otherwise set it to false.
$includeInOwnTab = false;
// Return a form field that should be used for selecting this model type for has_many relations.
return SearchableMultiDropdownField::create($relationName, $fieldTitle, static::get());
}

public function scaffoldFormFieldForManyMany(
string $relationName,
?string $fieldTitle,
DataObject $ownerRecord,
bool &$includeInOwnTab
): FormField {
// The default implementation for this method returns a GridField, which we can modify.
$gridField = parent::scaffoldFormFieldForManyMany($relationName, $fieldTitle, $ownerRecord, $includeInOwnTab);
$gridField->getConfig()->removeComponentsByType(GridFieldAddExistingAutocompleter::class);
return $gridField;
}
}
```

## Searchable fields

The `$searchable_fields` property uses a mixed array format that can be used to further customise your generated admin
Expand Down
25 changes: 25 additions & 0 deletions en/08_Changelogs/5.3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ title: 5.3.0 (unreleased)
- [Features and enhancements](#features-and-enhancements)
- [High-level API for converting files](#file-converter)
- [Validation for elemental content blocks when saving individual blocks](#elemental-validation)
- [Define scaffolded form fields for relations to `DataObject` models](#scaffolded-relation-formfields)
- [Support for `JOIN` in SQL `UPDATE`](#sql-update-join)
- [Other new features](#other-new-features)
- [Bug fixes](#bug-fixes)
Expand Down Expand Up @@ -56,6 +57,30 @@ Elemental content blocks now support validation when saving or publishing indivi

Validation can be added to a content block using standard [Model Validation and Constraints](https://docs.silverstripe.org/en/5/developer_guides/model/validation/#validation-and-constraints) by implementing a [`DataObject::validate()`](api:SilverStripe\ORM\DataObject::validate()) method on a content block, or by using [Form Validation](https://docs.silverstripe.org/en/5/developer_guides/forms/validation/#form-validation) where there are several options available.

### Define scaffolded form fields for relations to `DataObject` models {#scaffolded-relation-formfields}

Most `DataObject` classes will rely on some amount of automatic scaffolding of form fields in their [`getCMSFields()`](api:SilverStripe\ORM\DataObject::getCMSFields()) implementations. However, it's common for modules to provide a specialised form field which is intended to always be used with a specific `DataObject` class. In those cases, even though you always want to use that form field with that class, you have to copy some boilerplate code from the module's documentation to set it up.

You can now define what form fields should be used when scaffolding form fields for `has_one`, `has_many`, and `many_many` relations. This is defined on the class on the child-side of the relationship. For example, for the below `has_one` relation you would implement [`scaffoldFormFieldForHasOne()`](api:SilverStripe\ORM\DataObject::scaffoldFormFieldForHasOne()) on the `MyChild` class.

```php
namespace App\Model;

use SilverStripe\ORM\DataObject;

class MyParent extends DataObject
{
// ...
private static array $has_one = [
'MyChild' => MyChild::class,
];
}
```

This means modules can pre-define the form field that should be used for their custom models, which reduces the amount of boilerplate code developers need to include in their `getCMSFields()` implementations.

For more information see [scaffolding for relations](/developer_guides/model/scaffolding/#scaffolding-for-relations).

### Support for `JOIN` in SQL `UPDATE` {#sql-update-join}

The [`SQLUpdate`](api:SilverStripe\ORM\Queries\SQLUpdate) class now supports all of the same `JOIN` operations (using the same methods) that [`SQLSelect`](api:SilverStripe\ORM\Queries\SQLSelect) does.
Expand Down

0 comments on commit f5767a5

Please # to comment.