From 6e3ceefbb86b048bb9b12b414103fa578a8f2504 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 5 Mar 2012 10:55:09 +0100 Subject: [PATCH] ENHANCEMENT Relationship saving in ListboxField (preparing for chosen.js usage), escaping commas in payload when serialising multiple values into a single field --- forms/ListboxField.php | 58 +++++++++++++++++++++++++--- tests/forms/ListboxFieldTest.php | 66 +++++++++++++++++++++++++++++++- tests/forms/ListboxFieldTest.yml | 13 +++++++ 3 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 tests/forms/ListboxFieldTest.yml diff --git a/forms/ListboxField.php b/forms/ListboxField.php index 81701bcb0..a0423a696 100644 --- a/forms/ListboxField.php +++ b/forms/ListboxField.php @@ -142,19 +142,65 @@ class ListboxField extends DropdownField { return $this; } - + /** - * @return String + * Return the CheckboxSetField value as a string + * selected item keys. + * + * @return string */ function dataValue() { - if($this->value && $this->multiple && is_array($this->value)) { - return implode(',', $this->value); + if($this->value && is_array($this->value) && $this->multiple) { + $filtered = array(); + foreach($this->value as $item) { + if($item) { + $filtered[] = str_replace(",", "{comma}", $item); + } + } + return implode(',', $filtered); } else { return parent::dataValue(); } } - function setValue($val) { + /** + * Save the current value of this field into a DataObject. + * If the field it is saving to is a has_many or many_many relationship, + * it is saved by setByIDList(), otherwise it creates a comma separated + * list for a standard DB text/varchar field. + * + * @param DataObject $record The record to save into + */ + function saveInto(DataObject $record) { + if($this->multiple) { + $fieldname = $this->name; + if($fieldname && $record && ($record->has_many($fieldname) || $record->many_many($fieldname))) { + $idList = (is_array($this->value)) ? array_values($this->value) : array(); + $record->$fieldname()->setByIDList($idList); + } elseif($fieldname && $record) { + if($this->value) { + $this->value = str_replace(',', '{comma}', $this->value); + $record->$fieldname = implode(",", $this->value); + } else { + $record->$fieldname = null; + } + } + } else { + parent::saveInto($record); + } + } + + /** + * Load a value into this CheckboxSetField + */ + function setValue($val, $obj = null) { + // If we're not passed a value directly, + // we can look for it in a relation method on the object passed as a second arg + if(!$val && $obj && $obj instanceof DataObject && $obj->hasMethod($this->name)) { + $funcName = $this->name; + $val = array_values($obj->$funcName()->getIDList()); + } + if($val) { if(!$this->multiple && is_array($val)) { throw new InvalidArgumentException('No array values allowed with multiple=false'); @@ -187,4 +233,4 @@ class ListboxField extends DropdownField { return $this; } -} +} \ No newline at end of file diff --git a/tests/forms/ListboxFieldTest.php b/tests/forms/ListboxFieldTest.php index 3c9d18705..a35e33857 100644 --- a/tests/forms/ListboxFieldTest.php +++ b/tests/forms/ListboxFieldTest.php @@ -5,8 +5,28 @@ */ class ListboxFieldTest extends SapphireTest { + + static $fixture_file = 'ListboxFieldTest.yml'; - protected $extraDataObjects = array('ListboxFieldTest_DataObject'); + protected $extraDataObjects = array('ListboxFieldTest_DataObject', 'ListboxFieldTest_Article', 'ListboxFieldTest_Tag'); + + function testFieldWithManyManyRelationship() { + $articleWithTags = $this->objFromFixture('ListboxFieldTest_Article', 'articlewithtags'); + $tag1 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag1'); + $tag2 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag2'); + $tag3 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag3'); + $field = new ListboxField("Tags", "Test field", DataObject::get("ListboxFieldTest_Tag")->map()->toArray()); + $field->setMultiple(true); + $field->setValue(null, $articleWithTags); + + $p = new CSSContentParser($field->Field()); + $tag1xml = $p->getByXpath('//option[@value=' . $tag1->ID . ']'); + $tag2xml = $p->getByXpath('//option[@value=' . $tag2->ID . ']'); + $tag3xml = $p->getByXpath('//option[@value=' . $tag3->ID . ']'); + $this->assertEquals('selected', (string)$tag1xml[0]['selected']); + $this->assertEquals('selected', (string)$tag2xml[0]['selected']); + $this->assertNull($tag3xml[0]['selected']); + } function testSaveIntoNullValueWithMultipleOff() { $choices = array('a' => 'a value', 'b' => 'b value','c' => 'c value'); @@ -62,6 +82,33 @@ class ListboxFieldTest extends SapphireTest { $field->saveInto($obj2); $this->assertEquals('a,c', $obj2->Choices); } + + function testSaveIntoManyManyRelation() { + $article = $this->objFromFixture('ListboxFieldTest_Article', 'articlewithouttags'); + $articleWithTags = $this->objFromFixture('ListboxFieldTest_Article', 'articlewithtags'); + $tag1 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag1'); + $tag2 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag2'); + $field = new ListboxField("Tags", "Test field", DataObject::get("ListboxFieldTest_Tag")->map()->toArray()); + $field->setMultiple(true); + + // Save new relations + $field->setValue(array($tag1->ID,$tag2->ID)); + $field->saveInto($article); + $article = Dataobject::get_by_id('ListboxFieldTest_Article', $article->ID, false); + $this->assertEquals(array($tag1->ID, $tag2->ID), $article->Tags()->column('ID')); + + // Remove existing relation + $field->setValue(array($tag1->ID)); + $field->saveInto($article); + $article = Dataobject::get_by_id('ListboxFieldTest_Article', $article->ID, false); + $this->assertEquals(array($tag1->ID), $article->Tags()->column('ID')); + + // Set NULL value + $field->setValue(null); + $field->saveInto($article); + $article = Dataobject::get_by_id('ListboxFieldTest_Article', $article->ID, false); + $this->assertEquals(array(), $article->Tags()->column('ID')); + } /** * @expectedException InvalidArgumentException @@ -130,4 +177,21 @@ class ListboxFieldTest_DataObject extends DataObject implements TestOnly { static $db = array( 'Choices' => 'Text' ); +} + +class ListboxFieldTest_Article extends DataObject implements TestOnly { + static $db = array( + "Content" => "Text", + ); + + static $many_many = array( + "Tags" => "ListboxFieldTest_Tag", + ); + +} + +class ListboxFieldTest_Tag extends DataObject implements TestOnly { + static $belongs_many_many = array( + 'Articles' => 'ListboxFieldTest_Article' + ); } \ No newline at end of file diff --git a/tests/forms/ListboxFieldTest.yml b/tests/forms/ListboxFieldTest.yml new file mode 100644 index 000000000..a6ac056fa --- /dev/null +++ b/tests/forms/ListboxFieldTest.yml @@ -0,0 +1,13 @@ +ListboxFieldTest_Tag: + tag1: + Title: Tag 1 + tag2: + Title: Tag 2 + tag3: + Title: Tag 3 +ListboxFieldTest_Article: + articlewithouttags: + Content: Article 1 + articlewithtags: + Content: Article 2 + Tags: =>ListboxFieldTest_Tag.tag1,=>ListboxFieldTest_Tag.tag2 \ No newline at end of file