mirror of
https://github.com/silverstripe/silverstripe-tagfield
synced 2024-10-22 11:05:32 +02:00
BUG Fix duplicate tag creation
BUG Fix isMultiple not being initialised BUG Fix tag rendering as a 100px wide container
This commit is contained in:
parent
847a237938
commit
2077c9df20
@ -33,9 +33,9 @@ class StringTagField extends DropdownField {
|
||||
protected $record;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
* @var bool
|
||||
*/
|
||||
protected $isMultiple;
|
||||
protected $isMultiple = true;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
|
@ -35,9 +35,9 @@ class TagField extends DropdownField {
|
||||
protected $titleField = 'Title';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var bool
|
||||
*/
|
||||
protected $isMultiple;
|
||||
protected $isMultiple = true;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
@ -260,8 +260,6 @@ class TagField extends DropdownField {
|
||||
|
||||
$source = $this->getSource();
|
||||
|
||||
$dataClass = $source->dataClass();
|
||||
|
||||
$values = $this->Value();
|
||||
|
||||
if(!$values) {
|
||||
@ -287,10 +285,8 @@ class TagField extends DropdownField {
|
||||
continue;
|
||||
}
|
||||
|
||||
$record = new $dataClass();
|
||||
$record->{$titleField} = $value;
|
||||
$record->write();
|
||||
|
||||
// Get or create record
|
||||
$record = $this->getOrCreateTag($value);
|
||||
$values[$i] = $record->ID;
|
||||
}
|
||||
}
|
||||
@ -302,6 +298,31 @@ class TagField extends DropdownField {
|
||||
$relation->setByIDList(array_filter($values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create tag with the given value
|
||||
*
|
||||
* @param string $term
|
||||
* @return DataObject
|
||||
*/
|
||||
protected function getOrCreateTag($term) {
|
||||
// Check if existing record can be found
|
||||
$source = $this->getSource();
|
||||
$titleField = $this->getTitleField();
|
||||
$record = $source
|
||||
->filter($titleField, $term)
|
||||
->first();
|
||||
if($record) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
// Create new instance if not yet saved
|
||||
$dataClass = $source->dataClass();
|
||||
$record = Injector::inst()->create($dataClass);
|
||||
$record->{$titleField} = $term;
|
||||
$record->write();
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON string of tags, for lazy loading.
|
||||
*
|
||||
@ -334,28 +355,24 @@ class TagField extends DropdownField {
|
||||
|
||||
$titleField = $this->getTitleField();
|
||||
|
||||
$term = Convert::raw2sql($term);
|
||||
|
||||
$query = $source
|
||||
->filter($titleField . ':PartialMatch:nocase', $term)
|
||||
->sort($titleField)
|
||||
->limit($this->getLazyLoadItemLimit());
|
||||
|
||||
// Map into a distinct list
|
||||
$items = array();
|
||||
|
||||
$titleField = $this->getTitleField();
|
||||
foreach($query->map('ID', $titleField) as $id => $title) {
|
||||
if(!in_array($title, $items)) {
|
||||
$items[] = array(
|
||||
'id' => $id,
|
||||
'text' => $title
|
||||
);
|
||||
}
|
||||
$items[$title] = array(
|
||||
'id' => $id,
|
||||
'text' => $title
|
||||
);
|
||||
}
|
||||
|
||||
return $items;
|
||||
return array_values($items);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DropdownField assumes value will be a scalar so we must
|
||||
* override validate. This only applies to Silverstripe 3.2+
|
||||
|
@ -1,6 +1,7 @@
|
||||
.select2-container {
|
||||
position: relative;
|
||||
max-width: 416px !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.select2-selection {
|
||||
|
@ -49,7 +49,17 @@ class TagFieldTest extends SapphireTest {
|
||||
* @param TagFieldTestBlogPost $record
|
||||
*/
|
||||
protected function compareExpectedAndActualTags(array $expected, TagFieldTestBlogPost $record) {
|
||||
$actual = array_values($record->Tags()->map('ID', 'Title')->toArray());
|
||||
$this->compareTagLists($expected, $record->Tags());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a source of tags matches the given string tag names
|
||||
*
|
||||
* @param array $expected
|
||||
* @param DataList $actualSource
|
||||
*/
|
||||
protected function compareTagLists(array $expected, DataList $actualSource) {
|
||||
$actual = array_values($actualSource->map('ID', 'Title')->toArray());
|
||||
|
||||
sort($expected);
|
||||
sort($actual);
|
||||
@ -103,6 +113,44 @@ class TagFieldTest extends SapphireTest {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that {@see TagField::saveInto} respects existing tags
|
||||
*/
|
||||
public function testSaveDuplicateTags() {
|
||||
$record = $this->getNewTagFieldTestBlogPost('BlogPost2');
|
||||
$record->write();
|
||||
$tag2ID = $this->idFromFixture('TagFieldTestBlogTag', 'Tag2');
|
||||
|
||||
// Check tags before write
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag1', 'Tag2'),
|
||||
$record
|
||||
);
|
||||
$this->compareTagLists(
|
||||
array('Tag1', 'Tag2'),
|
||||
TagFieldTestBlogTag::get()
|
||||
);
|
||||
$this->assertContains($tag2ID, TagFieldTestBlogTag::get()->column('ID'));
|
||||
|
||||
// Write new tags
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
$field->setValue(array('Tag2', 'Tag3'));
|
||||
$field->saveInto($record);
|
||||
|
||||
// Check only one new tag was added
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag2', 'Tag3'),
|
||||
$record
|
||||
);
|
||||
|
||||
// Ensure that only one new dataobject was added and that tag2s id has not changed
|
||||
$this->compareTagLists(
|
||||
array('Tag1', 'Tag2', 'Tag3'),
|
||||
TagFieldTestBlogTag::get()
|
||||
);
|
||||
$this->assertContains($tag2ID, TagFieldTestBlogTag::get()->column('ID'));
|
||||
}
|
||||
|
||||
function testItSuggestsTags() {
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user