silverstripe-framework/forms/SelectField.php

213 lines
5.0 KiB
PHP
Raw Normal View History

<?php
/**
* 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);
}
/**
* 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
*/
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;
}
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;
}
// 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() {
$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;
}
}