getListValues($this->Value()); } /** * Default selections, regardless of the {@link setValue()} settings. * Note: Items marked as disabled through {@link setDisabledItems()} can still be * selected by default through this method. * * @param array $items Collection of array keys, as defined in the $source array * @return $this Self reference */ public function setDefaultItems($items) { $this->defaultItems = $this->getListValues($items); return $this; } /** * Default selections, regardless of the {@link setValue()} settings. * * @return array */ public function getDefaultItems() { return $this->defaultItems; } /** * Load a value into this MultiSelectField */ public function setValue($val, $obj = null) { // If we're not passed a value directly, // we can look for it in a relation method on the object passed as a second arg if($obj instanceof DataObject) { $this->loadFrom($obj); } else { return parent::setValue($val); } return $this; } /** * Load the value from the dataobject into this field * * @param DataObjectInterface $record */ public function loadFrom(DataObjectInterface $record) { $fieldName = $this->getName(); if(empty($fieldName) || empty($record)) { return; } $relation = $record->hasMethod($fieldName) ? $record->$fieldName() : null; // Detect DB relation or field if($relation instanceof Relation) { // Load ids from relation $value = array_values($relation->getIDList()); parent::setValue($value); } elseif($record->hasField($fieldName)) { $value = $this->stringDecode($record->$fieldName); parent::setValue($value); } } /** * Save the current value of this MultiSelectField into a DataObject. * If the field it is saving to is a has_many or many_many relationship, * it is saved by setByIDList(), otherwise it creates a comma separated * list for a standard DB text/varchar field. * * @param DataObject $record The record to save into */ public function saveInto(DataObjectInterface $record) { $fieldName = $this->getName(); if(empty($fieldName) || empty($record)) { return; } $relation = $record->hasMethod($fieldName) ? $record->$fieldName() : null; // Detect DB relation or field $items = $this->getValueArray(); if($relation instanceof Relation) { // Save ids into relation $relation->setByIDList($items); } elseif($record->hasField($fieldName)) { // Save dataValue into field $record->$fieldName = $this->stringEncode($items); } } /** * Encode a list of values into a string, or null if empty (to simplify empty checks) * * @param array $value * @return string|null */ public function stringEncode($value) { return $value ? json_encode(array_values($value)) : null; } /** * Extract a string value into an array of values * * @param string $value * @return array */ protected function stringDecode($value) { // Handle empty case if(empty($value)) { return array(); } // If json deserialisation fails, then fallover to legacy format $result = json_decode($value, true); if($result !== false) { return $result; } throw new \InvalidArgumentException("Invalid string encoded value for multi select field"); } /** * Validate this field * * @param Validator $validator * @return bool */ public function validate($validator) { $values = $this->getValueArray(); $validValues = $this->getValidValues(); // Filter out selected values not in the data source $self = $this; $invalidValues = array_filter( $values, function($userValue) use ($self, $validValues) { foreach($validValues as $formValue) { if($self->isSelectedValue($formValue, $userValue)) { return false; } } return true; } ); if(empty($invalidValues)) { return true; } // List invalid items $validator->validationError( $this->getName(), _t( 'MultiSelectField.SOURCE_VALIDATION', "Please select values within the list provided. Invalid option(s) {value} given", array('value' => implode(',', $invalidValues)) ), "validation" ); return false; } /** * Transforms the source data for this CheckboxSetField * into a comma separated list of values. * * @return ReadonlyField */ public function performReadonlyTransformation() { $source = $this->getSource(); // Map selected values to titles $data = array(); foreach($this->getValueArray() as $value) { if(array_key_exists($value, $source)) { $data[] = $source[$value]; } else { $data[] = $value; } } $values = implode(', ', $data); $field = $this->castedCopy('ReadonlyField'); $field->setValue($values); return $field; } }