2010-10-19 25 views
5

Me gustaría crear un Zend_Form con casillas anidadas. Estoy seguro de que es posible, pero no recuerdo cómo hacerlo. Esto es lo que se vería así:Zend Framework Casillas Anidadas

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

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

¿Cómo puedo lograr este resultado?

Respuesta

0

Usted puede utilizar ViewScript decorador de hacer esto

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

Un ejemplo

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

Crear _element.phtml en el directorio de scripts de vista.

<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

Tengo una solución para este problema. No es lo mejor, pero es suficiente para mí ahora.

En primer lugar necesita una matriz válida que pasará al formulario. si selecciona los datos de la base de datos, la matriz tendrá una estructura similar:

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

Es necesario transformar esta matriz. He usado filtro para él:

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

¿Qué hacer este filtro? devuelve una matriz unidimensional ordenada relativa al elemento principal. El nivel anidado está marcado como "---". Ejemplo:

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

Luego creo el formulario. Tiene elemento específico category_id. Voy a configurar view helper para eso.

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

entonces usted necesita ayudante de vista de código:

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

Este asistente encontrará la marca '---' y establecer tres espaciadores (&nbsp;) antes de casilla de verificación.

Así que quédate solo para mostrar la acción del controlador. Obtiene la lista de categorías de db, la filtra en una matriz nueva, luego crea la forma y la envía para formar la matriz filtrada:

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