Skip to content

Commit

Permalink
DOC Document SiteTree form field scaffolding (#550)
Browse files Browse the repository at this point in the history
Also updates best practices around scaffolding form fields.
  • Loading branch information
GuySartorelli authored Aug 15, 2024
1 parent fbc67af commit 097a664
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 122 deletions.
28 changes: 15 additions & 13 deletions en/02_Developer_Guides/00_Model/10_Versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ This can also be manually enabled for a single `GridField` by passing the `Versi
namespace {
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
use SilverStripe\Forms\GridField\GridFieldDetailForm;
Expand All @@ -564,16 +565,15 @@ namespace {
{
public function getCMSFields()
{
$fields = parent::getCMSFields();
$config = GridFieldConfig_RelationEditor::create();
$config
->getComponentByType(GridFieldDetailForm::class)
->setItemRequestClass(VersionedGridFieldItemRequest::class);
$gridField = GridField::create('Items', 'Items', $this->Items(), $config);
$fields->addFieldToTab('Root.Items', $gridField);
return $fields;
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$config = GridFieldConfig_RelationEditor::create();
$config
->getComponentByType(GridFieldDetailForm::class)
->setItemRequestClass(VersionedGridFieldItemRequest::class);
$gridField = GridField::create('Items', 'Items', $this->Items(), $config);
$fields->addFieldToTab('Root.Items', $gridField);
});
return parent::getCMSFields();
}
}
}
Expand Down Expand Up @@ -1404,13 +1404,15 @@ Then you can add the [HistoryViewerField](api:SilverStripe\VersionedAdmin\Forms\
fields in the same way as any other form field:

```php
use SilverStripe\Forms\FieldList;
use SilverStripe\VersionedAdmin\Forms\HistoryViewerField;
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.History', HistoryViewerField::create('MyObjectHistory'));
return $fields;
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab('Root.History', HistoryViewerField::create('MyObjectHistory'));
});
return parent::getCMSFields();
}
```

Expand Down
12 changes: 7 additions & 5 deletions en/02_Developer_Guides/00_Model/11_Scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Note that the [`SiteTree`](api:SilverStripe\CMS\Model\SiteTree) edit form does n
```php
namespace App\Model;

use SilverStripe\Forms\FieldList;
use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
Expand All @@ -32,17 +33,18 @@ class MyDataObject extends DataObject

public function getCMSFields()
{
// parent::getCMSFields() does all the hard work and creates the fields for Title, IsActive and Content.
$fields = parent::getCMSFields();
$fields->dataFieldByName('IsActive')->setTitle('Is active?');
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->dataFieldByName('IsActive')->setTitle('Is active?');
});

return $fields;
// parent::getCMSFields() does all the hard work and creates the fields for Title, IsActive and Content.
return parent::getCMSFields();
}
}
```

> [!TIP]
> It is typically considered a good practice to wrap your modifications in a call to [`beforeUpdateCMSFields()`](api:SilverStripe\ORM\DataObject::beforeUpdateCMSFields()) - the `updateCMSFields()` extension hook is already triggered by `parent::getCMSFields()`, so this is how you ensure any new fields are added before extensions update your fieldlist.
> It is typically considered a good practice to wrap your modifications in a call to [`beforeUpdateCMSFields()`](api:SilverStripe\ORM\DataObject::beforeUpdateCMSFields()) - the `updateCMSFields()` extension hook is triggered by `parent::getCMSFields()`, so this is how you ensure any new fields are added before extensions update your fieldlist.
To define the form fields yourself without using scaffolding, use the `mainTabOnly` option in [`DataObject.scaffold_cms_fields_settings`](api:SilverStripe\ORM\DataObject->scaffold_cms_fields_settings). See [scaffolding options](#scaffolding-options) for details.

Expand Down
14 changes: 8 additions & 6 deletions en/02_Developer_Guides/03_Forms/01_Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ namespace App\PageType;

use Page;
use SilverStripe\Forms\CompositeValidator;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\RequiredFields;
use SilverStripe\Forms\TextField;

Expand All @@ -371,12 +372,13 @@ class MyPage extends Page

public function getCMSFields()
{
$fields = parent::getCMSFields();

$fields->addFieldToTab(
'Root.Main',
TextField::create('MyRequiredField')->setCustomValidationMessage('You missed me.')
);
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab(
'Root.Main',
TextField::create('MyRequiredField')->setCustomValidationMessage('You missed me.')
);
});
return parent::getCMSFields();
}

public function getCMSCompositeValidator(): CompositeValidator
Expand Down
16 changes: 8 additions & 8 deletions en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace App\PageType;

use Page;
use SilverStripe\Forms\DateField;
use SilverStripe\Forms\FieldList;

class MyPage extends Page
{
Expand All @@ -29,14 +30,13 @@ class MyPage extends Page

public function getCMSFields()
{
$fields = parent::getCMSFields();

$fields->addFieldToTab(
'Root.Main',
DateField::create('MyDate', 'Enter a date')
);

return $fields;
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab(
'Root.Main',
DateField::create('MyDate', 'Enter a date')
);
});
return parent::getCMSFields();
}
}
```
Expand Down
27 changes: 20 additions & 7 deletions en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ class MyObject extends DataObject

public function getCMSFields()
{
return FieldList::create(
HTMLEditorField::create('Content')
);
$this->beforeUpdateCMSFields(function (FieldList $fields) {
// Note that this field would be scaffolded automatically,
// we're only adding it here for demonstration purposes.
$fields->addFieldToTab('Root.Main', HTMLEditorField::create('Content'));
});
return parent::getCMSFields();
}
}
```
Expand Down Expand Up @@ -64,12 +67,22 @@ class MyObject extends DataObject
'OtherContent' => 'HTMLText',
];

private static array $scaffold_cms_fields_settings = [
'ignoreFields' => [
'OtherContent',
],
];

public function getCMSFields()
{
return FieldList::create([
HTMLEditorField::create('Content'),
HTMLEditorField::create('OtherContent', 'Other content', $this->OtherContent, 'myConfig'),
]);
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab(
'Root.Main',
HTMLEditorField::create('OtherContent', 'Other content', $this->OtherContent, 'myConfig'),
'Content'
);
});
return parent::getCMSFields();
}
}
```
Expand Down
107 changes: 57 additions & 50 deletions en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@ namespace App\PageType;

use Page;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;

class MyPage extends Page
{
// ...

public function getCMSFields()
{
$fields = parent::getCMSFields();

$fields->addFieldToTab(
'Root.Pages',
GridField::create('Pages', 'All pages', SiteTree::get())
);
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab(
'Root.Pages',
GridField::create('Pages', 'All pages', SiteTree::get())
);
});

return $fields;
return parent::getCMSFields();
}
}
```
Expand All @@ -69,35 +72,38 @@ namespace App\PageType;

use Page;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldDataColumns;

class MyPage extends Page
{
// ...

public function getCMSFields()
{
$fields = parent::getCMSFields();

$fields->addFieldToTab(
'Root.Pages',
$grid = GridField::create('Pages', 'All pages', SiteTree::get())
);
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab(
'Root.Pages',
$grid = GridField::create('Pages', 'All pages', SiteTree::get())
);

// GridField configuration
$config = $grid->getConfig();
// GridField configuration
$config = $grid->getConfig();

// Modification of existing components can be done by fetching that component.
// Consult the API documentation for each component to determine the configuration
// you can do.
$dataColumns = $config->getComponentByType(GridFieldDataColumns::class);
// Modification of existing components can be done by fetching that component.
// Consult the API documentation for each component to determine the configuration
// you can do.
$dataColumns = $config->getComponentByType(GridFieldDataColumns::class);

$dataColumns->setDisplayFields([
'Title' => 'Title',
'Link' => 'URL',
'LastEdited' => 'Changed',
]);
$dataColumns->setDisplayFields([
'Title' => 'Title',
'Link' => 'URL',
'LastEdited' => 'Changed',
]);
});

return $fields;
return parent::getCMSFields();
}
}
```
Expand Down Expand Up @@ -373,6 +379,7 @@ class Team extends DataObject
```php
namespace App\Model;

use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
use SilverStripe\Forms\GridField\GridFieldDataColumns;
Expand All @@ -398,31 +405,31 @@ class Player extends DataObject

public function getCMSFields()
{
$fields = parent::getCMSFields();

if ($this->ID) {
$singletonTeam = singleton(Team::class);
$teamEditFields = $singletonTeam->getCMSFields();
$teamEditFields->addFieldToTab(
'Root.Main',
// The "ManyMany[<extradata-name>]" convention is necessary here, because this will be passed
// into the GridFieldDetailForm
TextField::create('ManyMany[Position]', 'Current Position')
);

// For summary fields, the "ManyMany[<extradata-name>]" convention won't work (and isn't necessary),
// since this isn't passed into the GridFieldDetailForm
$teamSummaryFields = array_merge($singletonTeam->summaryFields(), ['Position' => 'Current Position']);

$config = GridFieldConfig_RelationEditor::create();
$config->getComponentByType(GridFieldDetailForm::class)->setFields($teamEditFields);
$config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($teamSummaryFields);

$gridField = GridField::create('Teams', 'Teams', $this->Teams(), $config);
$fields->findOrMakeTab('Root.Teams')->replaceField('Teams', $gridField);
}

return $fields;
$this->beforeUpdateCMSFields(function (FieldList $fields) {
if ($this->ID) {
$singletonTeam = singleton(Team::class);
$teamEditFields = $singletonTeam->getCMSFields();
$teamEditFields->addFieldToTab(
'Root.Main',
// The "ManyMany[<extradata-name>]" convention is necessary here, because this will be passed
// into the GridFieldDetailForm
TextField::create('ManyMany[Position]', 'Current Position')
);

// For summary fields, the "ManyMany[<extradata-name>]" convention won't work (and isn't necessary),
// since this isn't passed into the GridFieldDetailForm
$teamSummaryFields = array_merge($singletonTeam->summaryFields(), ['Position' => 'Current Position']);

$config = GridFieldConfig_RelationEditor::create();
$config->getComponentByType(GridFieldDetailForm::class)->setFields($teamEditFields);
$config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($teamSummaryFields);

$gridField = GridField::create('Teams', 'Teams', $this->Teams(), $config);
$fields->findOrMakeTab('Root.Teams')->replaceField('Teams', $gridField);
}
});

return parent::getCMSFields();
}
}
```
Expand Down
3 changes: 2 additions & 1 deletion en/02_Developer_Guides/05_Extending/01_Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ Example 2: User code can intervene in the process of extending CMS fields.
```php
namespace App\Model;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataObject;
Expand All @@ -397,7 +398,7 @@ class MyModel extends DataObject
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function ($fields) {
$this->beforeUpdateCMSFields(function (FieldList $fields) {
// Include field which must be present when updateCMSFields is called on extensions
$fields->addFieldToTab('Root.Main', TextField::create('Detail', 'Details', null, 255));
});
Expand Down
14 changes: 8 additions & 6 deletions en/02_Developer_Guides/09_Security/00_Member.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ Note that if you want to look this class-name up, you can call `Injector::inst()

If you override the built-in public function getCMSFields(), then you can change the form that is used to view & edit member
details in the newsletter system. This function returns a [FieldList](api:SilverStripe\Forms\FieldList) object. You should generally start by calling
parent::getCMSFields() and manipulate the [FieldList](api:SilverStripe\Forms\FieldList) from there.
`$this->beforeUpdateCMSFields()` and manipulate the [FieldList](api:SilverStripe\Forms\FieldList) from there.

```php
namespace App\Security;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\Security\Member;
Expand All @@ -78,11 +79,12 @@ class MyMember extends Member
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->insertBefore('HTMLEmail', TextField::create('Age'));
$fields->removeByName('JobTitle');
$fields->removeByName('Organisation');
return $fields;
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->insertBefore('HTMLEmail', TextField::create('Age'));
$fields->removeByName('JobTitle');
$fields->removeByName('Organisation');
});
return parent::getCMSFields();
}
}
```
Expand Down
Loading

0 comments on commit 097a664

Please sign in to comment.