2015-04-14 03:15:28 +02:00
|
|
|
<?php
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
namespace SilverStripe\TagField;
|
|
|
|
|
2018-09-17 08:18:40 +02:00
|
|
|
use Exception;
|
2017-01-13 20:11:59 +01:00
|
|
|
use SilverStripe\Control\Controller;
|
|
|
|
use SilverStripe\Control\HTTPRequest;
|
|
|
|
use SilverStripe\Control\HTTPResponse;
|
|
|
|
use SilverStripe\Core\Injector\Injector;
|
|
|
|
use SilverStripe\Forms\DropdownField;
|
2018-09-17 08:18:40 +02:00
|
|
|
use SilverStripe\Forms\Validator;
|
2017-01-13 20:11:59 +01:00
|
|
|
use SilverStripe\ORM\ArrayList;
|
|
|
|
use SilverStripe\ORM\DataList;
|
|
|
|
use SilverStripe\ORM\DataObject;
|
|
|
|
use SilverStripe\ORM\DataObjectInterface;
|
2018-09-17 08:18:40 +02:00
|
|
|
use SilverStripe\ORM\Relation;
|
2017-01-13 20:11:59 +01:00
|
|
|
use SilverStripe\ORM\SS_List;
|
|
|
|
use SilverStripe\View\ArrayData;
|
|
|
|
use SilverStripe\View\Requirements;
|
|
|
|
|
2015-04-14 03:15:28 +02:00
|
|
|
/**
|
2015-05-15 12:29:17 +02:00
|
|
|
* Provides a tagging interface, storing links between tag DataObjects and a parent DataObject.
|
2015-04-14 03:15:28 +02:00
|
|
|
*
|
2015-05-15 12:29:17 +02:00
|
|
|
* @package forms
|
|
|
|
* @subpackage fields
|
2015-04-14 03:15:28 +02:00
|
|
|
*/
|
2015-11-18 05:05:38 +01:00
|
|
|
class TagField extends DropdownField
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2017-01-13 20:11:59 +01:00
|
|
|
private static $allowed_actions = array(
|
|
|
|
'suggest'
|
2015-11-18 05:05:38 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $shouldLazyLoad = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
protected $lazyLoadItemLimit = 10;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $canCreate = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $titleField = 'Title';
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
/**
|
|
|
|
* @var DataList
|
|
|
|
*/
|
|
|
|
protected $sourceList;
|
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
protected $isMultiple = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $name
|
|
|
|
* @param string $title
|
|
|
|
* @param null|DataList $source
|
|
|
|
* @param null|DataList $value
|
2018-04-06 04:18:14 +02:00
|
|
|
* @param string $titleField
|
2015-11-18 05:05:38 +01:00
|
|
|
*/
|
2018-09-17 08:18:40 +02:00
|
|
|
public function __construct($name, $title = '', $source = null, $value = null, $titleField = 'Title')
|
2015-11-18 05:05:38 +01:00
|
|
|
{
|
2018-04-06 03:47:49 +02:00
|
|
|
$this->setTitleField($titleField);
|
2018-09-17 08:18:40 +02:00
|
|
|
parent::__construct($name, $title, $source, $value);
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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 bool
|
|
|
|
*/
|
|
|
|
public function getIsMultiple()
|
|
|
|
{
|
|
|
|
return $this->isMultiple;
|
|
|
|
}
|
2015-04-23 21:19:10 +02:00
|
|
|
|
2015-10-09 00:10:33 +02:00
|
|
|
/**
|
2015-11-18 05:05:38 +01:00
|
|
|
* @param bool $isMultiple
|
|
|
|
*
|
|
|
|
* @return static
|
|
|
|
*/
|
|
|
|
public function setIsMultiple($isMultiple)
|
|
|
|
{
|
|
|
|
$this->isMultiple = $isMultiple;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function getCanCreate()
|
|
|
|
{
|
|
|
|
return $this->canCreate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $canCreate
|
|
|
|
*
|
|
|
|
* @return static
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
/**
|
2018-09-17 08:18:40 +02:00
|
|
|
* Get the DataList source. The 4.x upgrade for SelectField::setSource starts to convert this to an array.
|
|
|
|
* If empty use getSource() for array version
|
|
|
|
*
|
2017-01-13 20:11:59 +01:00
|
|
|
* @return DataList
|
|
|
|
*/
|
|
|
|
public function getSourceList()
|
|
|
|
{
|
|
|
|
return $this->sourceList;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the model class name for tags
|
2018-09-17 08:18:40 +02:00
|
|
|
*
|
|
|
|
* @param DataList $sourceList
|
2017-01-13 20:11:59 +01:00
|
|
|
* @return self
|
|
|
|
*/
|
|
|
|
public function setSourceList($sourceList)
|
|
|
|
{
|
|
|
|
$this->sourceList = $sourceList;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function Field($properties = array())
|
|
|
|
{
|
2017-10-18 02:28:49 +02:00
|
|
|
Requirements::css('silverstripe/tagfield:css/select2.min.css');
|
|
|
|
Requirements::css('silverstripe/tagfield:css/TagField.css');
|
2015-11-18 05:05:38 +01:00
|
|
|
|
2017-10-18 02:28:49 +02:00
|
|
|
Requirements::javascript('silverstripe/tagfield:js/select2.js');
|
|
|
|
Requirements::javascript('silverstripe/tagfield:js/TagField.js');
|
2015-11-18 05:05:38 +01:00
|
|
|
|
|
|
|
$this->addExtraClass('ss-tag-field');
|
2015-04-14 03:15:28 +02:00
|
|
|
|
2015-10-09 00:10:33 +02:00
|
|
|
if ($this->getIsMultiple()) {
|
2015-11-18 05:05:38 +01:00
|
|
|
$this->setAttribute('multiple', 'multiple');
|
2015-10-09 00:10:33 +02:00
|
|
|
}
|
2015-04-14 03:15:28 +02:00
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
if ($this->shouldLazyLoad) {
|
|
|
|
$this->setAttribute('data-ss-tag-field-suggest-url', $this->getSuggestURL());
|
|
|
|
} else {
|
|
|
|
$properties = array_merge($properties, array(
|
|
|
|
'Options' => $this->getOptions()
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2016-07-21 22:52:17 +02:00
|
|
|
$this->setAttribute('data-can-create', (int) $this->getCanCreate());
|
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
return $this
|
|
|
|
->customise($properties)
|
2017-01-13 20:11:59 +01:00
|
|
|
->renderWith(self::class);
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected function getSuggestURL()
|
|
|
|
{
|
|
|
|
return Controller::join_links($this->Link(), 'suggest');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return ArrayList
|
|
|
|
*/
|
|
|
|
protected function getOptions()
|
|
|
|
{
|
|
|
|
$options = ArrayList::create();
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
$source = $this->getSourceList();
|
2015-11-18 05:05:38 +01:00
|
|
|
|
2017-10-18 02:28:49 +02:00
|
|
|
if (!$source) {
|
2017-01-13 20:11:59 +01:00
|
|
|
$source = ArrayList::create();
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
2015-08-17 17:53:38 +02:00
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
$dataClass = $source->dataClass();
|
|
|
|
|
|
|
|
$values = $this->Value();
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
if (!$values) {
|
2016-02-04 00:08:34 +01:00
|
|
|
return $options;
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
if (is_array($values)) {
|
2018-04-06 04:18:14 +02:00
|
|
|
$values = DataList::create($dataClass)->filter($this->getTitleField(), $values);
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
|
2018-04-06 04:18:14 +02:00
|
|
|
$ids = $values->column($this->getTitleField());
|
2016-02-04 00:08:34 +01:00
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
$titleField = $this->getTitleField();
|
2018-09-07 07:28:05 +02:00
|
|
|
|
|
|
|
if ($this->shouldLazyLoad) {
|
|
|
|
// only render options that are selected as everything else should be lazy loaded, and or loaded by the form
|
|
|
|
foreach ($values as $value) {
|
|
|
|
$options->push(
|
|
|
|
ArrayData::create(array(
|
|
|
|
'Title' => $value->$titleField,
|
|
|
|
'Value' => $value->Title,
|
|
|
|
'Selected' => true, // only values are iterated.
|
|
|
|
))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return $options;
|
|
|
|
}
|
2015-11-18 05:05:38 +01:00
|
|
|
|
2017-10-18 02:28:49 +02:00
|
|
|
foreach ($source as $object) {
|
2015-11-18 05:05:38 +01:00
|
|
|
$options->push(
|
2017-10-18 02:28:49 +02:00
|
|
|
ArrayData::create(array(
|
2016-02-04 00:08:34 +01:00
|
|
|
'Title' => $object->$titleField,
|
|
|
|
'Value' => $object->Title,
|
|
|
|
'Selected' => in_array($object->Title, $ids),
|
2015-11-18 05:05:38 +01:00
|
|
|
))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $options;
|
2017-10-18 02:28:49 +02:00
|
|
|
}
|
2015-11-18 05:05:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function setValue($value, $source = null)
|
|
|
|
{
|
|
|
|
if ($source instanceof DataObject) {
|
|
|
|
$name = $this->getName();
|
|
|
|
|
|
|
|
if ($source->hasMethod($name)) {
|
2018-04-06 04:18:14 +02:00
|
|
|
$value = $source->$name()->column($this->getTitleField());
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
} elseif ($value instanceof SS_List) {
|
2018-04-06 04:18:14 +02:00
|
|
|
$value = $value->column($this->getTitleField());
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_array($value)) {
|
|
|
|
return parent::setValue($value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return parent::setValue(array_filter($value));
|
|
|
|
}
|
|
|
|
|
2018-09-13 01:18:55 +02:00
|
|
|
/**
|
|
|
|
* Gets the source array if required
|
|
|
|
*
|
|
|
|
* Note: this is expensive for a SS_List
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getSource()
|
|
|
|
{
|
|
|
|
if (is_null($this->source)) {
|
2018-09-17 08:18:40 +02:00
|
|
|
$this->source = $this->getListMap($this->getSourceList());
|
2018-09-13 01:18:55 +02:00
|
|
|
}
|
|
|
|
return $this->source;
|
|
|
|
}
|
|
|
|
|
2018-09-17 08:18:40 +02:00
|
|
|
/**
|
|
|
|
* Intercept DataList source
|
|
|
|
*
|
|
|
|
* @param mixed $source
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function setSource($source)
|
|
|
|
{
|
|
|
|
// When setting a datalist force internal list to null
|
|
|
|
if ($source instanceof DataList) {
|
|
|
|
$this->source = null;
|
|
|
|
$this->setSourceList($source);
|
|
|
|
} else {
|
|
|
|
parent::setSource($source);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
|
|
|
public function getAttributes()
|
|
|
|
{
|
|
|
|
return array_merge(
|
|
|
|
parent::getAttributes(),
|
2018-02-20 14:39:58 +01:00
|
|
|
[
|
|
|
|
'name' => $this->getName() . '[]',
|
|
|
|
'style'=> 'width: 100%'
|
|
|
|
]
|
2015-11-18 05:05:38 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-09-17 08:18:40 +02:00
|
|
|
* @param DataObject|DataObjectInterface $record DataObject to save data into
|
|
|
|
* @throws Exception
|
2015-11-18 05:05:38 +01:00
|
|
|
*/
|
|
|
|
public function saveInto(DataObjectInterface $record)
|
|
|
|
{
|
|
|
|
parent::saveInto($record);
|
|
|
|
|
|
|
|
$name = $this->getName();
|
|
|
|
$titleField = $this->getTitleField();
|
|
|
|
$values = $this->Value();
|
2018-09-17 08:18:40 +02:00
|
|
|
|
|
|
|
/** @var Relation $relation */
|
2016-02-04 00:08:34 +01:00
|
|
|
$relation = $record->$name();
|
|
|
|
$ids = array();
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
if (!$values) {
|
2015-11-18 05:05:38 +01:00
|
|
|
$values = array();
|
|
|
|
}
|
2017-01-26 06:10:14 +01:00
|
|
|
if (empty($record) || empty($titleField)) {
|
2015-11-18 05:05:38 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
if (!$record->hasMethod($name)) {
|
2015-11-18 05:05:38 +01:00
|
|
|
throw new Exception(
|
|
|
|
sprintf("%s does not have a %s method", get_class($record), $name)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-04 00:08:34 +01:00
|
|
|
foreach ($values as $key => $value) {
|
2016-01-27 03:49:36 +01:00
|
|
|
// Get or create record
|
|
|
|
$record = $this->getOrCreateTag($value);
|
2017-01-13 20:11:59 +01:00
|
|
|
if ($record) {
|
2016-02-04 00:08:34 +01:00
|
|
|
$ids[] = $record->ID;
|
|
|
|
$values[$key] = $record->Title;
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-04 00:08:34 +01:00
|
|
|
$relation->setByIDList(array_filter($ids));
|
2017-10-18 02:28:49 +02:00
|
|
|
}
|
2015-11-18 05:05:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get or create tag with the given value
|
|
|
|
*
|
2017-01-13 20:11:59 +01:00
|
|
|
* @param string $term
|
2018-09-17 08:18:40 +02:00
|
|
|
* @return DataObject|false
|
2015-11-18 05:05:38 +01:00
|
|
|
*/
|
|
|
|
protected function getOrCreateTag($term)
|
|
|
|
{
|
|
|
|
// Check if existing record can be found
|
2017-01-13 20:11:59 +01:00
|
|
|
$source = $this->getSourceList();
|
2018-09-17 08:18:40 +02:00
|
|
|
if (!$source) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-18 05:05:38 +01:00
|
|
|
$titleField = $this->getTitleField();
|
|
|
|
$record = $source
|
|
|
|
->filter($titleField, $term)
|
|
|
|
->first();
|
2017-01-13 20:11:59 +01:00
|
|
|
if ($record) {
|
2015-11-18 05:05:38 +01:00
|
|
|
return $record;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create new instance if not yet saved
|
2016-02-04 04:07:15 +01:00
|
|
|
if ($this->getCanCreate()) {
|
|
|
|
$dataClass = $source->dataClass();
|
|
|
|
$record = Injector::inst()->create($dataClass);
|
|
|
|
$record->{$titleField} = $term;
|
|
|
|
$record->write();
|
|
|
|
return $record;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2015-11-18 05:05:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a JSON string of tags, for lazy loading.
|
|
|
|
*
|
2017-01-13 20:11:59 +01:00
|
|
|
* @param HTTPRequest $request
|
|
|
|
* @return HTTPResponse
|
2015-11-18 05:05:38 +01:00
|
|
|
*/
|
2017-01-13 20:11:59 +01:00
|
|
|
public function suggest(HTTPRequest $request)
|
2015-11-18 05:05:38 +01:00
|
|
|
{
|
|
|
|
$tags = $this->getTags($request->getVar('term'));
|
|
|
|
|
2017-01-13 20:11:59 +01:00
|
|
|
$response = new HTTPResponse();
|
2015-11-18 05:05:38 +01:00
|
|
|
$response->addHeader('Content-Type', 'application/json');
|
|
|
|
$response->setBody(json_encode(array('items' => $tags)));
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns array of arrays representing tags.
|
|
|
|
*
|
2017-01-13 20:11:59 +01:00
|
|
|
* @param string $term
|
2015-11-18 05:05:38 +01:00
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function getTags($term)
|
|
|
|
{
|
2017-01-13 20:11:59 +01:00
|
|
|
$source = $this->getSourceList();
|
2018-09-17 08:18:40 +02:00
|
|
|
if (!$source) {
|
|
|
|
return [];
|
|
|
|
}
|
2015-11-18 05:05:38 +01:00
|
|
|
|
|
|
|
$titleField = $this->getTitleField();
|
|
|
|
|
|
|
|
$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) {
|
|
|
|
$items[$title] = array(
|
2016-02-04 00:08:34 +01:00
|
|
|
'id' => $title,
|
2015-11-18 05:05:38 +01:00
|
|
|
'text' => $title
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return array_values($items);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* DropdownField assumes value will be a scalar so we must
|
|
|
|
* override validate. This only applies to Silverstripe 3.2+
|
|
|
|
*
|
|
|
|
* @param Validator $validator
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function validate($validator)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2016-07-21 22:52:17 +02:00
|
|
|
|
2016-02-25 02:32:29 +01:00
|
|
|
/**
|
|
|
|
* Converts the field to a readonly variant.
|
|
|
|
*
|
2018-09-17 08:18:40 +02:00
|
|
|
* @return ReadonlyTagField
|
2016-02-25 02:32:29 +01:00
|
|
|
*/
|
|
|
|
public function performReadonlyTransformation()
|
|
|
|
{
|
2018-09-17 08:18:40 +02:00
|
|
|
/** @var ReadonlyTagField $copy */
|
2018-01-19 08:37:55 +01:00
|
|
|
$copy = $this->castedCopy(ReadonlyTagField::class);
|
2017-01-13 20:11:59 +01:00
|
|
|
$copy->setSourceList($this->getSourceList());
|
2016-02-25 02:32:29 +01:00
|
|
|
return $copy;
|
|
|
|
}
|
2015-04-14 03:15:28 +02:00
|
|
|
}
|