From 02fb7c3b178f85b75365b0efb46ae8b25a204590 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Sat, 24 Aug 2019 16:28:09 +1200 Subject: [PATCH] NEW: Support dot syntax in form field names This change adds support for these in a few places. - Form::saveInto($record) - Form::loadDataForm($record) - Form::loadDataForm($_POST) Fixes https://github.com/silverstripe/silverstripe-framework/issues/9163 --- src/Forms/Form.php | 29 +++++++++++++++++++++-------- src/Forms/FormField.php | 14 ++++++++++++-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/Forms/Form.php b/src/Forms/Form.php index 1d351695417..d9e0e91c172 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -1462,16 +1462,29 @@ public function loadDataFrom($data, $mergeStrategy = 0, $fieldList = null) $val = null; if (is_object($data)) { - $exists = ( - isset($data->$name) || - $data->hasMethod($name) || - ($data->hasMethod('hasField') && $data->hasField($name)) - ); - - if ($exists) { - $val = $data->__get($name); + // Allow dot-syntax traversal of has-one relations fields + if (strpos($name, '.') !== false && $data->hasMethod('relField')) { + $val = $data->relField($name); + $exists = true; + + // Regular ViewableData access + } else { + $exists = ( + isset($data->$name) || + $data->hasMethod($name) || + ($data->hasMethod('hasField') && $data->hasField($name)) + ); + + if ($exists) { + $val = $data->__get($name); + } } + + // Regular array access. Note that dot-syntax not supported here } elseif (is_array($data)) { + // PHP turns the '.'s in POST vars into '_'s + $name = str_replace('.', '_', $name); + if (array_key_exists($name, $data)) { $exists = true; $val = $data[$name]; diff --git a/src/Forms/FormField.php b/src/Forms/FormField.php index 9cad1e8df6c..d35871c3a94 100644 --- a/src/Forms/FormField.php +++ b/src/Forms/FormField.php @@ -469,8 +469,18 @@ public function Value() */ public function saveInto(DataObjectInterface $record) { - if ($this->name) { - $record->setCastedField($this->name, $this->dataValue()); + $component = $record; + $fieldName = $this->name; + + // Allow for dot syntax + if (($pos = strrpos($this->name, '.')) !== false) { + $relation = substr($this->name, 0, $pos); + $fieldName = substr($this->name, $pos + 1); + $component = $record->relObject($relation); + } + + if ($fieldName) { + $component->setCastedField($fieldName, $this->dataValue()); } }