Search code examples
zend-frameworkzend-formzend-decorators

Use zend-decorator to format Zend_Form_Element_Radio in a table column with oher Zend_Form_Elements in rows


I want use decorators to format as table the following Zend_Form, placing a description in the first column and the Zend_Form_Element_Radio's options in second column and add 2 select in every row as you can see in the html example later.

I need a concrete/working example.

FORM

class My_Form extends Zend_Form
{
    const KIND_1 = 'dineer1';
    const KIND_2 = 'dineer2';
    const KIND_3 = 'dineer3';
    const KIND_4 = 'dineer4';
    const KIND_5 = 'dineer5';
    const KIND_6 = 'dineer6';

    public static $KINDS = array(
        1 => self::KIND_1,
        2 => self::KIND_2,
        3 => self::KIND_3,
        4 => self::KIND_4,
        5 => self::KIND_5,
        6 => self::KIND_6,
    );

    const DRINK_C = 'c';
    const DRINK_M = 'm';
    const DRINK_W = 'w';

    public static $DRINKS = array(
        self::DRINK_C => "cole",
        self::DRINK_M => "milk",
        self::DRINK_W => "water",
    );

    const FOOD_B = 'b';
    const FOOD_F = 'f';
    const FOOD_M = 'm';
    const FOOD_P = 'p';
    const FOOD_V = 'v';
    const FOOD_W = 'w';

    public static $FOODS = array(
        self::FOOD_B => "burger",
        self::FOOD_F => "fruit",
        self::FOOD_M => "Meat",
        self::FOOD_P => "pizza",
        self::FOOD_V => "vegetables",
        self::FOOD_W => "Wursterl",
    );

    public function init()
    {
        $_please_select = array("" => " please select ");

        $this->setMethod(Zend_Form::METHOD_POST);

        $input_lunch = new Zend_Form_Element_Radio('lunch');  
        $input_lunch ->setMultiOptions(self::$KINDS) ;
        $this->addElement($input_lunch );

        foreach (self::$KINDS as $k => $_descriprion) {
            $input_drink = new Zend_Form_Element_Select('drink_' . $k);
            $input_drink->addMultiOptions(self::$DRINKS);

            $input_food = new Zend_Form_Element_Select('food_' . $k);
            $input_food->addMultiOptions($_please_select)
                ->addMultiOptions(self::$FOODS);

            $this->addElement($input_drink);
            $this->addElement($input_food);
        }
    }
}

expected HTML

<html>
<body>
    <form action="/" method="POST">
    <table>
    <thead>
        <tr>
            <th></td>
            <th>kind</td>
            <th>drink</td>
            <th>food</td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Description row 1</td>
            <td><input type="radio" name="lunch" value "dinner1"></td>
            <td>
                <select name="drink_1">
                    <option value="w">Water</option>
                    <option value="m">Milk</option>
                    <option value="b">Beer</option>
                </select>
            </td>
            <td>
                <select name="food_1">
                    <option value="">please select</option>
                    <option value="b">Burger</option>
                    <option value="f">Fruit</option>
                    <option value="m">Meat</option>
                    <option value="p">Pizza</option>
                    <option value="v">Vegetable</option>
                    <option value="w">Wurstel</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Description row 2</td>
            <td><input type="radio" name="lunch" value "dinner2"></td>
            <td>
                <select name="drink_2">
                    <option value="w">Water</option>
                    <option value="m">Milk</option>
                    <option value="b">Beer</option>
                </select>
            </td>
            <td>
                <select name="food_2">
                    <option value="">please select</option>
                    <option value="b">Burger</option>
                    <option value="f">Fruit</option>
                    <option value="m">Meat</option>
                    <option value="p">Pizza</option>
                    <option value="v">Vegetable</option>
                    <option value="w">Wurstel</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Description row 3</td>
            <td><input type="radio" name="lunch" value "dinner3"></td>
            <td>
                <select name="drink_3">
                    <option value="w">Water</option>
                    <option value="m">Milk</option>
                    <option value="b">Beer</option>
                </select>
            </td>
            <td>
                <select name="food_3">
                    <option value="">please select</option>
                    <option value="b">Burger</option>
                    <option value="f">Fruit</option>
                    <option value="m">Meat</option>
                    <option value="p">Pizza</option>
                    <option value="v">Vegetable</option>
                    <option value="w">Wurstel</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Description row 4</td>
            <td><input type="radio" name="lunch" value "dinner4"></td>
            <td>
                <select name="drink_4">
                    <option value="w">Water</option>
                    <option value="m">Milk</option>
                    <option value="b">Beer</option>
                </select>
            </td>
            <td>
                <select name="food_4">
                    <option value="">please select</option>
                    <option value="b">Burger</option>
                    <option value="f">Fruit</option>
                    <option value="m">Meat</option>
                    <option value="p">Pizza</option>
                    <option value="v">Vegetable</option>
                    <option value="w">Wurstel</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Description row 5</td>
            <td><input type="radio" name="lunch" value "dinner5"></td>
            <td>
                <select name="drink_5">
                    <option value="w">Water</option>
                    <option value="m">Milk</option>
                    <option value="b">Beer</option>
                </select>
            </td>
            <td>
                <select name="food_5">
                    <option value="">please select</option>
                    <option value="b">Burger</option>
                    <option value="f">Fruit</option>
                    <option value="m">Meat</option>
                    <option value="p">Pizza</option>
                    <option value="v">Vegetable</option>
                    <option value="w">Wurstel</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Description row 6</td>
            <td><input type="radio" name="lunch" value "dinner6"></td>
            <td>
                <select name="drink_6">
                    <option value="w">Water</option>
                    <option value="m">Milk</option>
                    <option value="b">Beer</option>
                </select>
            </td>
            <td>
                <select name="food_6">
                    <option value="">please select</option>
                    <option value="b">Burger</option>
                    <option value="f">Fruit</option>
                    <option value="m">Meat</option>
                    <option value="p">Pizza</option>
                    <option value="v">Vegetable</option>
                    <option value="w">Wurstel</option>
                </select>
            </td>
        </tr>
        </tbody>
        <table>
    </form>
</body>
</html>

Solution

  • I would suggest a solution based on this answer here https://stackoverflow.com/a/8451723/212940

    Your form:-

    class My_Form extends Zend_Form
    {
        const KIND_1 = 'dineer1';
        const KIND_2 = 'dineer2';
        const KIND_3 = 'dineer3';
        const KIND_4 = 'dineer4';
        const KIND_5 = 'dineer5';
        const KIND_6 = 'dineer6';
    
        public static $KINDS = array(
            1 => self::KIND_1,
            2 => self::KIND_2,
            3 => self::KIND_3,
            4 => self::KIND_4,
            5 => self::KIND_5,
            6 => self::KIND_6,
        );
    
        const DRINK_C = 'c';
        const DRINK_M = 'm';
        const DRINK_W = 'w';
    
        public static $DRINKS = array(
            self::DRINK_C => "cole",
            self::DRINK_M => "milk",
            self::DRINK_W => "water",
        );
    
        const FOOD_B = 'b';
        const FOOD_F = 'f';
        const FOOD_M = 'm';
        const FOOD_P = 'p';
        const FOOD_V = 'v';
        const FOOD_W = 'w';
    
        public static $FOODS = array(
            self::FOOD_B => "burger",
            self::FOOD_F => "fruit",
            self::FOOD_M => "Meat",
            self::FOOD_P => "pizza",
            self::FOOD_V => "vegetables",
            self::FOOD_W => "Wursterl",
        );
    
        public function init()
        {
            $this->addDecorators(
                array(
                    array('ViewScript', array('viewScript' => 'forms/_form_test.phtml'))
                )
            ); //added as part of answer. Note all default decorators are still available.
    
            $_please_select = array("" => " please select ");
    
            $this->setMethod(Zend_Form::METHOD_POST);
    
            $input_lunch = new Zend_Form_Element_Radio('lunch');  
            $input_lunch ->setMultiOptions(self::$KINDS) ;
            $this->addElement($input_lunch );
    
            foreach (self::$KINDS as $k => $_descriprion) {
                $input_drink = new Zend_Form_Element_Select('drink_' . $k);
                $input_drink->addMultiOptions(self::$DRINKS);
    
                $input_food = new Zend_Form_Element_Select('food_' . $k);
                $input_food->addMultiOptions($_please_select)
                    ->addMultiOptions(self::$FOODS);
    
                $this->addElement($input_drink);
                $this->addElement($input_food);
            }
            $this->setElementDecorators(array('ViewHelper'));//added as part of answer
        }
    }
    

    As you can see it requires only two small changes.
    Then you need to create the file scripts/forms/_form_test.phtml which contains:-

    <form
        id='contact' 
        action='<?php echo $this->element->getAction(); ?>' 
        method='<?php echo $this->element->getMethod(); ?>'
    >
    <table>
        <thead>
            <tr>
                <th></td>
                <th>kind</td>
                <th>drink</td>
                <th>food</td>
            </tr>
        </thead>
        <tbody>
            <?php 
            $elements = $this->element->getElements();
            $options = $this->element->lunch->getMultiOptions();
            foreach($options as $key => $option){
                echo "<tr>\n";
                echo "<td>Description row $key</td>\n";
                echo "<td><input type='radio' name='lunch' value='$option'</td>\n";
                echo "<td>{$elements['drink_' . $key]}</td>\n";
                echo "<td>{$elements['food_' . $key]}</td>\n";
                echo "</tr>\n";
            }
            ?>
            </tbody>
            <table>
    </form>
    

    The file _form_test.phtml is effectively your decorator for rendering the form. This is a very flexible way of using Zend_Form and I learnt how to do this by reading this article here

    The default decorators, such as 'error' should still be available with this method.

    On my system I got the exact html output you asked for. Try it and see.