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 scaffolding formfields for model relations #527

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
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
87 changes: 87 additions & 0 deletions en/02_Developer_Guides/00_Model/11_Scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ customise those fields as required.

An example is `DataObject`, Silverstripe CMS will automatically create your CMS interface so you can modify what you need, without having to define all of your form fields from scratch.

Note that the [`SiteTree`](api:SilverStripe\CMS\Model\SiteTree) edit form does not use scaffolded fields.

```php
namespace App\Model;

Expand Down Expand Up @@ -83,6 +85,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, and you can also customise what form field will be used for any given `DataObject` model.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Form fields are also automatically scaffolded for `has_one`, `has_many`, and `many_many` relations. These have sensible default implementations, and you can also customise what form field will be used for any given `DataObject` model.
Form fields are also automatically scaffolded for `has_one`, `has_many`, and `many_many` relations on the form created when editing DataObjects, with the notable exception of the [SiteTree](api:SilverStripe\CMS\Model\SiteTree) edit form. These have sensible default implementations, and you can also customise what form field will be used for any given `DataObject` model.

Copy link
Member Author

@GuySartorelli GuySartorelli Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've put it in the section above this instead, since that isn't something unique to fields scaffolded for relations.


> [!NOTE]
> Polymorphic `has_one` relations do not have scaffolded form fields. Usually these are managed via a `has_many` relation which points at the `has_one` 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
Loading