tag. * * Setting a $has_one relation * * Using here an example of an art gallery, with Exhibition pages, * each of which has a Gallery they belong to. The Gallery class is also user-defined. * * static $has_one = array( * 'Gallery' => 'Gallery', * ); * * public function getCMSFields() { * $fields = parent::getCMSFields(); * $field = DropdownField::create('GalleryID', 'Gallery', Gallery::get()->map('ID', 'Title')) * ->setEmptyString('(Select one)'); * $fields->addFieldToTab('Root.Content', $field, 'Content'); * * * As you see, you need to put "GalleryID", rather than "Gallery" here. * * Populate with Array * * Example model defintion: * * class MyObject extends DataObject { * static $db = array( * 'Country' => "Varchar(100)" * ); * } * * * Example instantiation: * * DropdownField::create( * 'Country', * 'Country', * array( * 'NZ' => 'New Zealand', * 'US' => 'United States', * 'GEM'=> 'Germany' * ) * ); * * * Populate with Enum-Values * * You can automatically create a map of possible values from an {@link Enum} database column. * * Example model definition: * * class MyObject extends DataObject { * static $db = array( * 'Country' => "Enum('New Zealand,United States,Germany','New Zealand')" * ); * } * * * Field construction: * * DropdownField::create( * 'Country', * 'Country', * singleton('MyObject')->dbObject('Country')->enumValues() * ); * * * Disabling individual items * * Individual items can be disabled by feeding their array keys to setDisabledItems. * * * $DrDownField->setDisabledItems( array( 'US', 'GEM' ) ); * * * @see CheckboxSetField for multiple selections through checkboxes instead. * @see ListboxField for a single element will be * rendered with the first option from {@link $source} selected. */ protected $hasEmptyDefault = false; /** * @var string $emptyString The title shown for an empty default selection, * e.g. "Select...". */ protected $emptyString = ''; /** * @var array $disabledItems The keys for items that should be disabled (greyed out) in the dropdown */ 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 string $value The current value * @param Form $form The parent form * @param string $emptyString Empty string value, e.g. "please choose" */ public function __construct($name, $title=null, $source=array(), $value='', $form=null, $emptyString=null) { $this->setSource($source); 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); parent::__construct($name, ($title===null) ? $name : $title, $value, $form); } /** * @param array $properties * @return HTMLText */ public function Field($properties = array()) { $source = $this->getSource(); $options = array(); 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) { foreach($source as $value => $title) { $selected = false; if($value === '' && ($this->value === '' || $this->value === null)) { $selected = true; } else { // check against value, fallback to a type check comparison when !value if($value) { $selected = ($value == $this->value); } else { // 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); } } $this->isSelected = $selected; } $disabled = false; if(in_array($value, $this->disabledItems) && $title != $this->emptyString ){ $disabled = 'disabled'; } $options[] = new ArrayData(array( 'Title' => $title, 'Value' => $value, 'Selected' => $selected, 'Disabled' => $disabled, )); } } $properties = array_merge($properties, array( 'Options' => new ArrayList($options) )); return parent::Field($properties); } /** * Mark certain elements as disabled, regardless of the * {@link setDisabled()} settings. * * @param array $items Collection of array keys, as defined in the $source array */ public function setDisabledItems($items) { $this->disabledItems = $items; return $this; } /** * @return array */ public function getDisabledItems() { return $this->disabledItems; } /** * @return array */ public function getAttributes() { return array_merge( parent::getAttributes(), array( 'type' => null, 'value' => null ) ); } /** * @return boolean */ public function isSelected() { return $this->isSelected; } /** * Gets the source array including any empty default values. * * @return array|ArrayAccess */ public function getSource() { return $this->source; } /** * @param array|ArrayAccess $source */ public function setSource($source) { $this->source = $source; return $this; } /** * @param boolean $bool */ public function setHasEmptyDefault($bool) { $this->hasEmptyDefault = $bool; return $this; } /** * @return boolean */ public function getHasEmptyDefault() { return $this->hasEmptyDefault; } /** * Set the default selection label, e.g. "select...". * * Defaults to an empty string. Automatically sets {@link $hasEmptyDefault} * to true. * * @param string $str */ public function setEmptyString($str) { $this->setHasEmptyDefault(true); $this->emptyString = $str; return $this; } /** * @return string */ public function getEmptyString() { return $this->emptyString; } /** * @return LookupField */ public function performReadonlyTransformation() { $field = $this->castedCopy('LookupField'); $field->setSource($this->getSource()); $field->setReadonly(true); return $field; } /** * Get the source of this field as an array * * @return array */ public function getSourceAsArray() { $source = $this->getSource(); // Simplify source if presented as dataobject list if ($source instanceof SS_List) { $source = $source->map(); } if ($source instanceof SS_Map) { $source = $source->toArray(); } if (is_array($source)) { return $source; } $sourceArray = array(); foreach ($source as $key => $value) { $sourceArray[$key] = $value; } return $sourceArray; } /** * Validate this field * * @param Validator $validator * @return bool */ public function validate($validator) { $source = $this->getSourceAsArray(); $disabled = $this->getDisabledItems(); if (!array_key_exists($this->value, $source) || in_array($this->value, $disabled)) { 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); if($field->hasMethod('setHasEmptyDefault')) { $field->setHasEmptyDefault($this->getHasEmptyDefault()); } return $field; } }