From 76255c9fb599d012dbd9498c98beb25b0f5d7f74 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 18 Oct 2018 22:52:14 +1300 Subject: [PATCH] FIX: CheckboxSetField can now save into DBMultiEnum Fixes https://github.com/silverstripe/silverstripe-framework/issues/1489 --- src/Forms/MultiSelectField.php | 60 +++++++++++- .../CheckboxFieldtest/MutiEnumArticle.php | 16 +++ .../Forms/CheckboxSetFieldMultiEnumTest.php | 98 +++++++++++++++++++ 3 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 tests/php/Forms/CheckboxFieldtest/MutiEnumArticle.php create mode 100644 tests/php/Forms/CheckboxSetFieldMultiEnumTest.php diff --git a/src/Forms/MultiSelectField.php b/src/Forms/MultiSelectField.php index 710ae916a..f87b4b023 100644 --- a/src/Forms/MultiSelectField.php +++ b/src/Forms/MultiSelectField.php @@ -4,6 +4,7 @@ namespace SilverStripe\Forms; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObjectInterface; +use SilverStripe\ORM\FieldType\DBMultiEnum; use SilverStripe\ORM\Relation; /** @@ -98,7 +99,15 @@ abstract class MultiSelectField extends SelectField $value = array_values($relation->getIDList()); parent::setValue($value); } elseif ($record->hasField($fieldName)) { - $value = $this->stringDecode($record->$fieldName); + // Load dataValue from field... a CSV for DBMultiEnum + if ($record->obj($fieldName) instanceof DBMultiEnum) { + $value = $this->csvDecode($record->$fieldName); + + // ... JSON-encoded string for other fields + } else { + $value = $this->stringDecode($record->$fieldName); + } + parent::setValue($value); } } @@ -129,8 +138,14 @@ abstract class MultiSelectField extends SelectField // Save ids into relation $relation->setByIDList($items); } elseif ($record->hasField($fieldName)) { - // Save dataValue into field - $record->$fieldName = $this->stringEncode($items); + // Save dataValue into field... a CSV for DBMultiEnum + if ($record->obj($fieldName) instanceof DBMultiEnum) { + $record->$fieldName = $this->csvEncode($items); + + // ... JSON-encoded string for other fields + } else { + $record->$fieldName = $this->stringEncode($items); + } } } @@ -169,6 +184,45 @@ abstract class MultiSelectField extends SelectField throw new \InvalidArgumentException("Invalid string encoded value for multi select field"); } + /** + * Encode a list of values into a string as a comma separated list. + * Commas will be stripped from the items passed in + * + * @param array $value + * @return string|null + */ + protected function csvEncode($value) + { + if (!$value) { + return null; + } + return implode( + ',', + array_map( + function ($x) { + return str_replace(',', '', $x); + }, + array_values($value) + ) + ); + } + + /** + * Decode a list of values from a comma separated string. + * Spaces are trimmed + * + * @param string $value + * @return array + */ + protected function csvDecode($value) + { + if (!$value) { + return []; + } + + return preg_split('/\s*,\s*/', trim($value)); + } + /** * Validate this field * diff --git a/tests/php/Forms/CheckboxFieldtest/MutiEnumArticle.php b/tests/php/Forms/CheckboxFieldtest/MutiEnumArticle.php new file mode 100644 index 000000000..8c44b169e --- /dev/null +++ b/tests/php/Forms/CheckboxFieldtest/MutiEnumArticle.php @@ -0,0 +1,16 @@ + "Text", + "Colours" => "MultiEnum('Red,Blue,Green')", + ); +} diff --git a/tests/php/Forms/CheckboxSetFieldMultiEnumTest.php b/tests/php/Forms/CheckboxSetFieldMultiEnumTest.php new file mode 100644 index 000000000..3eadb6999 --- /dev/null +++ b/tests/php/Forms/CheckboxSetFieldMultiEnumTest.php @@ -0,0 +1,98 @@ +markTestSkipped('DBMultiEnum only supported by MySQL'); + return; + } + parent::setUp(); + } + + public function tearDown() + { + if (!(DB::get_conn() instanceof MySQLDatabase)) { + return; + } + parent::tearDown(); + } + + public function testLoadDataFromMultiEnum() + { + $article = new MultiEnumArticle(); + $article->Colours = 'Red,Green'; + + $field = new CheckboxSetField( + 'Colours', + 'Colours', + [ + 'Red' => 'Red', + 'Blue' => 'Blue', + 'Green' => 'Green', + ] + ); + + $form = new Form( + Controller::curr(), + 'Form', + new FieldList($field), + new FieldList() + ); + $form->loadDataFrom($article); + $value = $field->Value(); + $this->assertEquals(['Red', 'Green'], $value); + } + + public function testSavingIntoMultiEnum() + { + $field = new CheckboxSetField( + 'Colours', + 'Colours', + [ + 'Red' => 'Red', + 'Blue' => 'Blue', + 'Green' => 'Green', + ] + ); + $article = new MultiEnumArticle(); + $field->setValue(array('Red' => 'Red', 'Blue' => 'Blue')); + $field->saveInto($article); + $article->write(); + + $dbValue = DB::query( + sprintf( + 'SELECT "Colours" FROM "CheckboxSetFieldTest_MultiEnumArticle" WHERE "ID" = %s', + $article->ID + ) + )->value(); + + // JSON encoded values + $this->assertEquals('Red,Blue', $dbValue); + } +}