Skip to content

Commit

Permalink
Merge pull request #58 from tractorcow/pulls/fix-dupe-records
Browse files Browse the repository at this point in the history
BUG Fix duplicate tag creation
  • Loading branch information
assertchris committed Nov 4, 2015
2 parents 847a237 + 2077c9d commit d46e325
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 22 deletions.
4 changes: 2 additions & 2 deletions code/StringTagField.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class StringTagField extends DropdownField {
protected $record;

/**
* @var boolean
* @var bool
*/
protected $isMultiple;
protected $isMultiple = true;

/**
* @param string $name
Expand Down
55 changes: 36 additions & 19 deletions code/TagField.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class TagField extends DropdownField {
protected $titleField = 'Title';

/**
* @var string
* @var bool
*/
protected $isMultiple;
protected $isMultiple = true;

/**
* @param string $name
Expand Down Expand Up @@ -260,8 +260,6 @@ public function saveInto(DataObjectInterface $record) {

$source = $this->getSource();

$dataClass = $source->dataClass();

$values = $this->Value();

if(!$values) {
Expand All @@ -287,10 +285,8 @@ public function saveInto(DataObjectInterface $record) {
continue;
}

$record = new $dataClass();
$record->{$titleField} = $value;
$record->write();

// Get or create record
$record = $this->getOrCreateTag($value);
$values[$i] = $record->ID;
}
}
Expand All @@ -302,6 +298,31 @@ public function saveInto(DataObjectInterface $record) {
$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.
*
Expand Down Expand Up @@ -334,28 +355,24 @@ protected function getTags($term) {

$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+
Expand Down
1 change: 1 addition & 0 deletions css/TagField.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.select2-container {
position: relative;
max-width: 416px !important;
width: 100%;
}

.select2-selection {
Expand Down
50 changes: 49 additions & 1 deletion tests/TagFieldTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,17 @@ protected function getNewTagFieldTestBlogPost($name) {
* @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);
Expand Down Expand Up @@ -103,6 +113,44 @@ public function testItSavesLinksToExistingTagsOnExistingRecords() {
);
}

/**
* 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'));

Expand Down

0 comments on commit d46e325

Please sign in to comment.