2010-10-19 39 views
5

Tôi muốn tạo một Zend_Form với các hộp kiểm lồng nhau. Tôi chắc chắn rằng nó có thể, nhưng tôi không nhớ làm thế nào để làm điều đó. Đây là hình thức của nó:Zend Framework Nested Checkboxes

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

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

Làm cách nào để đạt được kết quả này?

Trả lời

0

Bạn có thể sử dụng ViewScript Decorator làm

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

Một thí dụ

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') 
        ) 
      ) 
     )); 
    } 
} 

Tạo _element.phtml này trong thư mục xem kịch bản của bạn.

<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> 
1

Tôi có một giải pháp cho vấn đề này. Nó không phải là tốt nhất, nhưng nó là đủ cho tôi bây giờ.

đầu tiên bạn cần mảng hợp lệ mà bạn sẽ chuyển sang biểu mẫu. nếu bạn chọn dữ liệu từ cơ sở dữ liệu, mảng của bạn sẽ có cấu trúc tương tự:

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 
    ) 
) 

Bạn cần phải chuyển đổi mảng này. Tôi đã sử dụng bộ lọc cho nó:

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; 
} 
} 

Bộ lọc này làm gì? nó trả về một mảng một chiều được sắp xếp liên quan đến phần tử cha. Mức lồng nhau được đánh dấu là "---". Ví dụ:

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' 
) 

Sau đó, tôi tạo biểu mẫu. Nó có phần tử category_id cụ thể. Tôi sẽ thiết lập trợ giúp xem cho nó.

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; 
} 
} 

Sau đó, bạn cần xem mã giúp đỡ:

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; 
} 
} 

helper này sẽ tìm ra dấu '---' và thiết lập ba miếng đệm (&nbsp;) trước hộp kiểm.

Vì vậy, chỉ hoạt động với bộ điều khiển hiển thị. Bạn nhận danh sách các loại từ db, lọc nó trong mảng mới, sau đó tạo biểu mẫu và gửi để tạo thành mảng được lọc:

$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;