Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ViewScript Decorator on Nested Subforms (Zend Form)

I want to use a view script to render my zend form as it seems to be the best way to control the layout/design of the form while still using the Zend_Elements classes.

From the view script, I render the element with $this->element->getElement('elementName') .

I'm having problems with the names of the elements. This is actually a sub-form inside a sub-form inside a form.

When I used the FormElements decorators , the fully qualified name of the elements was form[subForm][subForm][element] , which was good. Wehn I moved to the viewScript decorators, it changed to subForm[subForm][element].

I understood that I need to use the PrepareElements decorator to fix this, but this caused the name to change form[subForm][form][subForm][subForm][elements] (it doubled the first two names in the start).

Any ideas how I should handle this?

Thanks.

UPDATE: I tried to debug PrepareElements and I really don't understand what is doing. It seems like it works ok in the first iteration, but then it adds again the form[subform] prefix when running on one of the middle subforms.

When I'm not using the PrepareElements decorator, I'm just missing the "form" prefix in the names (i.e., instead of form[subForm][element], I get only subForm[element]).

May be I can just fix this somehow?

I tried to change the belongsTo but that only replaced the "subForm" prefix .

It actually seems like what is missing is a belongsTo method on the subForm.

Again, this is all because of the ViewScript decorator. It works fine with the FormElements decorators.

UPDATE 2: Just to clarify, I wouldn't mind this name change, but it causes my fields to not populate when I call form->populate .

Edit: I think that I've narrowed the problem to this: when I get my values back in setDefaults, they are ordered like this:

array(
\"formElements1-name\" => value1... \"subFormName\" => array(
\"parentFormName\" => array(
\"subFormName\" => subForm-values-array
)
)

... The main problem here is the "parentFormName" => "subFormNAme".. what does it repeat itself? I'm already in the main form. I'm guessing this is caused because I've set the setElementsBelongTo(formName[subFormName]) , but if I wouldn't do that, then I would get my subform values completely separate from the form,

i.e. values array = array( \"formName\" => array( formValues ), \"subFormNAme\" => array( subFormValues )

, while I exepct it to be

array(
formName => array(
subFormNAme => values-array
)
)...

Is it even possible to make this work?

like image 586
Ran Avatar asked Sep 28 '11 21:09

Ran


2 Answers

Are you just trying to output your form using <?php echo $this->form; ?> from your view script?

That works well for simple forms, but for my more complex forms I tend to render each element individually but don't need to use ViewScript decorator on each individual element to do this. Just try something like this from your view script:

<div class="form">
    <fieldset>
        <legend>Some Form Name</legend>
        <form action="<?php echo $this->escape($this->form->getAction()) ?>"
              method="<?php echo $this->escape($this->form->getMethod()) ?>"
              enctype="multipart/form-data">

            <?php echo $this->form->id; // render the id element here ?>

            <div class="half">
                <?php echo $this->form->name; // render the user name field here ?>
            </div>
            <div class="half">
                <?php echo $this->form->description; // render the description element here ?>
            </div>
            <div class="clear"></div>

            <div class="half">
                <?php echo $this->form->address1; // render the address ?>
            </div>
            <div class="half">
                <?php echo $this->form->address2; // render address2 ?>
            </div>
            <div class="clear"></div>

            <div class="third">
                <?php echo $this->form->zip; // render zip code ?>
            </div>
            <div class="third">
                <?php echo $this->form->city; // render city ?>
            </div>
            <div class="third">
                <?php echo $this->form->state; // render state ?>
            </div>
            <div class="clear"></div>

            <div class="half">
                <?php echo $this->form->country; // render country ?>
            </div>
            <div class="clear"></div>

            <?php echo $this->form->submit; ?>

        </form>
    </fieldset>
</div>

That is how I do most of my forms because I want to have some elements take up half the width and others the full width.

Surprisingly, the reference guide doesn't tell you that you can do this. I seem to remember a page about it in the past but cannot find it now. When I got started with Zend Framework, I thought the only way I could get my form to output exactly how I wanted was to create complex decorators, but that is not the case.

Matthew Weier O'Phinney has a great blog post on rendering Zend_Form decorators individually which explains what I did above. I hope they add this to the first page of Zend Form because that was discouraging to me at first. The fact is, 90% of my forms render elements individually instead of just echo'ing the form itself.

Note: To stop ZF from enclosing my form elements in the dt and dd tags, I apply this decorator to all of my standard form elements. I have a base form class that I extend all of my forms from so I don't have to repeat this everywhere. This is the decorator for the element so I can use tags to enclose my elements.

public $elementDecorators = array(
    'ViewHelper',
    'Errors',
    array('Description', array('tag' => 'p',    'class' => 'description')),
    array('HtmlTag',     array('tag' => 'div', 'class' => 'form-div')),
    array('Label',       array('class' => 'form-label', 'requiredSuffix' => '*'))
);

For my submit buttons I use

public $buttonDecorators = array(
    'ViewHelper',
    array('HtmlTag', array('tag' => 'div', 'class' => 'form-button'))
);
like image 60
drew010 Avatar answered Sep 18 '22 11:09

drew010


The current solution is to use the PrepareElements decorator on the subforms with one change - remove the recursive call in the PrepareElements code. Also, no "setElementsBelongTo" is required.

This seem to generate the correct names and ids.

like image 30
Ran Avatar answered Sep 20 '22 11:09

Ran