Module version(s) affected
6.x, 5.x, 4.x
Description
I wanted to save values from a CheckboxSetField into a many_many_extraFields Text field. Doing this with a standard TextField works fine, but any MultiSelectField fails. The way MultiSelectField->saveInto() is implemented does not work with the ManyMany[Ranking] declaration.
However the ManyMany[]-prefix is required. Without that field being present, in GridFieldDetailForm_ItemRequest->getExtraSavedData() the line $record->hasField($savedField) returns false and no $extraData will be available in GridFieldDetailForm_ItemRequest->saveFormIntoRecord()
I hope this makes sense. I spend a few hours debugging this and my brain is a bit mushy. Please see my sample code. Some breakpoints at the places mentioned above will help as well :)
How to reproduce
- Clean Installation.
- Use the first code example.
- Add a team
- Add a Supporter to the team, change some checkboxes and save
- Refresh and/or
SELECT * FROM Team_Supporters
class TeamModelAdmin extends \SilverStripe\Admin\ModelAdmin {
private static $url_segment = 'teams';
private static $managed_models = [
Team::class,
Supporter::class,
];
}
class Team extends \SilverStripe\ORM\DataObject {
private static $many_many = [
'Supporters' => Supporter::class,
];
private static $many_many_extraFields = [
'Supporters' => [
'Ranking' => 'Text',
],
];
public function getCMSFields() {
$this->beforeUpdateCMSFields(function ($fields) {
if (!$this->isInDB())
return;
$gfConfig = \SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor::create();
$detailform = $gfConfig->getComponentByType(\SilverStripe\Forms\GridField\GridFieldDetailForm::class);
$values = ['a', 'b', 'c', 'd'];
$values = array_combine($values, $values);
$detailform->setFields(\SilverStripe\Forms\FieldList::create(
\SilverStripe\Forms\CheckboxSetField::create('ManyMany[Ranking]', null, $values),
));
$fields->dataFieldByName('Supporters')->setConfig($gfConfig);
});
return parent::getCMSFields();
}
}
class Supporter extends \SilverStripe\ORM\DataObject {}
In order to make it work without core hacking, I had to do the following changes. I would be fine with most of them, but overriding Supporter->__construct() seems a bit hacky.
class Team extends \SilverStripe\ORM\DataObject {
// [...]
public function getCMSFields() {
$this->beforeUpdateCMSFields(function ($fields) {
if (!$this->isInDB())
return;
$gfConfig = \SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor::create();
$detailform = $gfConfig->getComponentByType(\SilverStripe\Forms\GridField\GridFieldDetailForm::class);
$values = ['a', 'b', 'c', 'd'];
$values = array_combine($values, $values);
$detailform->setFields(\SilverStripe\Forms\FieldList::create(
\SilverStripe\Forms\CheckboxSetField::create('ManyMany[Ranking]', null, $values),
));
$detailform->setItemEditFormCallback(function (\SilverStripe\Forms\Form $form) {
$record = $form->getRecord();
// without the following chain the updated values would be visible only after a page reload
$valCurrent = $record->getField('ManyMany[Ranking]') ?? $record->getField('Ranking') ?? '[]';
$field = $form->Fields()->dataFieldByName('ManyMany[Ranking]');
$field->setValue(json_decode($valCurrent));
});
$fields->dataFieldByName('Supporters')->setConfig($gfConfig);
});
return parent::getCMSFields();
}
}
class Supporter extends \SilverStripe\ORM\DataObject {
public function __construct($record = [], $creationType = self::CREATE_OBJECT, $queryParams = []) {
parent::__construct($record, $creationType, $queryParams);
$this->setField('ManyMany[Ranking]', $this->getField('Ranking'));
}
}
Possible Solution
A better implementation of MultiSelectField->saveInto() / loadFrom() with checking if $fieldName starts with 'ManyMany[' seems to have the least friction?
Additional Context
No response
Validations
Module version(s) affected
6.x, 5.x, 4.x
Description
I wanted to save values from a CheckboxSetField into a many_many_extraFields Text field. Doing this with a standard TextField works fine, but any MultiSelectField fails. The way
MultiSelectField->saveInto()is implemented does not work with theManyMany[Ranking]declaration.However the ManyMany[]-prefix is required. Without that field being present, in
GridFieldDetailForm_ItemRequest->getExtraSavedData()the line$record->hasField($savedField)returns false and no$extraDatawill be available inGridFieldDetailForm_ItemRequest->saveFormIntoRecord()I hope this makes sense. I spend a few hours debugging this and my brain is a bit mushy. Please see my sample code. Some breakpoints at the places mentioned above will help as well :)
How to reproduce
SELECT * FROM Team_SupportersIn order to make it work without core hacking, I had to do the following changes. I would be fine with most of them, but overriding Supporter->__construct() seems a bit hacky.
Possible Solution
A better implementation of
MultiSelectField->saveInto() / loadFrom()with checking if$fieldNamestarts with 'ManyMany[' seems to have the least friction?Additional Context
No response
Validations
silverstripe/installer(with any code examples you've provided)