mirror of
https://github.com/silverstripe/silverstripe-tagfield
synced 2024-10-22 09:05:32 +00:00
Stabilized API
This commit is contained in:
parent
0181932591
commit
5efeb5642f
37
README.md
37
README.md
@ -1,10 +1,7 @@
|
||||
# TagField Module
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/silverstripe-labs/silverstripe-tagfield.png?branch=master)](https://travis-ci.org/silverstripe-labs/silverstripe-tagfield)
|
||||
|
||||
## Maintainer Contact
|
||||
|
||||
* Christopher Pitt (Nickname: assertchris) <chris (at) silverstripe (dot) com>
|
||||
[![Build Status](http://img.shields.io/travis/silverstripe-labs/silverstripe-tagfield.svg?style=flat-square)](https://travis-ci.org/silverstripe-labs/silverstripe-tagfield)
|
||||
[![Code Quality](http://img.shields.io/scrutinizer/g/silverstripe-labs/silverstripe-tagfield.svg?style=flat-square)](https://scrutinizer-ci.com/g/silverstripe-labs/silverstripe-tagfield)
|
||||
|
||||
## Requirements
|
||||
|
||||
@ -17,6 +14,8 @@
|
||||
|
||||
## Usage
|
||||
|
||||
### Relational Tags
|
||||
|
||||
```php
|
||||
class BlogPost extends DataObject {
|
||||
static $many_many = array(
|
||||
@ -38,10 +37,28 @@ class BlogTag extends DataObject {
|
||||
```
|
||||
|
||||
```php
|
||||
$all = BlogTags::get()->map();
|
||||
$linked = $post->BlogTags()->map();
|
||||
|
||||
$field = new TagField(
|
||||
'BlogTags', 'Blog Tags', $all, $linked
|
||||
'BlogTags', 'Blog Tags', BlogTags::get(), $post->BlogTags()
|
||||
);
|
||||
```
|
||||
|
||||
$field->setShouldLazyLoad(true); // tags should be lazy loaded
|
||||
$field->setCanCreate(true); // new tag DataObjects can be created
|
||||
```
|
||||
|
||||
### String Tags
|
||||
|
||||
```php
|
||||
class BlogPost extends DataObject {
|
||||
static $db = array(
|
||||
'Tags' => 'Text'
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
$field = new StringTagField(
|
||||
'BlogTags', 'Blog Tags', array('one', 'two'), explode(',', $post->Tags)
|
||||
);
|
||||
|
||||
$field->setShouldLazyLoad(true); // tags should be lazy loaded
|
||||
```
|
||||
|
285
code/StringTagField.php
Normal file
285
code/StringTagField.php
Normal file
@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Provides a tagging interface, storing comma-delimited tags in a DataObject string field.
|
||||
*
|
||||
* This is intended bridge the gap between 1.x and 2.x, and when possible TagField should be used
|
||||
* instead.
|
||||
*
|
||||
* @package forms
|
||||
* @subpackage fields
|
||||
*/
|
||||
class StringTagField extends DropdownField {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $allowed_actions = array(
|
||||
'suggest',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $shouldLazyLoad = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $lazyLoadItemLimit = 10;
|
||||
|
||||
/**
|
||||
* @var null|DataObject
|
||||
*/
|
||||
protected $record;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param array|SS_List $source
|
||||
* @param array|SS_List $value
|
||||
*/
|
||||
public function __construct($name, $title = '', $source = array(), $value = array()) {
|
||||
parent::__construct($name, $title, $source, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getShouldLazyLoad() {
|
||||
return $this->shouldLazyLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $shouldLazyLoad
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setShouldLazyLoad($shouldLazyLoad) {
|
||||
$this->shouldLazyLoad = $shouldLazyLoad;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLazyLoadItemLimit() {
|
||||
return $this->lazyLoadItemLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $lazyLoadItemLimit
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setLazyLoadItemLimit($lazyLoadItemLimit) {
|
||||
$this->lazyLoadItemLimit = $lazyLoadItemLimit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|DataObject
|
||||
*/
|
||||
public function getRecord() {
|
||||
if($this->record) {
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
if($form = $this->getForm()) {
|
||||
return $form->getRecord();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataObject $record
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRecord(DataObject $record) {
|
||||
$this->record = $record;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function Field($properties = array()) {
|
||||
Requirements::css(TAG_FIELD_DIR . '/css/select2.min.css');
|
||||
Requirements::css(TAG_FIELD_DIR . '/css/TagField.css');
|
||||
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js');
|
||||
Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js');
|
||||
|
||||
$this->addExtraClass('ss-tag-field');
|
||||
|
||||
$this->setAttribute('multiple', 'multiple');
|
||||
|
||||
if($this->getShouldLazyLoad()) {
|
||||
$this->setAttribute('data-ss-tag-field-suggest-url', $this->getSuggestURL());
|
||||
} else {
|
||||
$properties = array_merge($properties, array(
|
||||
'Options' => $this->getOptions()
|
||||
));
|
||||
}
|
||||
|
||||
return $this
|
||||
->customise($properties)
|
||||
->renderWith(array("templates/StringTagField"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getSuggestURL() {
|
||||
return Controller::join_links($this->Link(), 'suggest');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayList
|
||||
*/
|
||||
protected function getOptions() {
|
||||
$options = ArrayList::create();
|
||||
|
||||
$source = $this->getSource();
|
||||
|
||||
if($source instanceof Iterator) {
|
||||
$source = iterator_to_array($source);
|
||||
}
|
||||
|
||||
$values = $this->Value();
|
||||
|
||||
foreach($source as $value) {
|
||||
$options->push(
|
||||
ArrayData::create(array(
|
||||
'Title' => $value,
|
||||
'Value' => $value,
|
||||
'Selected' => in_array($value, $values),
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setValue($value, $source = null) {
|
||||
if(is_string($value)) {
|
||||
$value = explode(',', $value);
|
||||
}
|
||||
|
||||
if($source instanceof DataObject) {
|
||||
$name = $this->getName();
|
||||
$value = $source->$name;
|
||||
}
|
||||
|
||||
if($source instanceof SS_List) {
|
||||
$value = $source->column('ID');
|
||||
}
|
||||
|
||||
return parent::setValue(array_filter($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributes() {
|
||||
return array_merge(
|
||||
parent::getAttributes(),
|
||||
array('name' => $this->getName() . '[]')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveInto(DataObjectInterface $record) {
|
||||
parent::saveInto($record);
|
||||
|
||||
$name = $this->getName();
|
||||
|
||||
$record->$name = join(',', $this->Value());
|
||||
$record->write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON string of tags, for lazy loading.
|
||||
*
|
||||
* @param SS_HTTPRequest $request
|
||||
*
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function suggest(SS_HTTPRequest $request) {
|
||||
$responseBody = Convert::raw2json(
|
||||
array('items' => array())
|
||||
);
|
||||
|
||||
$response = new SS_HTTPResponse();
|
||||
$response->addHeader('Content-Type', 'application/json');
|
||||
|
||||
if($record = $this->getRecord()) {
|
||||
$tags = array();
|
||||
$term = $request->getVar('term');
|
||||
|
||||
if($record->hasField($this->getName())) {
|
||||
$tags = $this->getTags($term);
|
||||
}
|
||||
|
||||
$responseBody = Convert::raw2json(
|
||||
array('items' => $tags)
|
||||
);
|
||||
}
|
||||
|
||||
$response->setBody($responseBody);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of arrays representing tags.
|
||||
*
|
||||
* @param string $term
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTags($term) {
|
||||
$record = $this->getRecord();
|
||||
|
||||
if(!$record) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$fieldName = $this->getName();
|
||||
$className = $record->getClassName();
|
||||
|
||||
$term = Convert::raw2sql($term);
|
||||
|
||||
$query = $className::get()
|
||||
->filter($fieldName . ':PartialMatch:nocase', $term)
|
||||
->limit($this->getLazyLoadItemLimit());
|
||||
|
||||
$items = array();
|
||||
|
||||
foreach($query->column($fieldName) as $tags) {
|
||||
$tags = explode(',', $tags);
|
||||
|
||||
foreach($tags as $i => $tag) {
|
||||
if(stripos($tag, $term) !== false && !in_array($tag, $items)) {
|
||||
$items[] = array(
|
||||
'id' => $tag,
|
||||
'text' => $tag
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tag field, using jQuery/Select2.
|
||||
* Provides a tagging interface, storing links between tag DataObjects and a parent DataObject.
|
||||
*
|
||||
* @package forms
|
||||
* @subpackage fields-formattedinput
|
||||
* @package forms
|
||||
* @subpackage fields
|
||||
*/
|
||||
class TagField extends DropdownField {
|
||||
/**
|
||||
@ -17,91 +17,47 @@ class TagField extends DropdownField {
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $ajax = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $readOnly = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $relationTitle = 'Title';
|
||||
protected $shouldLazyLoad = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $ajaxItemLimit = 10;
|
||||
protected $lazyLoadItemLimit = 10;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
* @var bool
|
||||
*/
|
||||
protected $recordClass;
|
||||
protected $canCreate = true;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $titleField = 'Title';
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param null|string $title
|
||||
* @param array $source
|
||||
* @param array $value
|
||||
* @param bool $readOnly
|
||||
* @param string $title
|
||||
* @param null|DataList $source
|
||||
* @param null|DataList $value
|
||||
*/
|
||||
public function __construct($name, $title = null, $source = array(), $value = array(), $readOnly = false) {
|
||||
$this->setReadOnly($readOnly);
|
||||
|
||||
public function __construct($name, $title = '', $source = null, $value = null) {
|
||||
parent::__construct($name, $title, $source, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getAjax() {
|
||||
return $this->ajax;
|
||||
public function getShouldLazyLoad() {
|
||||
return $this->shouldLazyLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $ajax
|
||||
* @param bool $shouldLazyLoad
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setAjax($ajax) {
|
||||
$this->ajax = $ajax;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getReadOnly() {
|
||||
return $this->readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $readOnly
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setReadOnly($readOnly) {
|
||||
$this->readOnly = $readOnly;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getRelationTitle() {
|
||||
return $this->relationTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relationTitle
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setRelationTitle($relationTitle) {
|
||||
$this->relationTitle = $relationTitle;
|
||||
public function setShouldLazyLoad($shouldLazyLoad) {
|
||||
$this->shouldLazyLoad = $shouldLazyLoad;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -109,35 +65,53 @@ class TagField extends DropdownField {
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAjaxItemLimit() {
|
||||
return $this->ajaxItemLimit;
|
||||
public function getLazyLoadItemLimit() {
|
||||
return $this->lazyLoadItemLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ajaxItemLimit
|
||||
* @param int $lazyLoadItemLimit
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setAjaxItemLimit($ajaxItemLimit) {
|
||||
$this->ajaxItemLimit = $ajaxItemLimit;
|
||||
public function setLazyLoadItemLimit($lazyLoadItemLimit) {
|
||||
$this->lazyLoadItemLimit = $lazyLoadItemLimit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
* @return bool
|
||||
*/
|
||||
public function getRecordClass() {
|
||||
return $this->recordClass;
|
||||
public function getCanCreate() {
|
||||
return $this->canCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $recordClass
|
||||
* @param bool $canCreate
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setRecordClass($recordClass) {
|
||||
$this->recordClass = $recordClass;
|
||||
public function setCanCreate($canCreate) {
|
||||
$this->canCreate = $canCreate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleField() {
|
||||
return $this->titleField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $titleField
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTitleField($titleField) {
|
||||
$this->titleField = $titleField;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -149,23 +123,23 @@ class TagField extends DropdownField {
|
||||
Requirements::css(TAG_FIELD_DIR . '/css/select2.min.css');
|
||||
Requirements::css(TAG_FIELD_DIR . '/css/TagField.css');
|
||||
|
||||
Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js');
|
||||
Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js');
|
||||
Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js');
|
||||
|
||||
$this->addExtraClass('silverstripe-tag-field');
|
||||
$this->addExtraClass('ss-tag-field');
|
||||
|
||||
$this->setAttribute('multiple', 'multiple');
|
||||
|
||||
if($this->ajax) {
|
||||
$this->setAttribute('data-suggest-url', $this->getSuggestURL());
|
||||
if($this->shouldLazyLoad) {
|
||||
$this->setAttribute('data-ss-tag-field-suggest-url', $this->getSuggestURL());
|
||||
} else {
|
||||
$properties = array_merge($properties, array(
|
||||
'Options' => $this->getOptions()
|
||||
));
|
||||
}
|
||||
|
||||
$properties = array_merge($properties, array(
|
||||
'Options' => $this->getOptions()
|
||||
));
|
||||
|
||||
return $this
|
||||
->customise($properties)
|
||||
->renderWith(array("templates/TagField"));
|
||||
@ -186,18 +160,32 @@ class TagField extends DropdownField {
|
||||
|
||||
$source = $this->getSource();
|
||||
|
||||
if($source instanceof Iterator) {
|
||||
$source = iterator_to_array($source);
|
||||
if(!$source) {
|
||||
$source = new ArrayList();
|
||||
}
|
||||
|
||||
$dataClass = $source->dataClass();
|
||||
|
||||
$values = $this->Value();
|
||||
|
||||
foreach($source as $key => $value) {
|
||||
if(!$values) {
|
||||
return $options;
|
||||
}
|
||||
|
||||
if(is_array($values)) {
|
||||
$values = DataList::create($dataClass)->filter('ID', $values);
|
||||
}
|
||||
|
||||
$ids = $values->column('ID');
|
||||
|
||||
$titleField = $this->getTitleField();
|
||||
|
||||
foreach($source as $object) {
|
||||
$options->push(
|
||||
ArrayData::create(array(
|
||||
"Title" => $value,
|
||||
"Value" => $key,
|
||||
"Selected" => in_array($key, $values),
|
||||
'Title' => $object->$titleField,
|
||||
'Value' => $object->ID,
|
||||
'Selected' => in_array($object->ID, $ids),
|
||||
))
|
||||
);
|
||||
}
|
||||
@ -208,20 +196,18 @@ class TagField extends DropdownField {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setValue($value, $record = null) {
|
||||
if(empty($value) && $record) {
|
||||
if($record instanceof DataObject) {
|
||||
$name = $this->getName();
|
||||
public function setValue($value, $source = null) {
|
||||
if($source instanceof DataObject) {
|
||||
$name = $this->getName();
|
||||
|
||||
if($record->hasMethod($name)) {
|
||||
$value = $record->$name()->getIDList();
|
||||
}
|
||||
} elseif($record instanceof SS_List) {
|
||||
$value = $record->column('ID');
|
||||
if($source->hasMethod($name)) {
|
||||
$value = $source->$name()->getIDList();
|
||||
}
|
||||
} elseif($value instanceof SS_List) {
|
||||
$value = $value->column('ID');
|
||||
}
|
||||
|
||||
return parent::setValue($value, $record);
|
||||
return parent::setValue(array_filter($value));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -241,108 +227,96 @@ class TagField extends DropdownField {
|
||||
parent::saveInto($record);
|
||||
|
||||
$name = $this->getName();
|
||||
$relationTitle = $this->getRelationTitle();
|
||||
$titleField = $this->getTitleField();
|
||||
|
||||
$source = $this->getSource();
|
||||
|
||||
$dataClass = $source->dataClass();
|
||||
|
||||
$values = $this->Value();
|
||||
|
||||
if(empty($values) || empty($record) || empty($relationTitle)) {
|
||||
if(!$values) {
|
||||
$values = array();
|
||||
}
|
||||
|
||||
if(empty($record) || empty($source) || empty($titleField)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($record->hasMethod($name)) {
|
||||
$relation = $record->$name();
|
||||
|
||||
$class = $relation->dataClass();
|
||||
|
||||
foreach($values as $i => $value) {
|
||||
if(!is_numeric($value)) {
|
||||
if($this->getReadOnly()) {
|
||||
unset($values[$i]);
|
||||
continue;
|
||||
} else {
|
||||
$instance = new $class();
|
||||
$instance->{$relationTitle} = $value;
|
||||
$instance->write();
|
||||
|
||||
$values[$i] = $instance->ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$relation->setByIDList($values);
|
||||
} else {
|
||||
$record->$name = implode(',', $values);
|
||||
if(!$record->hasMethod($name)) {
|
||||
throw new Exception(
|
||||
sprintf("%s does not have a %s method", get_class($record), $name)
|
||||
);
|
||||
}
|
||||
|
||||
$relation = $record->$name();
|
||||
|
||||
foreach($values as $i => $value) {
|
||||
if(!is_numeric($value)) {
|
||||
if(!$this->getCanCreate()) {
|
||||
unset($values[$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$record = new $dataClass();
|
||||
$record->{$titleField} = $value;
|
||||
$record->write();
|
||||
|
||||
$values[$i] = $record->ID;
|
||||
}
|
||||
}
|
||||
|
||||
if($values instanceof SS_List) {
|
||||
$values = iterator_to_array($values);
|
||||
}
|
||||
|
||||
$relation->setByIDList(array_filter($values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON string of tags, for ajax-based search.
|
||||
* Returns a JSON string of tags, for lazy loading.
|
||||
*
|
||||
* @param SS_HTTPRequest $request
|
||||
*
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function suggest(SS_HTTPRequest $request) {
|
||||
$recordClass = $this->getRecordClass();
|
||||
$tags = $this->getTags($request->getVar('term'));
|
||||
|
||||
$response = new SS_HTTPResponse();
|
||||
|
||||
$response->addHeader('Content-Type', 'application/json');
|
||||
|
||||
$response->setBody(Convert::raw2json(
|
||||
array('items' => array())
|
||||
));
|
||||
|
||||
if($recordClass !== null) {
|
||||
$name = $this->getName();
|
||||
|
||||
/**
|
||||
* @var DataObject $object
|
||||
*/
|
||||
$object = singleton($recordClass);
|
||||
|
||||
$term = $request->getVar('term');
|
||||
|
||||
$tags = array();
|
||||
|
||||
if($object->hasMethod($name)) {
|
||||
$tags = $this->getObjectTags($object, $term);
|
||||
} elseif($object->hasField($name)) {
|
||||
$tags = $this->getStringTags($term);
|
||||
}
|
||||
|
||||
$response->setBody(Convert::raw2json(
|
||||
array('items' => $tags)
|
||||
));
|
||||
}
|
||||
$response->setBody(json_encode(array('items' => $tags)));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of arrays representing DataObject-based tags.
|
||||
* Returns array of arrays representing tags.
|
||||
*
|
||||
* @param DataObject $instance
|
||||
* @param string $term
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getObjectTags(DataObject $instance, $term) {
|
||||
$name = $this->getName();
|
||||
$relationTitle = $this->getRelationTitle();
|
||||
protected function getTags($term) {
|
||||
/**
|
||||
* @var DataList $source
|
||||
*/
|
||||
$source = $this->getSource();
|
||||
|
||||
$relation = $instance->{$name}();
|
||||
$dataClass = $source->dataClass();
|
||||
|
||||
$titleField = $this->getTitleField();
|
||||
|
||||
$term = Convert::raw2sql($term);
|
||||
|
||||
$query = DataList::create($relation->dataClass())
|
||||
->filter($relationTitle . ':PartialMatch:nocase', $term)
|
||||
->sort($relationTitle)
|
||||
->limit($this->getAjaxItemLimit());
|
||||
$query = $dataClass::get()
|
||||
->filter($titleField . ':PartialMatch:nocase', $term)
|
||||
->sort($titleField)
|
||||
->limit($this->getLazyLoadItemLimit());
|
||||
|
||||
$items = array();
|
||||
|
||||
foreach($query->map('ID', $relationTitle) as $id => $title) {
|
||||
foreach($query->map('ID', $titleField) as $id => $title) {
|
||||
if(!in_array($title, $items)) {
|
||||
$items[] = array(
|
||||
'id' => $id,
|
||||
@ -353,39 +327,4 @@ class TagField extends DropdownField {
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of arrays representing string-based tags.
|
||||
*
|
||||
* @param string $term
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getStringTags($term) {
|
||||
$name = $this->getName();
|
||||
$recordClass = $this->getRecordClass();
|
||||
|
||||
$term = Convert::raw2sql($term);
|
||||
|
||||
$query = DataObject::get($recordClass)
|
||||
->filter($name . ':PartialMatch:nocase', $term)
|
||||
->limit($this->getAjaxItemLimit());
|
||||
|
||||
$items = array();
|
||||
|
||||
foreach($query->column($name) as $tags) {
|
||||
$tags = explode(',', $tags);
|
||||
|
||||
foreach($tags as $i => $tag) {
|
||||
if(stripos($tag, $term) !== false && !in_array($tag, $items)) {
|
||||
$items[] = array(
|
||||
'id' => $tag,
|
||||
'text' => $tag
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
$.entwine('ss', function ($) {
|
||||
|
||||
$('.silverstripe-tag-field + .chzn-container').entwine({
|
||||
$('.ss-tag-field + .chzn-container').entwine({
|
||||
applySelect2: function () {
|
||||
var self = this,
|
||||
$select = $(this).prev();
|
||||
@ -40,9 +40,9 @@
|
||||
'tokenSeparators': [',', ' ']
|
||||
};
|
||||
|
||||
if ($select.attr('data-suggest-url')) {
|
||||
if ($select.attr('data-ss-tag-field-suggest-url')) {
|
||||
options.ajax = {
|
||||
'url': $select.attr('data-suggest-url'),
|
||||
'url': $select.attr('data-ss-tag-field-suggest-url'),
|
||||
'dataType': 'json',
|
||||
'delay': 250,
|
||||
'data': function (params) {
|
||||
@ -62,18 +62,6 @@
|
||||
$select
|
||||
.chosenDestroy()
|
||||
.select2(options);
|
||||
|
||||
/*
|
||||
* Delay a cycle so select2 is initialised before
|
||||
* selecting values (if data-selected-values is present).
|
||||
*/
|
||||
setTimeout(function () {
|
||||
if ($select.attr('data-selected-values')) {
|
||||
var values = $select.attr('data-selected-values');
|
||||
|
||||
$select.select2('val', values.split(','));
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
onmatch: function () {
|
||||
this.applySelect2();
|
||||
|
149
tests/StringTagFieldTest.php
Executable file
149
tests/StringTagFieldTest.php
Executable file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @mixin PHPUnit_Framework_TestCase
|
||||
*/
|
||||
class StringTagFieldTest extends SapphireTest {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $fixture_file = 'tagfield/tests/StringTagFieldTest.yml';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $extraDataObjects = array(
|
||||
'StringTagFieldTestBlogPost',
|
||||
);
|
||||
|
||||
function testItSavesTagsOnNewRecords() {
|
||||
$record = $this->getNewStringTagFieldTestBlogPost('BlogPost1');
|
||||
|
||||
$field = new StringTagField('Tags');
|
||||
$field->setValue(array('Tag1', 'Tag2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->assertEquals('Tag1,Tag2', $record->Tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return StringTagFieldTestBlogPost
|
||||
*/
|
||||
protected function getNewStringTagFieldTestBlogPost($name) {
|
||||
return $this->objFromFixture(
|
||||
'StringTagFieldTestBlogPost',
|
||||
$name
|
||||
);
|
||||
}
|
||||
|
||||
function testItSavesTagsOnExistingRecords() {
|
||||
$record = $this->getNewStringTagFieldTestBlogPost('BlogPost1');
|
||||
$record->write();
|
||||
|
||||
$field = new StringTagField('Tags');
|
||||
$field->setValue(array('Tag1', 'Tag2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$this->assertEquals('Tag1,Tag2', $record->Tags);
|
||||
}
|
||||
|
||||
function testItSuggestsTags() {
|
||||
$record = $this->getNewStringTagFieldTestBlogPost('BlogPost2');
|
||||
|
||||
$field = new StringTagField('Tags');
|
||||
$field->setRecord($record);
|
||||
|
||||
/**
|
||||
* Partial tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'Tag'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[{"id":"Tag1","text":"Tag1"},{"id":"Tag2","text":"Tag2"}]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
|
||||
/**
|
||||
* Exact tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'Tag1'));
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":"Tag1","text":"Tag1"}]}');
|
||||
|
||||
/**
|
||||
* Case-insensitive tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'TAG1'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[{"id":"Tag1","text":"Tag1"}]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
|
||||
/**
|
||||
* No tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'unknown'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return SS_HTTPRequest
|
||||
*/
|
||||
protected function getNewRequest(array $parameters) {
|
||||
return new SS_HTTPRequest(
|
||||
'get',
|
||||
'StringTagFieldTestController/StringTagFieldTestForm/fields/Tags/suggest',
|
||||
$parameters
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @property string $Tags
|
||||
*/
|
||||
class StringTagFieldTestBlogPost extends DataObject implements TestOnly {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
'Title' => 'Text',
|
||||
'Content' => 'Text',
|
||||
'Tags' => 'Text',
|
||||
);
|
||||
}
|
||||
|
||||
class StringTagFieldTestController extends Controller implements TestOnly {
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function StringTagFieldTestForm() {
|
||||
$fields = new FieldList(
|
||||
$tagField = new StringTagField('Tags')
|
||||
);
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction('StringTagFieldTestFormSubmit')
|
||||
);
|
||||
|
||||
return new Form($this, 'StringTagFieldTestForm', $fields, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataObject $dataObject
|
||||
* @param Form $form
|
||||
*/
|
||||
public function StringTagFieldTestFormSubmit(DataObject $dataObject, Form $form) {
|
||||
$form->saveInto($dataObject);
|
||||
}
|
||||
}
|
6
tests/StringTagFieldTest.yml
Executable file
6
tests/StringTagFieldTest.yml
Executable file
@ -0,0 +1,6 @@
|
||||
StringTagFieldTestBlogPost:
|
||||
BlogPost1:
|
||||
Title: BlogPost1
|
||||
BlogPost2:
|
||||
Title: BlogPost2
|
||||
Tags: Tag1,Tag2
|
269
tests/TagFieldTest.php
Executable file
269
tests/TagFieldTest.php
Executable file
@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @mixin PHPUnit_Framework_TestCase
|
||||
*/
|
||||
class TagFieldTest extends SapphireTest {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $fixture_file = 'tagfield/tests/TagFieldTest.yml';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $extraDataObjects = array(
|
||||
'TagFieldTestBlogTag',
|
||||
'TagFieldTestBlogPost',
|
||||
);
|
||||
|
||||
function testItSavesLinksToNewTagsOnNewRecords() {
|
||||
$record = $this->getNewTagFieldTestBlogPost('BlogPost1');
|
||||
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
$field->setValue(array('Tag3', 'Tag4'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag3', 'Tag4'),
|
||||
$record
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return TagFieldTestBlogPost
|
||||
*/
|
||||
protected function getNewTagFieldTestBlogPost($name) {
|
||||
return $this->objFromFixture(
|
||||
'TagFieldTestBlogPost',
|
||||
$name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $expected
|
||||
* @param TagFieldTestBlogPost $record
|
||||
*/
|
||||
protected function compareExpectedAndActualTags(array $expected, TagFieldTestBlogPost $record) {
|
||||
$actual = array_values($record->Tags()->map('ID', 'Title')->toArray());
|
||||
|
||||
sort($expected);
|
||||
sort($actual);
|
||||
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$actual
|
||||
);
|
||||
}
|
||||
|
||||
public function testItSavesLinksToNewTagsOnExistingRecords() {
|
||||
$record = $this->getNewTagFieldTestBlogPost('BlogPost1');
|
||||
$record->write();
|
||||
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
$field->setValue(array('Tag3', 'Tag4'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag3', 'Tag4'),
|
||||
$record
|
||||
);
|
||||
}
|
||||
|
||||
public function testItSavesLinksToExistingTagsOnNewRecords() {
|
||||
$record = $this->getNewTagFieldTestBlogPost('BlogPost1');
|
||||
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
$field->setValue(array('Tag1', 'Tag2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag1', 'Tag2'),
|
||||
$record
|
||||
);
|
||||
}
|
||||
|
||||
public function testItSavesLinksToExistingTagsOnExistingRecords() {
|
||||
$record = $this->getNewTagFieldTestBlogPost('BlogPost1');
|
||||
$record->write();
|
||||
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
$field->setValue(array('Tag1', 'Tag2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag1', 'Tag2'),
|
||||
$record
|
||||
);
|
||||
}
|
||||
|
||||
function testItSuggestsTags() {
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
|
||||
|
||||
/**
|
||||
* Partial tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'Tag'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[{"id":1,"text":"Tag1"},{"id":2,"text":"Tag2"}]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
|
||||
/**
|
||||
* Exact tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'Tag1'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[{"id":1,"text":"Tag1"}]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
|
||||
/**
|
||||
* Case-insensitive tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'TAG1'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[{"id":1,"text":"Tag1"}]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
|
||||
/**
|
||||
* No tag title match.
|
||||
*/
|
||||
$request = $this->getNewRequest(array('term' => 'unknown'));
|
||||
|
||||
$this->assertEquals(
|
||||
'{"items":[]}',
|
||||
$field->suggest($request)->getBody()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return SS_HTTPRequest
|
||||
*/
|
||||
protected function getNewRequest(array $parameters) {
|
||||
return new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTestController/TagFieldTestForm/fields/Tags/suggest',
|
||||
$parameters
|
||||
);
|
||||
}
|
||||
|
||||
function testItDisplaysValuesFromRelations() {
|
||||
$record = $this->getNewTagFieldTestBlogPost('BlogPost1');
|
||||
$record->write();
|
||||
|
||||
$form = new Form(
|
||||
new TagFieldTestController($record),
|
||||
'Form',
|
||||
new FieldList(
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'))
|
||||
),
|
||||
new FieldList()
|
||||
);
|
||||
|
||||
$form->loadDataFrom(
|
||||
$this->objFromFixture('TagFieldTestBlogPost', 'BlogPost2')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->Value(), array(1 => 1, 2 => 2));
|
||||
}
|
||||
|
||||
function testItIgnoresNewTagsIfCannotCreate() {
|
||||
$record = new TagFieldTestBlogPost();
|
||||
$record->write();
|
||||
|
||||
$tag = TagFieldTestBlogTag::get()->filter('Title', 'Tag1')->first();
|
||||
|
||||
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'), array($tag->ID, 'Tag3'));
|
||||
$field->setCanCreate(false);
|
||||
$field->saveInto($record);
|
||||
|
||||
/**
|
||||
* @var TagFieldTestBlogPost $record
|
||||
*/
|
||||
$record = DataObject::get_by_id('TagFieldTestBlogPost', $record->ID);
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
array('Tag1'),
|
||||
$record
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TagFieldTestBlogTag extends DataObject implements TestOnly {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $default_sort = '"TagFieldTestBlogTag"."ID" ASC';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
'Title' => 'Varchar(200)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $belongs_many_many = array(
|
||||
'BlogPosts' => 'TagFieldTestBlogPost',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @method ManyManyList Tags()
|
||||
*/
|
||||
class TagFieldTestBlogPost extends DataObject implements TestOnly {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
'Title' => 'Text',
|
||||
'Content' => 'Text',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $many_many = array(
|
||||
'Tags' => 'TagFieldTestBlogTag',
|
||||
);
|
||||
}
|
||||
|
||||
class TagFieldTestController extends Controller implements TestOnly {
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function TagFieldTestForm() {
|
||||
$fields = new FieldList(
|
||||
$tagField = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'))
|
||||
);
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction('TagFieldTestFormSubmit')
|
||||
);
|
||||
|
||||
return new Form($this, 'TagFieldTestForm', $fields, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataObject $dataObject
|
||||
* @param Form $form
|
||||
*/
|
||||
public function TagFieldTestFormSubmit(DataObject $dataObject, Form $form) {
|
||||
$form->saveInto($dataObject);
|
||||
}
|
||||
}
|
11
tests/TagFieldTest.yml
Executable file
11
tests/TagFieldTest.yml
Executable file
@ -0,0 +1,11 @@
|
||||
TagFieldTestBlogTag:
|
||||
Tag1:
|
||||
Title: Tag1
|
||||
Tag2:
|
||||
Title: Tag2
|
||||
TagFieldTestBlogPost:
|
||||
BlogPost1:
|
||||
Title: BlogPost1
|
||||
BlogPost2:
|
||||
Title: BlogPost2
|
||||
Tags: =>TagFieldTestBlogTag.Tag1,=>TagFieldTestBlogTag.Tag2
|
@ -1,365 +0,0 @@
|
||||
<?php
|
||||
|
||||
class TagFieldTest extends SapphireTest {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $fixture_file = 'tagfield/tests/unit/TagFieldTest.yml';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $extraDataObjects = array(
|
||||
'TagFieldTest_BlogTag',
|
||||
'TagFieldTest_BlogPost',
|
||||
);
|
||||
|
||||
public function testItSavesLinksToExistingTagsOnExistingRecords() {
|
||||
$record = $this->objFromFixture(
|
||||
'TagFieldTest_BlogPost',
|
||||
'BlogPost1'
|
||||
);
|
||||
|
||||
$field = new TagField('Tags');
|
||||
$field->setValue(array('Object1', 'Object2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
$record,
|
||||
array('Object1', 'Object2')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataObject $record
|
||||
* @param array $expected
|
||||
*/
|
||||
protected function compareExpectedAndActualTags(DataObject $record, array $expected) {
|
||||
$compare1 = array_values($record->Tags()->map('ID', 'Title')->toArray());
|
||||
$compare2 = $expected;
|
||||
|
||||
sort($compare1);
|
||||
sort($compare2);
|
||||
|
||||
$this->assertEquals(
|
||||
$compare1,
|
||||
$compare2
|
||||
);
|
||||
}
|
||||
|
||||
public function testItSavesLinksToExistingTagsOnNewRecords() {
|
||||
$record = new TagFieldTest_BlogPost();
|
||||
$record->write();
|
||||
|
||||
$field = new TagField('Tags');
|
||||
$field->setValue(array('Object1', 'Object2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
$record,
|
||||
array('Object1', 'Object2')
|
||||
);
|
||||
}
|
||||
|
||||
public function testItSavesLinksToNewTagsOnExistingRecords() {
|
||||
$record = $this->objFromFixture(
|
||||
'TagFieldTest_BlogPost',
|
||||
'BlogPost1'
|
||||
);
|
||||
|
||||
$field = new TagField('Tags');
|
||||
$field->setValue(array('Object3', 'Object4'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
$record,
|
||||
array('Object3', 'Object4')
|
||||
);
|
||||
}
|
||||
|
||||
function testItSavesLinksToNewTagsOnNewRecords() {
|
||||
$record = new TagFieldTest_BlogPost();
|
||||
$record->write();
|
||||
|
||||
$field = new TagField('Tags');
|
||||
$field->setValue(array('Object3', 'Object4'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
$record,
|
||||
array('Object3', 'Object4')
|
||||
);
|
||||
}
|
||||
|
||||
function testItSavesTextBasedTagsOnExistingRecords() {
|
||||
$record = $this->objFromFixture(
|
||||
'TagFieldTest_BlogPost',
|
||||
'BlogPost1'
|
||||
);
|
||||
|
||||
$field = new TagField('TextBasedTags');
|
||||
$field->setValue(array('Text1', 'Text2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->assertEquals(
|
||||
$record->TextBasedTags,
|
||||
'Text1,Text2'
|
||||
);
|
||||
}
|
||||
|
||||
function testItSavesTextBasedTagsOnNewRecords() {
|
||||
$record = new TagFieldTest_BlogPost();
|
||||
$record->write();
|
||||
|
||||
$field = new TagField('TextBasedTags');
|
||||
$field->setValue(array('Text1', 'Text2'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->assertEquals(
|
||||
$record->TextBasedTags,
|
||||
'Text1,Text2'
|
||||
);
|
||||
}
|
||||
|
||||
function testItSuggestsObjectTags() {
|
||||
$field = new TagField('Tags');
|
||||
$field->setRecordClass('TagFieldTest_BlogPost');
|
||||
|
||||
/**
|
||||
* Partial tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/ObjectTestForm/fields/Tags/suggest',
|
||||
array('term' => 'Object')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":1,"text":"Object1"},{"id":2,"text":"Object2"}]}');
|
||||
|
||||
/**
|
||||
* Exact tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/ObjectTestForm/fields/Tags/suggest',
|
||||
array('term' => 'Object1')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":1,"text":"Object1"}]}');
|
||||
|
||||
/**
|
||||
* Case-insensitive tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/ObjectTestForm/fields/Tags/suggest',
|
||||
array('term' => 'OBJECT1')
|
||||
);
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":1,"text":"Object1"}]}');
|
||||
|
||||
/**
|
||||
* No tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/ObjectTestForm/fields/Tags/suggest',
|
||||
array('term' => 'unknown')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[]}');
|
||||
}
|
||||
|
||||
function testItSuggestsTextTags() {
|
||||
$field = new TagField('TextBasedTags');
|
||||
$field->setRecordClass('TagFieldTest_BlogPost');
|
||||
|
||||
/**
|
||||
* Partial tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/TextBasedTestForm/fields/Tags/suggest',
|
||||
array('term' => 'Text')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":"Text1","text":"Text1"},{"id":"Text2","text":"Text2"}]}');
|
||||
|
||||
/**
|
||||
* Exact tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/TextBasedTestForm/fields/Tags/suggest',
|
||||
array('term' => 'Text1')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":"Text1","text":"Text1"}]}');
|
||||
|
||||
/**
|
||||
* Case-insensitive tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/TextBasedTestForm/fields/Tags/suggest',
|
||||
array('term' => 'TEXT1')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[{"id":"Text1","text":"Text1"}]}');
|
||||
|
||||
/**
|
||||
* No tag title match.
|
||||
*/
|
||||
$request = new SS_HTTPRequest(
|
||||
'get',
|
||||
'TagFieldTest_Controller/TextBasedTestForm/fields/Tags/suggest',
|
||||
array('term' => 'unknown')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->suggest($request)->getBody(), '{"items":[]}');
|
||||
}
|
||||
|
||||
function testItDisplaysValuesFromRelations() {
|
||||
$form = new Form(
|
||||
$this,
|
||||
'Form',
|
||||
new FieldList(
|
||||
$field = new TagField('Tags')
|
||||
),
|
||||
new FieldList()
|
||||
);
|
||||
|
||||
$form->loadDataFrom(
|
||||
$this->objFromFixture('TagFieldTest_BlogPost', 'BlogPost3')
|
||||
);
|
||||
|
||||
$this->assertEquals($field->Value(), array(1 => 1, 2 => 2));
|
||||
}
|
||||
|
||||
function testItIgnoresNewTagsIfReadOnly() {
|
||||
$record = new TagFieldTest_BlogPost();
|
||||
$record->write();
|
||||
|
||||
$tag = TagFieldTest_BlogTag::get()->filter('Title', 'Object1')->first();
|
||||
|
||||
$field = new TagField('Tags');
|
||||
$field->setReadOnly(true);
|
||||
$field->setValue(array($tag->ID, 'Object3'));
|
||||
$field->saveInto($record);
|
||||
|
||||
$record = DataObject::get_by_id('TagFieldTest_BlogPost', $record->ID);
|
||||
|
||||
$this->compareExpectedAndActualTags(
|
||||
$record,
|
||||
array('Object1')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TagFieldTest_BlogTag extends DataObject implements TestOnly {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $default_sort = '"TagFieldTest_BlogTag"."ID" ASC';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
'Title' => 'Varchar(200)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $belongs_many_many = array(
|
||||
'BlogEntries' => 'TagFieldTest_BlogPost',
|
||||
);
|
||||
}
|
||||
|
||||
class TagFieldTest_BlogPost extends DataObject implements TestOnly {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $default_sort = '"TagFieldTest_BlogPost"."ID" ASC';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
'Title' => 'Text',
|
||||
'Content' => 'Text',
|
||||
'TextBasedTags' => 'Text',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $many_many = array(
|
||||
'Tags' => 'TagFieldTest_BlogTag',
|
||||
);
|
||||
}
|
||||
|
||||
class TagFieldTest_Controller extends Controller implements TestOnly {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $url_handlers = array(
|
||||
'$Action//$ID/$OtherID' => "handleAction",
|
||||
);
|
||||
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function ObjectTestForm() {
|
||||
$fields = new FieldList(
|
||||
$tagField = new TagField('Tags')
|
||||
);
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction('ObjectTestForm_submit')
|
||||
);
|
||||
|
||||
return new Form($this, 'ObjectTestForm', $fields, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param Form $form
|
||||
*/
|
||||
public function ObjectTestForm_submit(array $data, Form $form) {
|
||||
$data->saveInto($form);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function TextBasedTestForm() {
|
||||
$fields = new FieldList(
|
||||
$tagField = new TagField('TextBasedTags')
|
||||
);
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction('TextBasedTestForm_submit')
|
||||
);
|
||||
|
||||
return new Form($this, 'TextBasedTestForm', $fields, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param Form $form
|
||||
*/
|
||||
public function TextBasedTestForm_submit(array $data, Form $form) {
|
||||
$data->saveInto($form);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
TagFieldTest_BlogTag:
|
||||
Object1:
|
||||
Title: Object1
|
||||
Object2:
|
||||
Title: Object2
|
||||
TagFieldTest_BlogPost:
|
||||
BlogPost1:
|
||||
Title: BlogPost1
|
||||
BlogPost2:
|
||||
Title: BlogPost2
|
||||
TextBasedTags: Text1,Text2
|
||||
BlogPost3:
|
||||
Title: BlogPost3
|
||||
Tags: =>TagFieldTest_BlogTag.Object1,=>TagFieldTest_BlogTag.Object2
|
Loading…
x
Reference in New Issue
Block a user