2010-10-19 18 views
5

Vorrei creare un Zend_Form con caselle di controllo annidate. Sono sicuro che sia possibile, ma non ricordo come farlo. Questo è come sarebbe:Caselle nidificate di Zend Framework

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

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

Come raggiungere questo risultato?

risposta

0

È possibile utilizzare ViewScript Decorator per fare questo

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

Un esempio

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

Crea _element.phtml nella directory vista script.

<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

Ho una soluzione a questo problema. Non è il migliore, ma ora è abbastanza per me.

in primo luogo è necessario un array valido che si passerà al modulo. se si seleziona i dati dal database, l'array avrà struttura simile:

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

È necessario trasformare questo array. Ho usato il filtro per questo:

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

Cosa fa questo filtro? restituisce un array unidimensionale ordinato relativo all'elemento padre. Il livello annidato è contrassegnato come "---". Esempio:

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

Quindi creo il modulo. Ha un elemento specifico category_id. Imposterò l'assistente di visualizzazione per questo.

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

allora avete bisogno di visualizzazione del codice di supporto:

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

questo helper troverà il marchio '---' e impostare tre distanziatori (&nbsp;) prima della casella di controllo.

Quindi resta solo l'azione del controller di visualizzazione. Ottieni l'elenco delle categorie da db, lo filtra in un nuovo array, quindi crea il modulo e invialo per formare l'array filtrato:

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