Fixes required for dot notation support in fields

See #9163
This commit is contained in:
Ingo Schommer 2021-05-20 20:07:44 +12:00
parent 23ffd2bbd6
commit 8806b3befc
4 changed files with 29 additions and 8 deletions

View File

@ -332,6 +332,8 @@ class PageController extends ContentController
``` ```
See [how_tos/handle_nested_data](How to: Handle nested form data) for more advanced use cases.
## Validation ## Validation
Form validation is handled by the [Validator](api:SilverStripe\Forms\Validator) class and the `validator` property on the `Form` object. The validator Form validation is handled by the [Validator](api:SilverStripe\Forms\Validator) class and the `validator` property on the `Form` object. The validator

View File

@ -511,6 +511,7 @@ class FieldList extends ArrayList
*/ */
public function fieldByName($name) public function fieldByName($name)
{ {
$fullName = $name;
if (strpos($name, '.') !== false) { if (strpos($name, '.') !== false) {
list($name, $remainder) = explode('.', $name, 2); list($name, $remainder) = explode('.', $name, 2);
} else { } else {
@ -518,7 +519,9 @@ class FieldList extends ArrayList
} }
foreach ($this as $child) { foreach ($this as $child) {
if (trim($name) == trim($child->getName()) || $name == $child->id) { if (trim($fullName) == trim($child->getName()) || $fullName == $child->id) {
return $child;
} elseif (trim($name) == trim($child->getName()) || $name == $child->id) {
if ($remainder) { if ($remainder) {
if ($child instanceof CompositeField) { if ($child instanceof CompositeField) {
return $child->fieldByName($remainder); return $child->fieldByName($remainder);

View File

@ -1463,10 +1463,16 @@ class Form extends ViewableData implements HasRequestHandler
if (is_object($data)) { if (is_object($data)) {
// Allow dot-syntax traversal of has-one relations fields // Allow dot-syntax traversal of has-one relations fields
if (strpos($name, '.') !== false && $data->hasMethod('relField')) { if (strpos($name, '.') !== false) {
$val = $data->relField($name); $exists = (
$exists = true; $data->hasMethod('relField')
);
try {
$val = $data->relField($name);
} catch (\LogicException $e) {
// There's no other way to tell whether the relation actually exists
$exists = false;
}
// Regular ViewableData access // Regular ViewableData access
} else { } else {
$exists = ( $exists = (

View File

@ -88,7 +88,8 @@ class FormTest extends FunctionalTest
new TextField('key1'), new TextField('key1'),
new TextField('namespace[key2]'), new TextField('namespace[key2]'),
new TextField('namespace[key3][key4]'), new TextField('namespace[key3][key4]'),
new TextField('othernamespace[key5][key6][key7]') new TextField('othernamespace[key5][key6][key7]'),
new TextField('dot.field')
), ),
new FieldList() new FieldList()
); );
@ -108,7 +109,9 @@ class FormTest extends FunctionalTest
'key7' => 'val7' 'key7' => 'val7'
] ]
] ]
] ],
'dot.field' => 'dot.field val'
]; ];
$form->loadDataFrom($requestData); $form->loadDataFrom($requestData);
@ -118,6 +121,7 @@ class FormTest extends FunctionalTest
$this->assertEquals('val2', $fields->fieldByName('namespace[key2]')->Value()); $this->assertEquals('val2', $fields->fieldByName('namespace[key2]')->Value());
$this->assertEquals('val4', $fields->fieldByName('namespace[key3][key4]')->Value()); $this->assertEquals('val4', $fields->fieldByName('namespace[key3][key4]')->Value());
$this->assertEquals('val7', $fields->fieldByName('othernamespace[key5][key6][key7]')->Value()); $this->assertEquals('val7', $fields->fieldByName('othernamespace[key5][key6][key7]')->Value());
$this->assertEquals('dot.field val', $fields->fieldByName('dot.field')->Value());
} }
public function testSubmitReadonlyFields() public function testSubmitReadonlyFields()
@ -186,7 +190,8 @@ class FormTest extends FunctionalTest
new TextField('Name'), // appears in both Player and Team new TextField('Name'), // appears in both Player and Team
new TextareaField('Biography'), new TextareaField('Biography'),
new DateField('Birthday'), new DateField('Birthday'),
new NumericField('BirthdayYear') // dynamic property new NumericField('BirthdayYear'), // dynamic property
new TextField('FavouriteTeam.Name') // dot syntax
), ),
new FieldList() new FieldList()
); );
@ -200,6 +205,7 @@ class FormTest extends FunctionalTest
'Biography' => 'Bio 1', 'Biography' => 'Bio 1',
'Birthday' => '1982-01-01', 'Birthday' => '1982-01-01',
'BirthdayYear' => '1982', 'BirthdayYear' => '1982',
'FavouriteTeam.Name' => 'Team 1',
], ],
'LoadDataFrom() loads simple fields and dynamic getters' 'LoadDataFrom() loads simple fields and dynamic getters'
); );
@ -213,6 +219,7 @@ class FormTest extends FunctionalTest
'Biography' => null, 'Biography' => null,
'Birthday' => null, 'Birthday' => null,
'BirthdayYear' => 0, 'BirthdayYear' => 0,
'FavouriteTeam.Name' => null,
], ],
'LoadNonBlankDataFrom() loads only fields with values, and doesnt overwrite existing values' 'LoadNonBlankDataFrom() loads only fields with values, and doesnt overwrite existing values'
); );
@ -229,6 +236,7 @@ class FormTest extends FunctionalTest
new TextareaField('Biography'), new TextareaField('Biography'),
new DateField('Birthday'), new DateField('Birthday'),
new NumericField('BirthdayYear'), // dynamic property new NumericField('BirthdayYear'), // dynamic property
new TextField('FavouriteTeam.Name'), // dot syntax
$unrelatedField = new TextField('UnrelatedFormField') $unrelatedField = new TextField('UnrelatedFormField')
//new CheckboxSetField('Teams') // relation editing //new CheckboxSetField('Teams') // relation editing
), ),
@ -245,6 +253,7 @@ class FormTest extends FunctionalTest
'Biography' => 'Bio 1', 'Biography' => 'Bio 1',
'Birthday' => '1982-01-01', 'Birthday' => '1982-01-01',
'BirthdayYear' => '1982', 'BirthdayYear' => '1982',
'FavouriteTeam.Name' => 'Team 1',
'UnrelatedFormField' => 'random value', 'UnrelatedFormField' => 'random value',
], ],
'LoadDataFrom() doesnt overwrite fields not found in the object' 'LoadDataFrom() doesnt overwrite fields not found in the object'
@ -261,6 +270,7 @@ class FormTest extends FunctionalTest
'Biography' => '', 'Biography' => '',
'Birthday' => '', 'Birthday' => '',
'BirthdayYear' => 0, 'BirthdayYear' => 0,
'FavouriteTeam.Name' => null,
'UnrelatedFormField' => null, 'UnrelatedFormField' => null,
], ],
'LoadDataFrom() overwrites fields not found in the object with $clearMissingFields=true' 'LoadDataFrom() overwrites fields not found in the object with $clearMissingFields=true'