mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
255 lines
5.9 KiB
PHP
255 lines
5.9 KiB
PHP
<?php
|
|
|
|
use SilverStripe\ORM\SS_List;
|
|
use SilverStripe\ORM\SS_Map;
|
|
|
|
/**
|
|
* Represents a field that allows users to select one or more items from a list
|
|
*/
|
|
abstract class SelectField extends FormField {
|
|
|
|
/**
|
|
* Associative or numeric array of all dropdown items,
|
|
* with array key as the submitted field value, and the array value as a
|
|
* natural language description shown in the interface element.
|
|
*
|
|
* @var array|ArrayAccess
|
|
*/
|
|
protected $source;
|
|
|
|
/**
|
|
* The values for items that should be disabled (greyed out) in the dropdown.
|
|
* This is a non-associative array
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $disabledItems = array();
|
|
|
|
/**
|
|
* @param string $name The field name
|
|
* @param string $title The field title
|
|
* @param array|ArrayAccess $source A map of the dropdown items
|
|
* @param mixed $value The current value
|
|
*/
|
|
public function __construct($name, $title = null, $source = array(), $value = null) {
|
|
$this->setSource($source);
|
|
if(!isset($title)) {
|
|
$title = $name;
|
|
}
|
|
parent::__construct($name, $title, $value);
|
|
}
|
|
|
|
public function getSchemaStateDefaults() {
|
|
$data = parent::getSchemaStateDefaults();
|
|
$disabled = $this->getDisabledItems();
|
|
|
|
// Add options to 'data'
|
|
$source = $this->getSource();
|
|
$data['source'] = (is_array($source))
|
|
? array_map(function ($value, $title) use ($disabled) {
|
|
return [
|
|
'value' => $value,
|
|
'title' => $title,
|
|
'disabled' => in_array($value, $disabled),
|
|
];
|
|
}, array_keys($source), $source)
|
|
: [];
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Mark certain elements as disabled,
|
|
* regardless of the {@link setDisabled()} settings.
|
|
*
|
|
* These should be items that appear in the source list, not in addition to them.
|
|
*
|
|
* @param array|SS_List $items Collection of values or items
|
|
* @return $this
|
|
*/
|
|
public function setDisabledItems($items){
|
|
$this->disabledItems = $this->getListValues($items);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Non-associative list of disabled item values
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getDisabledItems(){
|
|
return $this->disabledItems;
|
|
}
|
|
|
|
/**
|
|
* Check if the given value is disabled
|
|
*
|
|
* @param string $value
|
|
* @return bool
|
|
*/
|
|
protected function isDisabledValue($value) {
|
|
if($this->isDisabled()) {
|
|
return true;
|
|
}
|
|
return in_array($value, $this->getDisabledItems());
|
|
}
|
|
|
|
public function getAttributes() {
|
|
return array_merge(
|
|
parent::getAttributes(),
|
|
array('type' => null, 'value' => null)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retrieve all values in the source array
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function getSourceValues() {
|
|
return array_keys($this->getSource());
|
|
}
|
|
|
|
/**
|
|
* Gets all valid values for this field.
|
|
*
|
|
* Does not include "empty" value if specified
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getValidValues() {
|
|
$valid = array_diff($this->getSourceValues(), $this->getDisabledItems());
|
|
// Renumber indexes from 0
|
|
return array_values($valid);
|
|
}
|
|
|
|
/**
|
|
* Gets the source array not including any empty default values.
|
|
*
|
|
* @return array|ArrayAccess
|
|
*/
|
|
public function getSource() {
|
|
return $this->source;
|
|
}
|
|
|
|
/**
|
|
* Set the source for this list
|
|
*
|
|
* @param mixed $source
|
|
* @return $this
|
|
*/
|
|
public function setSource($source) {
|
|
$this->source = $this->getListMap($source);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Given a list of values, extract the associative map of id => title
|
|
*
|
|
* @param mixed $source
|
|
* @return array Associative array of ids and titles
|
|
*/
|
|
protected function getListMap($source) {
|
|
// Extract source as an array
|
|
if($source instanceof SS_List) {
|
|
$source = $source->map();
|
|
}
|
|
if($source instanceof SS_Map) {
|
|
$source = $source->toArray();
|
|
}
|
|
if(!is_array($source) && !($source instanceof ArrayAccess)) {
|
|
user_error('$source passed in as invalid type', E_USER_ERROR);
|
|
}
|
|
|
|
return $source;
|
|
}
|
|
|
|
/**
|
|
* Given a non-array collection, extract the non-associative list of ids
|
|
* If passing as array, treat the array values (not the keys) as the ids
|
|
*
|
|
* @param mixed $values
|
|
* @return array Non-associative list of values
|
|
*/
|
|
protected function getListValues($values) {
|
|
// Empty values
|
|
if(empty($values)) {
|
|
return array();
|
|
}
|
|
|
|
// Direct array
|
|
if(is_array($values)) {
|
|
return array_values($values);
|
|
}
|
|
|
|
// Extract lists
|
|
if($values instanceof SS_List) {
|
|
return $values->column('ID');
|
|
}
|
|
|
|
return array(trim($values));
|
|
}
|
|
|
|
/**
|
|
* Determine if the current value of this field matches the given option value
|
|
*
|
|
* @param mixed $dataValue The value as extracted from the source of this field (or empty value if available)
|
|
* @param mixed $userValue The value as submitted by the user
|
|
* @return boolean True if the selected value matches the given option value
|
|
*/
|
|
public function isSelectedValue($dataValue, $userValue) {
|
|
if($dataValue === $userValue) {
|
|
return true;
|
|
}
|
|
|
|
// Allow null to match empty strings
|
|
if($dataValue === '' && $userValue === null) {
|
|
return true;
|
|
}
|
|
|
|
// Safety check against casting arrays as strings in PHP>5.4
|
|
if(is_array($dataValue) || is_array($userValue)) {
|
|
return false;
|
|
}
|
|
|
|
// For non-falsey values do loose comparison
|
|
if($dataValue) {
|
|
return $dataValue == $userValue;
|
|
}
|
|
|
|
// For empty values, use string comparison to perform visible value match
|
|
return ((string) $dataValue) === ((string) $userValue);
|
|
}
|
|
|
|
public function performReadonlyTransformation() {
|
|
/** @var LookupField $field */
|
|
$field = $this->castedCopy('LookupField');
|
|
$field->setSource($this->getSource());
|
|
$field->setReadonly(true);
|
|
|
|
return $field;
|
|
}
|
|
|
|
public function performDisabledTransformation() {
|
|
$clone = clone $this;
|
|
$clone->setDisabled(true);
|
|
return $clone;
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
if($field instanceof SelectField) {
|
|
$field->setSource($this->getSource());
|
|
}
|
|
return $field;
|
|
}
|
|
}
|