diff --git a/src/Former/Form/Fields/Select.php b/src/Former/Form/Fields/Select.php index f4d354d5..8f8a7802 100644 --- a/src/Former/Form/Fields/Select.php +++ b/src/Former/Form/Fields/Select.php @@ -95,6 +95,8 @@ public function render() $this->value = (array) $this->value; } + $this->clearSelected(); + // Mark selected values as selected if ($this->hasChildren() and !empty($this->value)) { foreach ($this->value as $value) { @@ -131,9 +133,9 @@ protected function selectValue($value, $parent = null) } foreach ($parent->getChildren() as $child) { - // Search by value + $optionValue = $child->getAttribute('value'); - if ($child->getAttribute('value') === $value || is_numeric($value) && $child->getAttribute('value') === (int)$value ) { + if ($optionValue === $value || (is_numeric($value) && is_numeric($optionValue) && (int)$optionValue === (int)$value)) { $child->selected('selected'); } @@ -239,7 +241,11 @@ public function addOption($text = null, $value = null, $attributes = array()) if (is_array($text)) { $this->children[$childrenKey] = Element::create('optgroup')->label($value); foreach ($text as $key => $value) { - $option = Element::create('option', $value)->setAttribute('value', $key); + if (is_array($value)) { + $option = Element::create('option', $key)->setAttributes($value); + } else { + $option = Element::create('option', $value)->setAttribute('value', $key); + } $this->children[$childrenKey]->nest($option); } // Else if it's a simple option @@ -254,6 +260,29 @@ public function addOption($text = null, $value = null, $attributes = array()) return $this; } + /** + * Clear selected attribute for select options + * + * @param Element $parent + * + * @return void + */ + public function clearSelected($parent = null) + { + // If no parent element defined, use direct children + if (!$parent) { + $parent = $this; + } + + foreach ($parent->getChildren() as $child) { + $child->removeAttribute('selected'); + + if ($child->hasChildren()) { + $this->clearSelected($child); + } + } + } + /** * Use the results from a Fluent/Eloquent query as options * diff --git a/src/Former/Helpers.php b/src/Former/Helpers.php index 83ecd8fc..851d4978 100644 --- a/src/Former/Helpers.php +++ b/src/Former/Helpers.php @@ -29,7 +29,7 @@ public static function setApp(Container $app) /** * Encodes HTML * - * @param string|null $value The string to encode + * @param string|array|null $value The string to encode * * @return string */ @@ -39,6 +39,10 @@ public static function encode($value) return ''; } + if (is_array($value)) { + $value = ''; + } + return htmlentities($value, ENT_QUOTES, 'UTF-8', true); } diff --git a/src/Former/Traits/Checkable.php b/src/Former/Traits/Checkable.php index e989d249..ec35af84 100644 --- a/src/Former/Traits/Checkable.php +++ b/src/Former/Traits/Checkable.php @@ -257,6 +257,24 @@ public function check($checked = true) return $this; } + /** + * Creates a series of checkable items from query with attributes + * + * @param mixed $query + * @param mixed $text + * @param mixed $attributes + * @return $this + */ + public function fromQuery($query, $text = null, $attributes = null) + { + if ($this->isGrouped()) { + // Remove any possible items added by the Populator. + $this->items = array(); + } + $this->items($query, $text, $attributes); + + return $this; + } /** * Check if the checkables are inline @@ -275,9 +293,11 @@ public function isInline() /** * Creates a series of checkable items * - * @param array $_items Items to create + * @param array|Collection $_items Items to create + * @param string|function $text The value to use as text + * @param string|array $attributes The data to use as attributes */ - protected function items($_items) + protected function items($_items, $text = null, $attributes = null) { // If passing an array if (sizeof($_items) == 1 and @@ -288,9 +308,11 @@ protected function items($_items) } // Fetch models if that's what we were passed - if (isset($_items[0]) and is_object($_items[0])) { - $_items = Helpers::queryToArray($_items); - $_items = array_flip($_items); + if ((isset($_items[0]) and is_object($_items[0])) or ($_items instanceof Collection)) { + $_items = Helpers::queryToArray($_items, $text, $attributes); + if (is_null($text) && is_null($attributes)) { + $_items = array_flip($_items); + } } // Iterate through items, assign a name and a label to each @@ -542,7 +564,7 @@ protected function isChecked($item = null, $value = null) if (!is_null($post) and $post !== $this->app['former']->getOption('unchecked_value')) { $isChecked = ($post == $value); - } elseif (!is_null($static)) { + } elseif (!is_null($static) && !(is_array($static) && empty($static))) { $isChecked = ($static == $value); } else { $isChecked = $checked; diff --git a/tests/Fields/SelectTest.php b/tests/Fields/SelectTest.php index c17ee9e9..4040248f 100644 --- a/tests/Fields/SelectTest.php +++ b/tests/Fields/SelectTest.php @@ -542,4 +542,57 @@ public function testSelectCanPickRightOptionWithOptgroups() $this->assertStringContainsString($matcher, $select->render()); } + + public function testCanClearPreviouslySelectedOptions() + { + $select = $this->former->select('foo')->options([ + 'One' => ['value' => 1, 'selected' => 'selected'], + 'Two' => ['value' => 2], + ])->select(2); + + $matcher = $this->controlGroup( + '' + ); + + $this->assertEquals($matcher, $select->__toString()); + } + + public function testOptgroupSupportsNestedOptionsWithAttributes() + { + $select = $this->former->select('foo')->addOption([ + 'A' => ['value' => 1, 'data-type' => 'x'], + 'B' => ['value' => 2, 'data-type' => 'y'], + ], 'Group 1'); + + $matcher = $this->controlGroup( + '' + ); + + $this->assertEquals($matcher, $select->__toString()); + } + + public function testSelectHandlesLooseTypeMatchingForValues() + { + $select = $this->former->select('foo')->options([ + 'Zero' => ['value' => 0], + 'One' => ['value' => 1], + ])->select('0'); + + $matcher = $this->controlGroup( + '' + ); + + $this->assertEquals($matcher, $select->__toString()); + } }