Shardj / zf1-future

PHP 8.1 compatible version of ZF1
BSD 3-Clause "New" or "Revised" License
440 stars 192 forks source link

Select is always multiple #424

Open tomasr1981 opened 3 months ago

tomasr1981 commented 3 months ago

Hi, I extended Zend_Select:

<?php
require_once 'Zend/Form/Element/Select.php';

class My_Form_Element_SelectAttribs extends Zend_Form_Element_Select {

    public $options = array();
    public $helper = 'selectAttribs';

    public function addOption($value, $label = '', $attribs = array()) {
        $value = (string) $value;
        if (!empty($label)) {
            $label = (string) $label;
        } else {
            $label = $value;
        }
        $this->options[$value] = array(
            'value' => $value,
            'label' => $label
                ) + $attribs;
        return $this;
    }
}

This is using in form:

$select = new My_Form_Element_SelectAttribs('id');
$select->setLabel('Select')
             ->setValue(isset($_POST['id']) ? $_POST['id'] : null)
             ->setAttribs(array(
                    'size' => 1
             ));
$select->addOption(false, '==Select==');
foreach ($itemsForSelect as $item) {
    $select->addOption($item->country_id, $select->title, array('data-something' => $select->something));
}
$this->addElement($select);

Select has multiple attrib. How can I remove it? Param size does not work. In last oficial version of ZF1 ii worked.

Snímek obrazovky pořízený 2024-06-11 08-37-02

rruchte commented 3 months ago

Can you provide a concise runnable example? There is something important happening in your selectAttribs helper plugin that may be causing your problem.

When I run your code (after commenting out selectAttribs and editing the call to addOption), I do not get a multi-select, but the result is clearly not what you are looking for either. Seems like your problem is in your code.

<?php
class My_Form_Element_SelectAttribs extends Zend_Form_Element_Select {

    public $options = array();
    // What is this?
    //public $helper = 'selectAttribs';

    public function addOption($value, $label = '', $attribs = array()) {
        $value = (string) $value;
        if (!empty($label)) {
            $label = (string) $label;
        } else {
            $label = $value;
        }
        $this->options[$value] = array(
                                     'value' => $value,
                                     'label' => $label
                                 ) + $attribs;
        return $this;
    }
}

$select = new My_Form_Element_SelectAttribs('id');
$select->setLabel('Select')
       ->setValue(isset($_POST['id']) ? $_POST['id'] : null)
       ->setAttribs(array(
                        'size' => 1
                    ));
$select->addOption(false, '==Select==');

$itemsForSelect = [
    (object)['country_id' => 1, 'title' => 'Austria', 'something' => 'foo'],
    (object)['country_id' => 2, 'title' => 'Belgium', 'something' => 'bar'],
    (object)['country_id' => 3, 'title' => 'Croatia', 'something' => 'baz']
];

foreach ($itemsForSelect as $item)
{
    /*
     Are $select->title and $select->something correct? Should probably be looking for elements of $item, right?
     $select->addOption($item->country_id, $select->title, array('data-something' => $select->something));
     */
    $select->addOption($item->country_id, $item->title, array('data-something' => $item->something));
}

$form = new Zend_Form('foo');
$form->addElement($select);

echo $form->render();
echo PHP_EOL;

Result:

<form enctype="application/x-www-form-urlencoded" action="" method="post">
    <dl class="zend_form">
        <dt id="id-label"><label for="id" class="optional">Select</label></dt>
        <dd id="id-element">
            <select name="id" id="id" size="1">
                <optgroup id="id-optgroup-" label="">
                    <option value="value"></option>
                    <option value="label">==Select==</option>
                </optgroup>
                <optgroup id="id-optgroup-1" label="1">
                    <option value="value">1</option>
                    <option value="label">Austria</option>
                    <option value="data-something">foo</option>
                </optgroup>
                <optgroup id="id-optgroup-2" label="2">
                    <option value="value">2</option>
                    <option value="label">Belgium</option>
                    <option value="data-something">bar</option>
                </optgroup>
                <optgroup id="id-optgroup-3" label="3">
                    <option value="value">3</option>
                    <option value="label">Croatia</option>
                    <option value="data-something">baz</option>
                </optgroup>
            </select></dd>
    </dl>
</form>
tomasr1981 commented 3 months ago

Your are right. Helper looked like:

<?php

require_once 'Zend/View/Helper/FormElement.php';

class Zend_View_Helper_SelectAttribs extends Zend_View_Helper_FormElement {

    public function selectAttribs($name, $value = null, $attribs = null, $options = null, $listsep = "<br />\n") {
        $info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
        extract($info); // name, id, value, attribs, options, listsep, disable
        // force $value to array so we can compare multiple values to multiple
        // options; also ensure it's a string for comparison purposes.
        $value = array_map('strval', (array) $value);

        // now start building the XHTML.
        $disabled = '';
        if (true === $disable) {
            $disabled = ' disabled="disabled"';
        }

        // Build the surrounding select element first.
        $xhtml = '<select'
                . ' name="' . $this->view->escape($name) . '"'
                . ' id="' . $this->view->escape($id) . '"'
                . $disabled
                . $this->_htmlAttribs($attribs)
                . ">\n  ";

        // build the list of options
        $list = array();
        foreach ($options as $opt_value => $option) {
            $opt_disable = '';
            if (is_array($disable) && in_array($opt_value, $disable)) {
                $opt_disable = ' disabled="disabled"';
            }
            $list[] = $this->_build($option, $value, $disabled);
        }

        // add the options to the xhtml and close the select
        $xhtml .= implode("\n   ", $list) . "\n</select>";

        return $xhtml;
    }

    protected function _build($option, $selected, $disabled) {
        // selected
        $opt_selected = '';
        if (in_array((string) $option['value'], $selected)) {
            $opt_selected .= ' selected="selected"';
        }

        $html = '<option';
        foreach ($option as $attrib => $value) {
            $html .= $option['label'] !== $value ? " $attrib=\"$value\"" : null;
        }
        return $html . $opt_selected . $disabled . ">" . $option['label'] . "</option>";
    }
}

I had to add remove multiple attr when it was set as false:

if (isset($attribs['multiple']) && $attribs['multiple'] === false) {
        unset($attribs['multiple']);
}