Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/6009'
Browse files Browse the repository at this point in the history
  • Loading branch information
weierophinney committed Apr 14, 2014
2 parents 36fd7a2 + 5489f39 commit 469ddd8
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 7 deletions.
98 changes: 92 additions & 6 deletions library/Zend/Form/Element/Select.php
Expand Up @@ -50,6 +50,16 @@ class Select extends Element implements InputProviderInterface
*/
protected $valueOptions = array();

/**
* @var bool
*/
protected $useHiddenElement = false;

/**
* @var string
*/
protected $unselectedValue = '';

/**
* @return array
*/
Expand Down Expand Up @@ -128,6 +138,14 @@ public function setOptions($options)
$this->setDisableInArrayValidator($this->options['disable_inarray_validator']);
}

if (isset($options['use_hidden_element'])) {
$this->setUseHiddenElement($options['use_hidden_element']);
}

if (isset($options['unselected_value'])) {
$this->setUnselectedValue($options['unselected_value']);
}

return $this;
}

Expand Down Expand Up @@ -206,10 +224,7 @@ protected function getValidator()
'strict' => false
));

$multiple = (isset($this->attributes['multiple']))
? $this->attributes['multiple'] : null;

if (true === $multiple || 'multiple' === $multiple) {
if ($this->isMultiple()) {
$validator = new ExplodeValidator(array(
'validator' => $validator,
'valueDelimiter' => null, // skip explode if only one value
Expand All @@ -222,9 +237,51 @@ protected function getValidator()
}

/**
* Provide default input rules for this element
* Do we render hidden element?
*
* @param bool $useHiddenElement
* @return Select
*/
public function setUseHiddenElement($useHiddenElement)
{
$this->useHiddenElement = (bool) $useHiddenElement;
return $this;
}

/**
* Do we render hidden element?
*
* @return bool
*/
public function useHiddenElement()
{
return $this->useHiddenElement;
}

/**
* Set the value if the select is not selected
*
* Attaches the captcha as a validator.
* @param string $unselectedValue
* @return Select
*/
public function setUnselectedValue($unselectedValue)
{
$this->unselectedValue = (string) $unselectedValue;
return $this;
}

/**
* Get the value when the select is not selected
*
* @return string
*/
public function getUnselectedValue()
{
return $this->unselectedValue;
}

/**
* Provide default input rules for this element
*
* @return array
*/
Expand All @@ -235,6 +292,24 @@ public function getInputSpecification()
'required' => true,
);

if ($this->useHiddenElement() && $this->isMultiple()) {
$unselectedValue = $this->getUnselectedValue();

$spec['allow_empty'] = true;
$spec['continue_if_empty'] = true;
$spec['filters'] = array(array(
'name' => 'Callback',
'options' => array(
'callback' => function ($value) use ($unselectedValue) {
if ($value === $unselectedValue) {
$value = array();
}
return $value;
}
)
));
}

if ($validator = $this->getValidator()) {
$spec['validators'] = array(
$validator,
Expand Down Expand Up @@ -270,4 +345,15 @@ protected function getOptionValue($key, $optionSpec)
{
return is_array($optionSpec) ? $optionSpec['value'] : $key;
}

/**
* Element has the multiple attribute
*
* @return bool
*/
public function isMultiple()
{
return isset($this->attributes['multiple'])
&& ($this->attributes['multiple'] === true || $this->attributes['multiple'] === 'multiple');
}
}
45 changes: 44 additions & 1 deletion library/Zend/Form/View/Helper/FormSelect.php
Expand Up @@ -9,6 +9,7 @@

namespace Zend\Form\View\Helper;

use Zend\Form\Element\Hidden;
use Zend\Form\ElementInterface;
use Zend\Form\Element\Select as SelectElement;
use Zend\Form\Exception;
Expand Down Expand Up @@ -66,6 +67,11 @@ class FormSelect extends AbstractHelper
'label' => true,
);

/**
* @var FromHidden|null
*/
protected $formHiddenHelper;

/**
* Invoke helper as functor
*
Expand Down Expand Up @@ -123,11 +129,22 @@ public function render(ElementInterface $element)
}
$this->validTagAttributes = $this->validSelectAttributes;

return sprintf(
$rendered = sprintf(
'<select %s>%s</select>',
$this->createAttributesString($attributes),
$this->renderOptions($options, $value)
);

// Render hidden element
$useHiddenElement = method_exists($element, 'useHiddenElement')
&& method_exists($element, 'getUnselectedValue')
&& $element->useHiddenElement();

if ($useHiddenElement) {
$rendered = $this->renderHiddenElement($element) . $rendered;
}

return $rendered;
}

/**
Expand Down Expand Up @@ -278,4 +295,30 @@ protected function validateMultiValue($value, array $attributes)

return $value;
}

protected function renderHiddenElement(ElementInterface $element)
{
$hiddenElement = new Hidden($element->getName());
$hiddenElement->setValue($element->getUnselectedValue());

return $this->getFormHiddenHelper()->__invoke($hiddenElement);
}

/**
* @return FormHidden
*/
protected function getFormHiddenHelper()
{
if (!$this->formHiddenHelper) {
if (method_exists($this->view, 'plugin')) {
$this->formHiddenHelper = $this->view->plugin('formhidden');
}

if (!$this->formHiddenHelper instanceof FormHidden) {
$this->formHiddenHelper = new FormHidden();
}
}

return $this->formHiddenHelper;
}
}
34 changes: 34 additions & 0 deletions tests/ZendTest/Form/Element/SelectTest.php
Expand Up @@ -235,4 +235,38 @@ public function testUnsetUndefinedValueOption()
$this->assertArrayNotHasKey('Option Undefined', $valueOptions);
}

public function testSetOptionsToSelectMultiple()
{
$element = new SelectElement(null, array(
'label' => 'Importance',
'use_hidden_element' => true,
'unselected_value' => 'empty',
'value_options' => array(
'foo' => 'Foo',
'bar' => 'Bar'
),
));
$element->setAttributes(array('multiple' => 'multiple'));

$this->assertTrue($element->isMultiple());
$this->assertTrue($element->useHiddenElement());
$this->assertEquals('empty', $element->getUnselectedValue());
}

public function testProvidesInputSpecificationForMultipleSelectWithUseHiddenElement()
{
$element = new SelectElement();
$element
->setUseHiddenElement(true)
->setAttributes(array(
'multiple' => true,
));

$inputSpec = $element->getInputSpecification();

$this->assertArrayHasKey('allow_empty', $inputSpec);
$this->assertTrue($inputSpec['allow_empty']);
$this->assertArrayHasKey('continue_if_empty', $inputSpec);
$this->assertTrue($inputSpec['continue_if_empty']);
}
}
89 changes: 89 additions & 0 deletions tests/ZendTest/Form/FormTest.php
Expand Up @@ -1906,6 +1906,95 @@ public function testFormElementValidatorsMergeIntoAppliedInputFilter()
$this->assertTrue($this->form->isValid());
}

/**
* @param bool $expectedIsValid
* @param array $expectedFormData
* @param array $data
* @param string $unselectedValue
* @param bool $useHiddenElement
* @dataProvider formWithSelectMultipleAndEmptyUnselectedValueDataProvider
*/
public function testFormWithSelectMultipleAndEmptyUnselectedValue(
$expectedIsValid,
array $expectedFormData,
array $data,
$unselectedValue,
$useHiddenElement
)
{
$this->form->add(array(
'name' => 'multipleSelect',
'type' => 'Zend\Form\Element\Select',
'attributes' => array('multiple' => 'multiple'),
'options' => array(
'label' => 'Importance',
'use_hidden_element' => $useHiddenElement,
'unselected_value' => $unselectedValue,
'value_options' => array(
'foo' => 'Foo',
'bar' => 'Bar'
),
),
));

$actualIsValid = $this->form->setData($data)->isValid();
$this->assertEquals($expectedIsValid, $actualIsValid);

$formData = $this->form->getData();
$this->assertEquals($expectedFormData, $formData);
}

/**
* @return array
*/
public function formWithSelectMultipleAndEmptyUnselectedValueDataProvider()
{
return array(
array(
true,
array('multipleSelect' => array('foo')),
array('multipleSelect' => array('foo')),
'',
true
),
array(
true,
array('multipleSelect' => array()),
array('multipleSelect' => ''),
'',
true
),
array(
true,
array('multipleSelect' => array()),
array('multipleSelect' => 'empty'),
'empty',
true
),
array(
false,
array('multipleSelect' => ''),
array('multipleSelect' => ''),
'empty',
true
),
array(
false,
array('multipleSelect' => ''),
array('multipleSelect' => ''),
'',
false
),
array(
true,
array('multipleSelect' => array()),
array('multipleSelect' => 'foo'),
'foo',
true
),
);
}

public function testCanSetUseInputFilterDefaultsViaArray()
{
$spec = array(
Expand Down
10 changes: 10 additions & 0 deletions tests/ZendTest/Form/View/Helper/FormSelectTest.php
Expand Up @@ -384,6 +384,16 @@ public function testCanMarkOptionsAsSelectedWhenEmptyOptionOrZeroValueSelected()
$this->assertContains('<option value="0" selected="selected">label0</option>', $markup);
}

public function testHiddenElementWhenAttributeMultipleIsSet()
{
$element = new SelectElement('foo');
$element->setUseHiddenElement(true);
$element->setUnselectedValue('empty');

$markup = $this->helper->render($element);
$this->assertContains('<input type="hidden" name="foo" value="empty"><select', $markup);
}

public function testRenderInputNotSelectElementRaisesException()
{
$element = new Element\Text('foo');
Expand Down

0 comments on commit 469ddd8

Please sign in to comment.