Skip to content

Commit 35099c9

Browse files
committed
DOC Document new ChildFieldManager interface
1 parent 19ade0a commit 35099c9

File tree

2 files changed

+97
-2
lines changed

2 files changed

+97
-2
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
title: ChildFieldManager
3+
summary: Strict management of child fields for advanced use cases
4+
---
5+
6+
# `ChildFieldManager`
7+
8+
In most cases, child form fields can be grouped with a [`CompositeField`](api:SilverStripe\Forms\CompositeField) or one of its subclasses - but sometimes you need more control.
9+
10+
For example, you may have a use case where specific form fields *must* be present in the child field list. In that case you won't want methods like [`FieldList::removeByName()`](api:SilverStripe\Forms\FieldList::removeByName()) or [`FieldList::replaceField()`](api:SilverStripe\Forms\FieldList::replaceField()) to know about your child fields, but you'll still want to expose them for things like [`Form::loadDataFrom()`](api:SilverStripe\Forms\Form::loadDataFrom()), [`Form::saveInto()`](api:SilverStripe\Forms\Form::saveInto()), and allow them to manage their own AJAX requests.
11+
12+
To achieve this, your custom [`FormField`](api:SilverStripe\Forms\FormField) can implement the [`ChildFieldManager`](api:SilverStripe\Forms\ChildFieldManager) interface. The methods declared in this interface allow the form to access your fields for critical functionality, but doesn't let anyone remove or replace fields in your managed child field list.
13+
14+
In order to get managed fields from a `FieldList`, call [`FieldList::getDataFields(true)`](api:SilverStripe\Forms\FieldList::getDataFields()).This method replaces the now deprecated [`FieldList::dataFields()`](api:SilverStripe\Forms\FieldList::dataFields()) method.
15+
16+
Calling `FieldList::getDataFields()` with no arguments, or passing in `false` explicitly, is the same as calling the old `FieldList::dataFields()` method. If you pass in `true`, that differs in two ways:
17+
18+
1. It gets all data fields *including* those managed by a `ChildFieldManager`, which are excluded when passing `false`
19+
1. Fields returned from a `ChildFieldManager` are not cached. This allows child field managers to swap out the form field implementation if their logic requires it.
20+
21+
A very simple implementation of this interface would look like this:
22+
23+
> [!WARNING]
24+
> The below example shows a minimal PHP implementation but not the template.
25+
> The assumption is if you're implementing this interface, you already have an advanced use case and know what you need to do in your template to get your use case broadly working.
26+
27+
```php
28+
namespace App\Form;
29+
30+
use SilverStripe\Core\Validation\FieldValidation\CompositeFieldValidator;
31+
use SilverStripe\Forms\ChildFieldManager;
32+
use SilverStripe\Forms\FormField;
33+
use SilverStripe\Forms\TextField;
34+
35+
class MyChildFieldManager extends FormField implements ChildFieldManager
36+
{
37+
private static array $field_validators = [
38+
CompositeFieldValidator::class,
39+
];
40+
41+
private array $children = [];
42+
43+
public function __construct()
44+
{
45+
$this->children = [
46+
'FieldOne' => TextField::create('FieldOne'),
47+
'FieldTwo' => TextField::create('FieldTwo'),
48+
];
49+
parent::__construct('MyManagedField');
50+
}
51+
52+
public function isManagedField(string $fieldName): bool
53+
{
54+
return array_key_exists($fieldName, $this->children);
55+
}
56+
57+
public function getManagedFieldByName(string $fieldName): ?FormField
58+
{
59+
return $this->children[$fieldName] ?? null;
60+
}
61+
62+
public function getManagedFields(): iterable
63+
{
64+
return $this->children;
65+
}
66+
67+
public function getValueForValidation(): mixed
68+
{
69+
// Ensure child fields get validated by the CompositeFieldValidator
70+
return $this->children;
71+
}
72+
73+
public function getSchemaDataDefaults(): array
74+
{
75+
$defaults = parent::getSchemaDataDefaults();
76+
// Include child schema data for react forms
77+
$children = $this->getChildren();
78+
foreach ($children as $child) {
79+
$childSchema[] = $child->getSchemaData();
80+
}
81+
$defaults['children'] = $childSchema;
82+
return $defaults;
83+
}
84+
}
85+
```
86+
87+
You can then implement whatever logic you want and rely on those specific fields being there no matter what anyone else is doing with your form.
88+
89+
> [!TIP]
90+
> It's usually a good idea to ensure that if [`FormField::setForm()`](api:SilverStripe\Forms\FormField::setForm()), [`FormField::performReadonlyTransformation()`](api:SilverStripe\Forms\FormField::performReadonlyTransformation()), [`FormField::performDisabledTransformation()`](api:SilverStripe\Forms\FormField::performDisabledTransformation()), [`FormField::setReadonly()`](api:SilverStripe\Forms\FormField::setReadonly()), or [`FormField::setDisabled()`](api:SilverStripe\Forms\FormField::setDisabled()) is called on your parent form, the appropriate methods are called on your child fields a well.

en/08_Changelogs/6.2.0.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,14 @@ Note that some third-party modules may not yet support PHP 8.5, so PHP deprecati
105105

106106
### Move elemental blocks
107107

108-
In the [dnadesign/silverstripe-elemental](/optional_features/elemental/) module, functionality has been added to move elemental blocks from one parent to another, including from one elemental area to another on the same parent record.
108+
The [dnadesign/silverstripe-elemental](/optional_features/elemental/) module now includes functionality that allows elemental blocks to be moved from one parent record to another. This includes moving blocks between different elemental areas on the same parent record.
109109

110110
![move block button](./_images/move-block-button.png)
111111

112-
The move form provides a lot of flexibility for various configurations, and fields will be hidden if there's only one option to select from. For example, if there's only one elemental area relation on your selected parent record, no dropdown to select an elemental area will be displayed - but if there's multiple, a dropdown will be there for you.
112+
The move form has been designed for flexibility and will automatically hide fields if there's only one option available. For example:
113+
114+
- If your selected parent record has only one elemental area relation, the dropdown for selecting an elemental area won't be displayed.
115+
- If there are multiple elemental area relations, the dropdown will be available.
113116

114117
![move block form modal](./_images/move-block-modal.png)
115118

@@ -142,6 +145,7 @@ You can filter by the name and description of the campaign, its status, and the
142145

143146
### Other new features and enhancements {#other-new}
144147

148+
- A new [`ChildFieldManager`](api:SilverStripe\Forms\ChildFieldManager) interface has been added to allow a parent form field to strictly control its children, but still allow setting/getting values for those fields let them handle AJAX requests. See [`ChildFieldManager` docs](/developer_guides/forms/field_types/childfieldmanager/) for more details.
145149
- The `help` plugin is now added by default to all [`TinyMCEConfig`](api:SilverStripe\TinyMCE\TinyMCEConfig) instances. If you were adding it manually, you can remove that custom code. If for some reason you don't want that plugin in one of your configs, you can use [`TinyMCEConfig::disablePlugins()`](api:SilverStripe\TinyMCE\TinyMCEConfig::disablePlugins()) to remove it - but be aware that it is extremely useful for screen reader users to keep this plugin installed.
146150
- [`HTML::createTag()`](api:SilverStripe\View\HTML::createTag()) now supports value-less boolean attributes. For example if you pass `HTML::create('input', ['readonly' => true])`, the result will be `<input readonly>`. Previously it would output as `<input readonly="1">`.
147151
- The built-in session handlers [`FileSessionHandler`](api:SilverStripe\Control\SessionHandler\FileSessionHandler), [`CacheSessionHandler`](api:SilverStripe\Control\SessionHandler\CacheSessionHandler), and [`DatabaseSessionHandler`](api:SilverStripe\Control\SessionHandler\DatabaseSessionHandler) all now validate the session ID `PHPSESSID` to ensure it matches a valid format, otherwise a `RuntimeException` will be thrown.
@@ -178,6 +182,7 @@ It's best practice to avoid using deprecated code where possible, but sometimes
178182
- The [`EagerLoadedList::getIDList()`](api:SilverStripe\ORM\EagerLoadedList::getIDList()) method has been deprecated. Use `$list->column('ID')` instead.
179183
- The [`UnsavedRelationList::getIDList()`](api:SilverStripe\ORM\UnsavedRelationList::getIDList()) method has been deprecated. Use `$list->column('ID')` instead.
180184
- The `IconHOC` react component has been deprecated and will be removed in a future major release without a replacement. The `Button` component's `icon` prop will still remain.
185+
- The [`FieldList::dataFields()`](api:SilverStripe\Forms\FieldList::dataFields()) method has been deprecated. Use[`FieldList::getDataFields()`](api:SilverStripe\Forms\FieldList::getDataFields()) instead.
181186

182187
## Bug fixes
183188

0 commit comments

Comments
 (0)