2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Dropdown field, created from a <select> tag.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* <b>Setting a $has_one relation</b>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
|
|
|
* Using here an example of an art gallery, with Exhibition pages,
|
2010-10-15 05:55:22 +02:00
|
|
|
* each of which has a Gallery they belong to. The Gallery class is also user-defined.
|
|
|
|
* <code>
|
|
|
|
* static $has_one = array(
|
|
|
|
* 'Gallery' => 'Gallery',
|
|
|
|
* );
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* public function getCMSFields() {
|
|
|
|
* $fields = parent::getCMSFields();
|
2014-11-22 22:01:08 +01:00
|
|
|
* $field = DropdownField::create('GalleryID', 'Gallery', Gallery::get()->map('ID', 'Title'))
|
|
|
|
* ->setEmptyString('(Select one)');
|
2012-03-20 03:47:22 +01:00
|
|
|
* $fields->addFieldToTab('Root.Content', $field, 'Content');
|
2010-10-15 05:55:22 +02:00
|
|
|
* </code>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* As you see, you need to put "GalleryID", rather than "Gallery" here.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* <b>Populate with Array</b>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* Example model defintion:
|
|
|
|
* <code>
|
|
|
|
* class MyObject extends DataObject {
|
|
|
|
* static $db = array(
|
|
|
|
* 'Country' => "Varchar(100)"
|
|
|
|
* );
|
2012-05-23 12:45:04 +02:00
|
|
|
* }
|
2010-10-15 05:55:22 +02:00
|
|
|
* </code>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-05-23 12:45:04 +02:00
|
|
|
* Example instantiation:
|
2010-10-15 05:55:22 +02:00
|
|
|
* <code>
|
2014-11-22 22:01:08 +01:00
|
|
|
* DropdownField::create(
|
2010-10-15 05:55:22 +02:00
|
|
|
* 'Country',
|
|
|
|
* 'Country',
|
|
|
|
* array(
|
|
|
|
* 'NZ' => 'New Zealand',
|
2014-05-28 12:36:51 +02:00
|
|
|
* 'US' => 'United States',
|
2010-10-15 05:55:22 +02:00
|
|
|
* 'GEM'=> 'Germany'
|
|
|
|
* )
|
|
|
|
* );
|
|
|
|
* </code>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* <b>Populate with Enum-Values</b>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* You can automatically create a map of possible values from an {@link Enum} database column.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* Example model definition:
|
|
|
|
* <code>
|
|
|
|
* class MyObject extends DataObject {
|
|
|
|
* static $db = array(
|
|
|
|
* 'Country' => "Enum('New Zealand,United States,Germany','New Zealand')"
|
|
|
|
* );
|
2012-05-23 12:45:04 +02:00
|
|
|
* }
|
2010-10-15 05:55:22 +02:00
|
|
|
* </code>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-15 05:55:22 +02:00
|
|
|
* Field construction:
|
|
|
|
* <code>
|
2014-11-22 22:01:08 +01:00
|
|
|
* DropdownField::create(
|
2010-10-15 05:55:22 +02:00
|
|
|
* 'Country',
|
|
|
|
* 'Country',
|
|
|
|
* singleton('MyObject')->dbObject('Country')->enumValues()
|
|
|
|
* );
|
|
|
|
* </code>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-10-17 11:06:02 +02:00
|
|
|
* <b>Disabling individual items</b>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-10-17 11:06:02 +02:00
|
|
|
* Individual items can be disabled by feeding their array keys to setDisabledItems.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-10-17 11:06:02 +02:00
|
|
|
* <code>
|
|
|
|
* $DrDownField->setDisabledItems( array( 'US', 'GEM' ) );
|
|
|
|
* </code>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2010-10-19 00:50:48 +02:00
|
|
|
* @see CheckboxSetField for multiple selections through checkboxes instead.
|
|
|
|
* @see ListboxField for a single <select> box (with single or multiple selections).
|
|
|
|
* @see TreeDropdownField for a rich and customizeable UI that can visualize a tree of selectable elements
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2008-01-09 05:18:36 +01:00
|
|
|
* @package forms
|
|
|
|
* @subpackage fields-basic
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
class DropdownField extends FormField {
|
2011-12-21 17:35:42 +01:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
2014-11-12 03:19:12 +01:00
|
|
|
* @var array|ArrayAccess $source Associative or numeric array of all dropdown items,
|
2008-10-15 14:39:09 +02:00
|
|
|
* with array key as the submitted field value, and the array value as a
|
|
|
|
* natural language description shown in the interface element.
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
protected $source;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @var boolean $isSelected Determines if the field was selected
|
|
|
|
* at the time it was rendered, so if {@link $value} matches on of the array
|
|
|
|
* values specified in {@link $source}
|
|
|
|
*/
|
|
|
|
protected $isSelected;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @var boolean $hasEmptyDefault Show the first <option> element as
|
|
|
|
* empty (not having a value), with an optional label defined through
|
|
|
|
* {@link $emptyString}. By default, the <select> element will be
|
|
|
|
* rendered with the first option from {@link $source} selected.
|
|
|
|
*/
|
|
|
|
protected $hasEmptyDefault = false;
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @var string $emptyString The title shown for an empty default selection,
|
|
|
|
* e.g. "Select...".
|
|
|
|
*/
|
|
|
|
protected $emptyString = '';
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-17 11:06:02 +02:00
|
|
|
/**
|
|
|
|
* @var array $disabledItems The keys for items that should be disabled (greyed out) in the dropdown
|
|
|
|
*/
|
|
|
|
protected $disabledItems = array();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
2014-02-20 14:06:48 +01:00
|
|
|
* @param string $name The field name
|
|
|
|
* @param string $title The field title
|
2014-11-12 03:19:12 +01:00
|
|
|
* @param array|ArrayAccess $source A map of the dropdown items
|
2014-02-20 14:06:48 +01:00
|
|
|
* @param string $value The current value
|
|
|
|
* @param Form $form The parent form
|
2018-04-11 10:12:38 +02:00
|
|
|
* @param string $emptyString Empty string value, e.g. "please choose"
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2015-08-21 04:01:10 +02:00
|
|
|
public function __construct($name, $title=null, $source=array(), $value='', $form=null, $emptyString=null) {
|
2011-08-29 14:31:03 +02:00
|
|
|
$this->setSource($source);
|
2015-08-21 04:01:10 +02:00
|
|
|
|
|
|
|
if($emptyString === true) {
|
|
|
|
Deprecation::notice('4.0',
|
|
|
|
'Please use setHasEmptyDefault(true) instead of passing a boolean true $emptyString argument',
|
|
|
|
Deprecation::SCOPE_GLOBAL);
|
|
|
|
}
|
|
|
|
if(is_string($emptyString)) {
|
|
|
|
Deprecation::notice('4.0', 'Please use setEmptyString() instead of passing a string emptyString argument.',
|
|
|
|
Deprecation::SCOPE_GLOBAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($emptyString) $this->setHasEmptyDefault(true);
|
|
|
|
if(is_string($emptyString)) $this->setEmptyString($emptyString);
|
|
|
|
|
2008-08-06 05:43:48 +02:00
|
|
|
parent::__construct($name, ($title===null) ? $name : $title, $value, $form);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2015-06-20 12:11:08 +02:00
|
|
|
/**
|
|
|
|
* @param array $properties
|
|
|
|
* @return HTMLText
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function Field($properties = array()) {
|
2008-10-15 14:39:09 +02:00
|
|
|
$source = $this->getSource();
|
2011-03-23 05:12:25 +01:00
|
|
|
$options = array();
|
|
|
|
|
2013-10-18 00:16:27 +02:00
|
|
|
if ($this->getHasEmptyDefault()) {
|
|
|
|
$selected = ($this->value === '' || $this->value === null);
|
|
|
|
$disabled = (in_array('', $this->disabledItems, true)) ? 'disabled' : false;
|
|
|
|
|
|
|
|
$options[] = new ArrayData(array(
|
|
|
|
'Value' => '',
|
|
|
|
'Title' => $this->getEmptyString(),
|
|
|
|
'Selected' => $selected,
|
|
|
|
'Disabled' => $disabled
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($source) {
|
2008-10-16 01:25:55 +02:00
|
|
|
foreach($source as $value => $title) {
|
2011-03-23 05:12:25 +01:00
|
|
|
$selected = false;
|
2009-04-29 03:20:24 +02:00
|
|
|
if($value === '' && ($this->value === '' || $this->value === null)) {
|
2011-03-23 05:12:25 +01:00
|
|
|
$selected = true;
|
2009-04-29 03:20:24 +02:00
|
|
|
} else {
|
2011-03-23 05:12:25 +01:00
|
|
|
// check against value, fallback to a type check comparison when !value
|
2014-01-11 01:25:25 +01:00
|
|
|
if($value) {
|
|
|
|
$selected = ($value == $this->value);
|
|
|
|
} else {
|
2016-05-10 00:27:36 +02:00
|
|
|
// Safety check against casting arrays as strings in PHP>5.4
|
|
|
|
if(!is_array($value) && !is_array($this->value)) {
|
|
|
|
$selected = ($value === $this->value) || (((string) $value) === ((string) $this->value));
|
|
|
|
} else {
|
|
|
|
$selected = ($value === $this->value);
|
|
|
|
}
|
2014-01-11 01:25:25 +01:00
|
|
|
}
|
|
|
|
|
2011-03-23 05:12:25 +01:00
|
|
|
$this->isSelected = $selected;
|
2008-10-16 01:25:55 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-17 11:06:02 +02:00
|
|
|
$disabled = false;
|
|
|
|
if(in_array($value, $this->disabledItems) && $title != $this->emptyString ){
|
|
|
|
$disabled = 'disabled';
|
|
|
|
}
|
2011-03-23 05:12:25 +01:00
|
|
|
|
|
|
|
$options[] = new ArrayData(array(
|
|
|
|
'Title' => $title,
|
|
|
|
'Value' => $value,
|
|
|
|
'Selected' => $selected,
|
2012-10-17 11:06:02 +02:00
|
|
|
'Disabled' => $disabled,
|
2011-03-23 05:12:25 +01:00
|
|
|
));
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
2008-10-15 23:44:38 +02:00
|
|
|
|
2013-10-18 00:16:27 +02:00
|
|
|
$properties = array_merge($properties, array(
|
|
|
|
'Options' => new ArrayList($options)
|
|
|
|
));
|
2011-03-23 05:12:25 +01:00
|
|
|
|
2012-04-14 07:32:29 +02:00
|
|
|
return parent::Field($properties);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-17 11:06:02 +02:00
|
|
|
/**
|
2014-08-15 08:53:05 +02:00
|
|
|
* Mark certain elements as disabled, regardless of the
|
2013-10-18 00:16:27 +02:00
|
|
|
* {@link setDisabled()} settings.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2012-10-17 11:06:02 +02:00
|
|
|
* @param array $items Collection of array keys, as defined in the $source array
|
|
|
|
*/
|
2013-10-18 00:16:27 +02:00
|
|
|
public function setDisabledItems($items) {
|
2012-10-17 11:06:02 +02:00
|
|
|
$this->disabledItems = $items;
|
2013-10-18 00:16:27 +02:00
|
|
|
|
2012-10-17 11:06:02 +02:00
|
|
|
return $this;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-10-17 11:06:02 +02:00
|
|
|
/**
|
2013-10-18 00:16:27 +02:00
|
|
|
* @return array
|
2012-10-17 11:06:02 +02:00
|
|
|
*/
|
2013-10-18 00:16:27 +02:00
|
|
|
public function getDisabledItems() {
|
2012-10-17 11:06:02 +02:00
|
|
|
return $this->disabledItems;
|
|
|
|
}
|
2011-03-23 05:12:25 +01:00
|
|
|
|
2013-10-18 00:16:27 +02:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getAttributes() {
|
2011-12-22 13:10:57 +01:00
|
|
|
return array_merge(
|
|
|
|
parent::getAttributes(),
|
2013-10-18 00:16:27 +02:00
|
|
|
array(
|
2014-08-15 08:53:05 +02:00
|
|
|
'type' => null,
|
2013-10-18 00:16:27 +02:00
|
|
|
'value' => null
|
|
|
|
)
|
2011-12-22 13:10:57 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function isSelected() {
|
2007-07-19 12:40:28 +02:00
|
|
|
return $this->isSelected;
|
|
|
|
}
|
2012-05-23 12:45:04 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* Gets the source array including any empty default values.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2014-11-12 03:19:12 +01:00
|
|
|
* @return array|ArrayAccess
|
2008-10-15 14:39:09 +02:00
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getSource() {
|
2013-10-18 00:16:27 +02:00
|
|
|
return $this->source;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2012-05-23 12:45:04 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
2014-11-12 03:19:12 +01:00
|
|
|
* @param array|ArrayAccess $source
|
2008-10-15 14:39:09 +02:00
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function setSource($source) {
|
2007-07-19 12:40:28 +02:00
|
|
|
$this->source = $source;
|
2013-10-18 00:16:27 +02:00
|
|
|
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @param boolean $bool
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function setHasEmptyDefault($bool) {
|
2008-10-15 14:39:09 +02:00
|
|
|
$this->hasEmptyDefault = $bool;
|
2013-10-18 00:16:27 +02:00
|
|
|
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2008-10-15 14:39:09 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getHasEmptyDefault() {
|
2008-10-15 14:39:09 +02:00
|
|
|
return $this->hasEmptyDefault;
|
|
|
|
}
|
2011-03-23 05:12:25 +01:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* Set the default selection label, e.g. "select...".
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
|
|
|
* Defaults to an empty string. Automatically sets {@link $hasEmptyDefault}
|
2013-10-18 00:16:27 +02:00
|
|
|
* to true.
|
2012-05-23 12:45:04 +02:00
|
|
|
*
|
2008-10-15 14:39:09 +02:00
|
|
|
* @param string $str
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function setEmptyString($str) {
|
2008-10-15 14:39:09 +02:00
|
|
|
$this->setHasEmptyDefault(true);
|
|
|
|
$this->emptyString = $str;
|
2013-10-18 00:16:27 +02:00
|
|
|
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2008-10-15 14:39:09 +02:00
|
|
|
}
|
2011-03-23 05:12:25 +01:00
|
|
|
|
2008-10-15 14:39:09 +02:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getEmptyString() {
|
2008-10-15 14:39:09 +02:00
|
|
|
return $this->emptyString;
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
|
2013-10-18 00:16:27 +02:00
|
|
|
/**
|
|
|
|
* @return LookupField
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function performReadonlyTransformation() {
|
2012-12-13 13:51:28 +01:00
|
|
|
$field = $this->castedCopy('LookupField');
|
|
|
|
$field->setSource($this->getSource());
|
2008-08-12 04:58:48 +02:00
|
|
|
$field->setReadonly(true);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
return $field;
|
|
|
|
}
|
2014-11-12 03:19:12 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the source of this field as an array
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getSourceAsArray()
|
|
|
|
{
|
|
|
|
$source = $this->getSource();
|
2016-10-11 03:56:32 +02:00
|
|
|
|
|
|
|
// Simplify source if presented as dataobject list
|
|
|
|
if ($source instanceof SS_List) {
|
|
|
|
$source = $source->map();
|
|
|
|
}
|
|
|
|
if ($source instanceof SS_Map) {
|
|
|
|
$source = $source->toArray();
|
|
|
|
}
|
|
|
|
|
2014-11-12 03:19:12 +01:00
|
|
|
if (is_array($source)) {
|
|
|
|
return $source;
|
2016-10-11 03:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$sourceArray = array();
|
|
|
|
foreach ($source as $key => $value) {
|
|
|
|
$sourceArray[$key] = $value;
|
2014-11-12 03:19:12 +01:00
|
|
|
}
|
|
|
|
return $sourceArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validate this field
|
|
|
|
*
|
|
|
|
* @param Validator $validator
|
|
|
|
* @return bool
|
|
|
|
*/
|
2015-05-11 02:32:00 +02:00
|
|
|
public function validate($validator) {
|
2014-11-12 03:19:12 +01:00
|
|
|
$source = $this->getSourceAsArray();
|
2015-05-22 22:11:01 +02:00
|
|
|
$disabled = $this->getDisabledItems();
|
|
|
|
|
|
|
|
if (!array_key_exists($this->value, $source) || in_array($this->value, $disabled)) {
|
2014-11-12 03:19:12 +01:00
|
|
|
if ($this->getHasEmptyDefault() && !$this->value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
$validator->validationError(
|
|
|
|
$this->name,
|
|
|
|
_t(
|
|
|
|
'DropdownField.SOURCE_VALIDATION',
|
|
|
|
"Please select a value within the list provided. {value} is not a valid option",
|
|
|
|
array('value' => $this->value)
|
|
|
|
),
|
|
|
|
"validation"
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns another instance of this field, but "cast" to a different class.
|
|
|
|
*
|
|
|
|
* @see FormField::castedCopy()
|
|
|
|
*
|
|
|
|
* @param String $classOrCopy
|
|
|
|
* @return FormField
|
|
|
|
*/
|
|
|
|
public function castedCopy($classOrCopy) {
|
|
|
|
$field = parent::castedCopy($classOrCopy);
|
2015-10-20 01:39:04 +02:00
|
|
|
if($field->hasMethod('setHasEmptyDefault')) {
|
|
|
|
$field->setHasEmptyDefault($this->getHasEmptyDefault());
|
|
|
|
}
|
2014-11-12 03:19:12 +01:00
|
|
|
return $field;
|
|
|
|
}
|
2012-03-19 05:06:51 +01:00
|
|
|
}
|