SilverStripe 4 compatibility (#87)

* Update composer constraint and branch alias to support SS4 testing

* Add namespaces, update DataList quirk with getSourceList

* Add PSR-4 autoloader definition

* Move template to correct namespace location, update requirement paths

* FIX Visibility on allowed actions

* FIX Update chosen class names to match updates in framework

* Update Travis configuration for 4.x builds. Update docs for namespaced classes.

* Use "4" for the release instead of master.

* FIX Selected tag height. Move Readonly to own class.
This commit is contained in:
Robbie Averill 2017-01-14 08:11:59 +13:00 committed by Daniel Hensby
parent 4ce0560d6e
commit 518189e2ef
13 changed files with 226 additions and 158 deletions

View File

@ -6,4 +6,4 @@ checks:
duplication: true duplication: true
filter: filter:
paths: [code/*, tests/*] paths: [src/*, tests/*]

View File

@ -4,26 +4,18 @@ sudo: false
language: php language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
env:
- DB=MYSQL CORE_RELEASE=3.2
matrix: matrix:
include: include:
- php: 5.5
env: DB=MYSQL CORE_RELEASE=4
- php: 5.6 - php: 5.6
env: DB=MYSQL CORE_RELEASE=3 env: DB=MYSQL CORE_RELEASE=4
- php: 5.6 - php: 5.6
env: DB=MYSQL CORE_RELEASE=3.1 env: DB=PGSQL CORE_RELEASE=4
- php: 5.6
env: DB=PGSQL CORE_RELEASE=3.2
allow_failures:
- php: 7.0 - php: 7.0
env: DB=MYSQL CORE_RELEASE=4
- php: 7.0
env: DB=PGSQL CORE_RELEASE=4
before_script: before_script:
- composer self-update || true - composer self-update || true

View File

@ -1,29 +1,34 @@
{ {
"name": "silverstripe/tagfield", "name": "silverstripe/tagfield",
"description": "Tag field for Silverstripe", "description": "Tag field for Silverstripe",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"type": "silverstripe-module", "type": "silverstripe-module",
"keywords": [ "keywords": [
"silverstripe", "silverstripe",
"tag", "tag",
"field" "field"
], ],
"authors": [ "authors": [
{ {
"name": "Christopher Pitt", "name": "Christopher Pitt",
"email": "chris@silverstripe.com", "email": "chris@silverstripe.com",
"homepage": "http://github.com/assertchris" "homepage": "http://github.com/assertchris"
} }
], ],
"support": { "support": {
"issues": "http://github.com/silverstripe-labs/silverstripe-tagfield/issues" "issues": "http://github.com/silverstripe-labs/silverstripe-tagfield/issues"
}, },
"require": { "require": {
"silverstripe/framework": "~3.1" "silverstripe/framework": "^4.0"
}, },
"extra": { "autoload": {
"branch-alias": { "psr-4": {
"dev-master": "2.x-dev" "SilverStripe\\TagField\\": "src/"
} }
} },
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
}
} }

View File

@ -50,7 +50,7 @@
} }
.select2-selection__choice { .select2-selection__choice {
height: 13px; height: 22px;
line-height: 13px; line-height: 13px;
-webkit-border-radius: 3px; -webkit-border-radius: 3px;
-moz-border-radius: 3px; -moz-border-radius: 3px;
@ -100,4 +100,4 @@
background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%) !important; background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%) !important;
background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%) !important; background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%) !important;
color: #fff !important; color: #fff !important;
} }

View File

@ -3,19 +3,21 @@
The primary use, for this module, is as a custom input field interface. For instance, imagine you had the following data objects: The primary use, for this module, is as a custom input field interface. For instance, imagine you had the following data objects:
```php ```php
class BlogPost extends DataObject { class BlogPost extends DataObject
{
private static $many_many = array( private static $many_many = array(
'BlogTags' => 'BlogTag' 'BlogTags' => 'SilverStripe\\Blog\\Model\\BlogTag'
); );
} }
class BlogTag extends DataObject { class BlogTag extends DataObject
{
private static $db = array( private static $db = array(
'Title' => 'Varchar(200)', 'Title' => 'Varchar(200)'
); );
private static $belongs_many_many = array( private static $belongs_many_many = array(
'BlogPosts' => 'BlogPost' 'BlogPosts' => 'SilverStripe\\Blog\\Model\\BlogPost'
); );
} }
``` ```
@ -33,6 +35,8 @@ $field = TagField::create(
->setCanCreate(true); // new tag DataObjects can be created ->setCanCreate(true); // new tag DataObjects can be created
``` ```
**Note:** This assumes you have imported the namespaces class, e.g. `use SilverStripe\TagField\TagField;`.
This will present a tag field, in which you can select existing blog tags or create new ones. They will be created/linked after the blog posts are saved. This will present a tag field, in which you can select existing blog tags or create new ones. They will be created/linked after the blog posts are saved.
You can also store string-based tags, for blog posts, with the following field type: You can also store string-based tags, for blog posts, with the following field type:
@ -51,7 +55,8 @@ $field->setShouldLazyLoad(true); // tags should be lazy loaded
This assumes you are storing tags in the following data object structure: This assumes you are storing tags in the following data object structure:
```php ```php
class BlogPost extends DataObject { class BlogPost extends DataObject
{
private static $db = array( private static $db = array(
'Tags' => 'Text' 'Tags' => 'Text'
); );

View File

@ -10,11 +10,11 @@
*/ */
$.fn.chosenDestroy = function () { $.fn.chosenDestroy = function () {
var $this = $(this); var $this = $(this);
if ($this.siblings('.chzn-container').length) { if ($this.siblings('.chosen-container').length) {
$this $this
.show() // The field needs to be visible so Select2 evaluates the width correctly. .show() // The field needs to be visible so Select2 evaluates the width correctly.
.removeClass('chzn-done') .removeClass('chosen-done')
.removeClass('has-chzn') .removeClass('has-chosen')
.next() .next()
.remove(); .remove();
} }
@ -23,7 +23,7 @@
$.entwine('ss', function ($) { $.entwine('ss', function ($) {
$('.ss-tag-field.has-chzn + .chzn-container, .ss-tag-field:not(.has-chzn)').entwine({ $('.ss-tag-field.has-chosen + .chosen-container, .ss-tag-field:not(.has-chosen)').entwine({
applySelect2: function () { applySelect2: function () {
var self = this, var self = this,
$select = $(this); $select = $(this);

4
src/.upgrade.yml Normal file
View File

@ -0,0 +1,4 @@
mappings:
StringTagField: SilverStripe\TagField\StringTagField
TagField: SilverStripe\TagField\TagField
TagField_Readonly: SilverStripe\TagField\TagField\Readonly

View File

@ -1,12 +1,26 @@
<?php <?php
namespace SilverStripe\TagField;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\DropdownField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\SS_List;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
/** /**
* Provides a tagging interface, storing comma-delimited tags in a DataObject string field. * 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 * This is intended bridge the gap between 1.x and 2.x, and when possible TagField should be used
* instead. * instead.
* *
* @package forms * @package tagfield
* @subpackage fields * @subpackage fields
*/ */
class StringTagField extends DropdownField class StringTagField extends DropdownField
@ -14,9 +28,9 @@ class StringTagField extends DropdownField
/** /**
* @var array * @var array
*/ */
public static $allowed_actions = array( public static $allowed_actions = [
'suggest', 'suggest'
); ];
/** /**
* @var bool * @var bool
@ -43,17 +57,6 @@ class StringTagField extends DropdownField
*/ */
protected $isMultiple = true; protected $isMultiple = true;
/**
* @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 * @return bool
*/ */
@ -150,8 +153,8 @@ class StringTagField extends DropdownField
Requirements::css(TAG_FIELD_DIR . '/css/select2.min.css'); Requirements::css(TAG_FIELD_DIR . '/css/select2.min.css');
Requirements::css(TAG_FIELD_DIR . '/css/TagField.css'); Requirements::css(TAG_FIELD_DIR . '/css/TagField.css');
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery/jquery.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js'); Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js'); Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js');
Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js'); Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js');
@ -173,7 +176,7 @@ class StringTagField extends DropdownField
return $this return $this
->customise($properties) ->customise($properties)
->renderWith(array("templates/TagField")); ->renderWith(TagField::class);
} }
/** /**
@ -264,17 +267,16 @@ class StringTagField extends DropdownField
/** /**
* Returns a JSON string of tags, for lazy loading. * Returns a JSON string of tags, for lazy loading.
* *
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* * @return HTTPResponse
* @return SS_HTTPResponse
*/ */
public function suggest(SS_HTTPRequest $request) public function suggest(HTTPRequest $request)
{ {
$responseBody = Convert::raw2json( $responseBody = Convert::raw2json(
array('items' => array()) array('items' => array())
); );
$response = new SS_HTTPResponse(); $response = new HTTPResponse;
$response->addHeader('Content-Type', 'application/json'); $response->addHeader('Content-Type', 'application/json');
if ($record = $this->getRecord()) { if ($record = $this->getRecord()) {

View File

@ -1,5 +1,21 @@
<?php <?php
namespace SilverStripe\TagField;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\SS_List;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
/** /**
* Provides a tagging interface, storing links between tag DataObjects and a parent DataObject. * Provides a tagging interface, storing links between tag DataObjects and a parent DataObject.
* *
@ -11,8 +27,8 @@ class TagField extends DropdownField
/** /**
* @var array * @var array
*/ */
public static $allowed_actions = array( private static $allowed_actions = array(
'suggest', 'suggest'
); );
/** /**
@ -35,6 +51,11 @@ class TagField extends DropdownField
*/ */
protected $titleField = 'Title'; protected $titleField = 'Title';
/**
* @var DataList
*/
protected $sourceList;
/** /**
* @var bool * @var bool
*/ */
@ -48,6 +69,7 @@ class TagField extends DropdownField
*/ */
public function __construct($name, $title = '', $source = null, $value = null) public function __construct($name, $title = '', $source = null, $value = null)
{ {
$this->setSourceList($source);
parent::__construct($name, $title, $source, $value); parent::__construct($name, $title, $source, $value);
} }
@ -151,6 +173,26 @@ class TagField extends DropdownField
return $this; return $this;
} }
/**
* Get the DataList source. The 4.x upgrade for SelectField::setSource starts to convert this to an array
* @return DataList
*/
public function getSourceList()
{
return $this->sourceList;
}
/**
* Set the model class name for tags
* @param DataList $className
* @return self
*/
public function setSourceList($sourceList)
{
$this->sourceList = $sourceList;
return $this;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -159,8 +201,8 @@ class TagField extends DropdownField
Requirements::css(TAG_FIELD_DIR . '/css/select2.min.css'); Requirements::css(TAG_FIELD_DIR . '/css/select2.min.css');
Requirements::css(TAG_FIELD_DIR . '/css/TagField.css'); Requirements::css(TAG_FIELD_DIR . '/css/TagField.css');
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery/jquery.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js'); Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js'); Requirements::javascript(TAG_FIELD_DIR . '/js/select2.js');
Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js'); Requirements::javascript(TAG_FIELD_DIR . '/js/TagField.js');
@ -182,7 +224,7 @@ class TagField extends DropdownField
return $this return $this
->customise($properties) ->customise($properties)
->renderWith(array("templates/TagField")); ->renderWith(self::class);
} }
/** /**
@ -200,21 +242,21 @@ class TagField extends DropdownField
{ {
$options = ArrayList::create(); $options = ArrayList::create();
$source = $this->getSource(); $source = $this->getSourceList();
if(!$source) { if(!$source) {
$source = new ArrayList(); $source = ArrayList::create();
} }
$dataClass = $source->dataClass(); $dataClass = $source->dataClass();
$values = $this->Value(); $values = $this->Value();
if(!$values) { if (!$values) {
return $options; return $options;
} }
if(is_array($values)) { if (is_array($values)) {
$values = DataList::create($dataClass)->filter('Title', $values); $values = DataList::create($dataClass)->filter('Title', $values);
} }
@ -276,26 +318,21 @@ class TagField extends DropdownField
parent::saveInto($record); parent::saveInto($record);
$name = $this->getName(); $name = $this->getName();
$titleField = $this->getTitleField(); $titleField = $this->getTitleField();
$source = $this->getSource(); $source = $this->getSource();
$values = $this->Value(); $values = $this->Value();
$relation = $record->$name(); $relation = $record->$name();
$ids = array(); $ids = array();
if(!$values) { if (!$values) {
$values = array(); $values = array();
} }
if(empty($record) || empty($source) || empty($titleField)) { if (empty($record) || empty($source) || empty($titleField)) {
return; return;
} }
if(!$record->hasMethod($name)) { if (!$record->hasMethod($name)) {
throw new Exception( throw new Exception(
sprintf("%s does not have a %s method", get_class($record), $name) sprintf("%s does not have a %s method", get_class($record), $name)
); );
@ -304,31 +341,31 @@ class TagField extends DropdownField
foreach ($values as $key => $value) { foreach ($values as $key => $value) {
// Get or create record // Get or create record
$record = $this->getOrCreateTag($value); $record = $this->getOrCreateTag($value);
if($record) { if ($record) {
$ids[] = $record->ID; $ids[] = $record->ID;
$values[$key] = $record->Title; $values[$key] = $record->Title;
} }
} }
$relation->setByIDList(array_filter($ids)); $relation->setByIDList(array_filter($ids));
} }
/** /**
* Get or create tag with the given value * Get or create tag with the given value
* *
* @param string $term * @param string $term
* @return DataObject * @return DataObject
*/ */
protected function getOrCreateTag($term) protected function getOrCreateTag($term)
{ {
// Check if existing record can be found // Check if existing record can be found
$source = $this->getSource(); /** @var DataList $source */
$source = $this->getSourceList();
$titleField = $this->getTitleField(); $titleField = $this->getTitleField();
$record = $source $record = $source
->filter($titleField, $term) ->filter($titleField, $term)
->first(); ->first();
if($record) { if ($record) {
return $record; return $record;
} }
@ -347,15 +384,14 @@ class TagField extends DropdownField
/** /**
* Returns a JSON string of tags, for lazy loading. * Returns a JSON string of tags, for lazy loading.
* *
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* * @return HTTPResponse
* @return SS_HTTPResponse
*/ */
public function suggest(SS_HTTPRequest $request) public function suggest(HTTPRequest $request)
{ {
$tags = $this->getTags($request->getVar('term')); $tags = $this->getTags($request->getVar('term'));
$response = new SS_HTTPResponse(); $response = new HTTPResponse();
$response->addHeader('Content-Type', 'application/json'); $response->addHeader('Content-Type', 'application/json');
$response->setBody(json_encode(array('items' => $tags))); $response->setBody(json_encode(array('items' => $tags)));
@ -365,16 +401,15 @@ class TagField extends DropdownField
/** /**
* Returns array of arrays representing tags. * Returns array of arrays representing tags.
* *
* @param string $term * @param string $term
*
* @return array * @return array
*/ */
protected function getTags($term) protected function getTags($term)
{ {
/** /**
* @var DataList $source * @var array $source
*/ */
$source = $this->getSource(); $source = $this->getSourceList();
$titleField = $this->getTitleField(); $titleField = $this->getTitleField();
@ -415,40 +450,8 @@ class TagField extends DropdownField
*/ */
public function performReadonlyTransformation() public function performReadonlyTransformation()
{ {
$copy = $this->castedCopy('TagField_Readonly'); $copy = $this->castedCopy(TagFieldReadonly::class);
$copy->setSource($this->getSource()); $copy->setSourceList($this->getSourceList());
return $copy; return $copy;
} }
} }
/**
* A readonly extension of TagField useful for non-editable items within the CMS.
*
* @package forms
* @subpackage fields
*/
class TagField_Readonly extends TagField
{
protected $readonly = true;
/**
* Render the readonly field as HTML.
*
* @param array $properties
* @return HTMLText
*/
public function Field($properties = array())
{
$options = array();
foreach ($this->getOptions()->filter('Selected', true) as $option) {
$options[] = $option->Title;
}
$field = ReadonlyField::create($this->name.'_Readonly', $this->title);
$field->setForm($this->form);
$field->setValue(implode(', ', $options));
return $field->Field();
}
}

41
src/TagField/Readonly.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace SilverStripe\TagField\TagField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\TagField\TagField;
/**
* A readonly extension of TagField useful for non-editable items within the CMS.
*
* @package forms
* @subpackage fields
*/
class Readonly extends TagField
{
/**
* {@inheritDoc}
*/
protected $readonly = true;
/**
* Render the readonly field as HTML.
*
* @param array $properties
* @return HTMLText
*/
public function Field($properties = array())
{
$options = array();
foreach ($this->getOptions()->filter('Selected', true) as $option) {
$options[] = $option->Title;
}
$field = ReadonlyField::create($this->name . '_Readonly', $this->title);
$field->setForm($this->form);
$field->setValue(implode(', ', $options));
return $field->Field();
}
}

View File

@ -1,5 +1,15 @@
<?php <?php
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\ORM\DataObject;
use SilverStripe\TagField\StringTagField;
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
@ -103,11 +113,11 @@ class StringTagFieldTest extends SapphireTest
/** /**
* @param array $parameters * @param array $parameters
* *
* @return SS_HTTPRequest * @return HTTPRequest
*/ */
protected function getNewRequest(array $parameters) protected function getNewRequest(array $parameters)
{ {
return new SS_HTTPRequest( return new HTTPRequest(
'get', 'get',
'StringTagFieldTestController/StringTagFieldTestForm/fields/Tags/suggest', 'StringTagFieldTestController/StringTagFieldTestForm/fields/Tags/suggest',
$parameters $parameters

View File

@ -1,5 +1,16 @@
<?php <?php
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
use SilverStripe\TagField\TagField;
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
@ -21,13 +32,10 @@ class TagFieldTest extends SapphireTest
public function testItSavesLinksToNewTagsOnNewRecords() public function testItSavesLinksToNewTagsOnNewRecords()
{ {
$record = $this->getNewTagFieldTestBlogPost('BlogPost1'); $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
$field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag')); $field = new TagField('Tags', '', new DataList('TagFieldTestBlogTag'));
$field->setValue(array('Tag3', 'Tag4')); $field->setValue(array('Tag3', 'Tag4'));
$field->saveInto($record); $field->saveInto($record);
$record->write(); $record->write();
$this->compareExpectedAndActualTags( $this->compareExpectedAndActualTags(
array('Tag3', 'Tag4'), array('Tag3', 'Tag4'),
$record $record
@ -65,7 +73,6 @@ class TagFieldTest extends SapphireTest
protected function compareTagLists(array $expected, DataList $actualSource) protected function compareTagLists(array $expected, DataList $actualSource)
{ {
$actual = array_values($actualSource->map('ID', 'Title')->toArray()); $actual = array_values($actualSource->map('ID', 'Title')->toArray());
sort($expected); sort($expected);
sort($actual); sort($actual);
@ -247,11 +254,11 @@ class TagFieldTest extends SapphireTest
/** /**
* @param array $parameters * @param array $parameters
* *
* @return SS_HTTPRequest * @return HTTPRequest
*/ */
protected function getNewRequest(array $parameters) protected function getNewRequest(array $parameters)
{ {
return new SS_HTTPRequest( return new HTTPRequest(
'get', 'get',
'TagFieldTestController/TagFieldTestForm/fields/Tags/suggest', 'TagFieldTestController/TagFieldTestForm/fields/Tags/suggest',
$parameters $parameters
@ -283,9 +290,8 @@ class TagFieldTest extends SapphireTest
public function testItIgnoresNewTagsIfCannotCreate() public function testItIgnoresNewTagsIfCannotCreate()
{ {
$this->markTestSkipped( $this->markTestSkipped(
'This test has not been updated yet.' 'This test has not been updated yet.'
); );
$record = new TagFieldTestBlogPost(); $record = new TagFieldTestBlogPost();
@ -320,14 +326,14 @@ class TagFieldTestBlogTag extends DataObject implements TestOnly
* @var array * @var array
*/ */
private static $db = array( private static $db = array(
'Title' => 'Varchar(200)', 'Title' => 'Varchar(200)'
); );
/** /**
* @var array * @var array
*/ */
private static $belongs_many_many = array( private static $belongs_many_many = array(
'BlogPosts' => 'TagFieldTestBlogPost', 'BlogPosts' => 'TagFieldTestBlogPost'
); );
} }
@ -340,15 +346,15 @@ class TagFieldTestBlogPost extends DataObject implements TestOnly
* @var array * @var array
*/ */
private static $db = array( private static $db = array(
'Title' => 'Text', 'Title' => 'Text',
'Content' => 'Text', 'Content' => 'Text'
); );
/** /**
* @var array * @var array
*/ */
private static $many_many = array( private static $many_many = array(
'Tags' => 'TagFieldTestBlogTag', 'Tags' => 'TagFieldTestBlogTag'
); );
} }