5

我想创建一个Zend_Form带有嵌套复选框的。我确信这是可能的,但我不记得该怎么做。这就是它的样子:

[x] Top level checkbox 1
    [ ] Sub level 1
    [x] Sub level 2

[ ] Top level 2
    [ ] Sub level 1
    [ ] Sub level 2

我将如何实现这个结果?

4

2 回答 2

1

我有一个解决这个问题的方法。这不是最好的,但现在对我来说已经足够了。

首先,您需要将传递给表单的有效数组。如果您从数据库中选择数据,您的数组将具有类似的结构:

array(
0=>array(
    'id'=>1,
    'name'=>'Top level 1',
    'parent_id'=>0
    )
1=>array(
    'id'=>2,
    'name'=>'Top level 2',
    'parent_id'=>0
    )
2=>array(
    'id'=>3,
    'name'=>'Sub level 1',
    'parent_id'=>1
    )
3=>array(
    'id'=>4,
    'name'=>'Sub level 2',
    'parent_id'=>1
    )
4=>array(
    'id'=>5,
    'name'=>'Sub level 1',
    'parent_id'=>2
    )
5=>array(
    'id'=>6,
    'name'=>'Sub level 1',
    'parent_id'=>2
    )
)

您需要转换此数组。我已经使用了过滤器:

class My_Filter_Array_ParentRelation implements Zend_Filter_Interface {


public function __construct() {
}

public function filter($arr) {
    $data = array();
    foreach ( $arr as $value ) {
        $data[$value['parent_id']][$value['id']] = $value['name'];
    }
    $data = $this->create($data, 0,0);

    return $data;
}

public function create($data, $pid=0,$l) {
    $new_data = array();
    if ( $data[$pid] ) {
        foreach ($data[$pid] as $id => $value) {
            $new_data[$id] = str_repeat('---',$l).$value;
            if(isset($id)) {
                $temp_data = $this->create($data, $id,$l+1);
                $new_data = $new_data + $temp_data;
            }
        }
    }

    return $new_data;
}
}

这个过滤器有什么作用?它返回一个相对于父元素排序的一维数组。嵌套级别标记为“---”。例子:

array(
1=>'Top level 1',
3=>'---Sub level 1',
4=>'---Sub level 2',
2=>'Top level 2',
5=>'---Sub level 1',
6=>'---Sub level 2'
)

然后我创建表单。它具有特定的元素 category_id。我将为它设置视图助手。

class My_Form_Product extends Zend_Form {

protected $_categories = array();

public function init() {
    $this
        ->addElement('multiCheckbox', 'category_id', array('label' => 'Category:', 'required' => true, 'multiOptions' => $this->getCategories()));

    $this->category_id->helper = 'MultiCheckbox';
}

public function setCategories($categories = array()) {
    $this->_categories = $categories;
    return $this;
}

public function getCategories() {
    return $this->_categories;
}
}

然后你需要查看帮助代码:

class My_View_Helper_MultiCheckbox extends Zend_View_Helper_FormElement
{

protected $_inputType = 'checkbox';


protected $_isArray = false;

public function MultiCheckbox($name, $value = null, $attribs = null,
    $options = null, $listsep = "\n")
{

    $info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
    extract($info); // name, value, attribs, options, listsep, disable
    $listsep = "\n";

    // retrieve attributes for labels (prefixed with 'label_' or 'label')
    $label_attribs = array();
    foreach ($attribs as $key => $val) {
        $tmp    = false;
        $keyLen = strlen($key);
        if ((6 < $keyLen) && (substr($key, 0, 6) == 'label_')) {
            $tmp = substr($key, 6);
        } elseif ((5 < $keyLen) && (substr($key, 0, 5) == 'label')) {
            $tmp = substr($key, 5);
        }

        if ($tmp) {
            // make sure first char is lowercase
            $tmp[0] = strtolower($tmp[0]);
            $label_attribs[$tmp] = $val;
            unset($attribs[$key]);
        }
    }

    $labelPlacement = 'append';
    foreach ($label_attribs as $key => $val) {
        switch (strtolower($key)) {
            case 'placement':
                unset($label_attribs[$key]);
                $val = strtolower($val);
                if (in_array($val, array('prepend', 'append'))) {
                    $labelPlacement = $val;
                }
                break;
        }
    }

    // the radio button values and labels
    $options = (array) $options;

    // build the element
    $xhtml = '';
    $list  = array();

    // should the name affect an array collection?
    $name = $this->view->escape($name);
    if ($this->_isArray && ('[]' != substr($name, -2))) {
        $name .= '[]';
    }

    // ensure value is an array to allow matching multiple times
    $value = (array) $value;

    // XHTML or HTML end tag?
    $endTag = ' />';
    if (($this->view instanceof Zend_View_Abstract) && !$this->view->doctype()->isXhtml()) {
        $endTag= '>';
    }

    // add radio buttons to the list.
    $filter = new Zend_Filter_Alnum();
    foreach ($options as $opt_value => $opt_label) {

        // Should the label be escaped?
        if ($escape) {
            $opt_label = $this->view->escape($opt_label);
        }

        // is it disabled?
        $disabled = '';
        if (true === $disable) {
            $disabled = ' disabled="disabled"';
        } elseif (is_array($disable) && in_array($opt_value, $disable)) {
            $disabled = ' disabled="disabled"';
        }

        // is it checked?
        $checked = '';
        if (in_array($opt_value, $value)) {
            $checked = ' checked="checked"';
        }

        // generate ID
        $optId = $id . '-' . $filter->filter($opt_value);

        // Wrap the radios in labels
        $wrapper_start = '';
        $wrapper_end = '</label><br >';
        $level = substr_count($opt_label,'---');
        $opt_label = str_replace('---','',$opt_label);
        $label = '<label '. $this->_htmlAttribs($label_attribs) . ' for="' . $optId . '">' .$opt_label;
        $radio = (('prepend' == $labelPlacement) ? $label : '')
                . str_repeat('&nbsp;&nbsp;&nbsp;',$level).'<input type="' . $this->_inputType . '"'
                . ' name="' . $name . '"'
                . ' id="' . $optId . '"'
                . ' value="' . $this->view->escape($opt_value) . '"'
                . $checked
                . $disabled
                . $this->_htmlAttribs($attribs)
                . $endTag .' '
                . (('append' == $labelPlacement) ? $label : '');
        $text = $wrapper_start . $radio . $wrapper_end;

        // add to the array of radio buttons
        $list[] = $text;
    }

    // done!
    $xhtml .= implode($listsep, $list);

    return $xhtml;
}
}

该助手将找到标记“---”并&nbsp;在复选框前设置三个间隔 ( )。

所以留下来只显示控制器动作。您从 db 获取类别列表,将其过滤到新数组中,然后创建表单并发送以形成过滤后的数组:

$categories = Something::getCategories();
$filterCategory = new My_Filter_Array_ParentRelation();

$form = new Admin_Form_Product(array(
    'name' => 'Form',
    'categories' => $filterCategory->filter($categories->toArray()),
));

$this->view->form = $form;
于 2011-03-26T13:45:57.320 回答
0

您可以使用 ViewScript 装饰器来执行此操作

http://framework.zend.com/manual/en/zend.form.standardDecorators.html#zend.form.standardDecorators.viewScript

一个例子

class MyForm extends Zend_Form
{

    public function init()
    {
        $this->addElement('checkbox', 'elementName', array(
            'multiOptions' => array(
                'level1' => array(
                    'Level 1 Option 1',
                    'Level 1 Option 2',
                ),
                'level2' => array(
                    'Level 2 Option 1',
                    'Level 2 Option 2',
                ),
            ),
            'label' => 'Element Label',
            'decorators' => array(
                array('ViewScript', array(
                        'viewScript' => '_element.phtml',
                        'class' => 'form element')
                    )
            )
        ));
    }
}

在您的视图脚本目录中创建 _element.phtml。

<div class="<?php echo $this->class ?>">
    <?php echo $this->formLabel($this->element->getName(),
                         $this->element->getLabel()) ?>

    <?php $options = $this->element->getAttribs(); ?>

    <?php if(isset($options['multiOptions']) && is_array($options['multiOptions'])): ?>
        <ul>
        <?php foreach($options['multiOptions'] as $level => $levelOptions): ?>
            <li>
                <span><?php echo $level; ?></span>
                <?php if(is_array($levelOptions)): ?>
                <ul>
                    <?php foreach($levelOptions as $key => $value): ?>
                    <li>
                        <?php echo $this->{$this->element->helper}(
                            $this->element->getName() . '[' . $key . ']',
                            $this->element->getValue(),
                            $options['options']
                         ) ?><label><?php echo $value; ?></label>
                    </li>
                    <?php endforeach; ?>
                </ul>
                <?php endif; ?>
            </li>
        <?php endforeach; ?>
        </ul>
    <?php endif; ?>

    <?php echo $this->formErrors($this->element->getMessages()) ?>

    <div class="hint"><?php echo $this->element->getDescription() ?></div>
</div>
于 2011-01-17T22:29:12.057 回答