Glad to see that I'm not the only person that has found it difficult to get their head around form decorators. My current approach is to use view helper scripts to position the individual form elements in the page. Using a form helper then allows me to use the same script if using the form to create/add initial data or to update existing data.
starting in the controller, I will instantiate a form object and assign it to a view variable.
PHP Code:
public function addexptAction()
{
$this->view->title = 'Add Experiment';
$form = new Expt_Form_DetailsForm;
$form->setAction( $this->getUrlThisAction() );
$this->view->form = $form; // var_dump($form);die;
I set the value of the form action inside the controller, all other form attributes are pretty standard so I set them inside the form class, which I will show later.
An example view script (addexperiment.phtml) might look something like this...
PHP Code:
<div class="prepend-8 span-10 append-6 prepend-top content last" id="Title_container">
<h2><?php echo $this->title ?></h2>
</div>
<?php echo $this->ExptDetails01( $this->form ); ?>
above you can see that I am passing the form object into the view helper script (ExptDetails01.php)
This next piece of code is the view helper
[
PHP Code:
<?php
class Expt_View_Helper_ExptDetails01 extends Zend_View_Helper_Abstract
{
/**
* Description: accepts form object of type Expt_Form_DetailsForm and returns form html text
* @param $form
* @return text
*/
public function ExptDetails01( Expt_Form_DetailsForm $form )
{
$content=<<<_HTML_
<!-- START: Form Element -->
<form name="{$form->getAttrib('name')}"
class="{$form->getAttrib('class')}"
id="{$form->getAttrib('id')}"
enctype="{$form->getAttrib('enctype')}"
action="{$form->getAttrib('action')}"
method="{$form->getAttrib('method')}" >
<div class="span-24 maincontent-1 last" id="form_container">
<div class="prepend-1 span-10 last"> {$form->getElement("expt_number")->getLabel()} : {$form->getElement("expt_number")}</div>
</div> <!-- end div: form_container -->
<div class="span-24 maincontent-1 last" id="form_container">
<div class="prepend-1 span-10 last"> {$form->getElement("diet")->getLabel()} : {$form->getElement("diet")}</div>
</div> <!-- end div: form_container -->
_HTML_;
if ($form->getElement("id")) {
$content.=<<<_HTML_
{$form->getElement("id")}
_HTML_;
}
$content.=<<<_HTML_
<div class="span-24 maincontent-1 last" id="form_container">
<div class="prepend-1 span-7 last">{$form->getElement("submit")}</div>
</div> <!-- end div: form_container -->
</form><!-- end form -->
_HTML_;
return $content;
}
} // end class.
The allowed form class that is acceptable by this function is restricted to a single type, Expt_Form_DetailsForm, in this example.
If the form is used to insert initial data, the id is a serial which is automatically assigned by the database. If I want to use the same form/view helper as an update form I must pass in an id element which is not in the form class but is something that I add at the controller.
for example in the controller I might have something like ...
PHP Code:
// add hidden id element to form so that id number association is kept.
$form->addElement( $id = new Zend_Form_Element_Hidden('id') );
$id->setValue((int)$arrMouse['id']);
Now the form class for this example. There are only three elements, a textbox, select box, and a submit button.
PHP Code:
<?php
class Expt_Form_DetailsForm extends My_Zend_Form
{
protected $detailsService;
protected $_refTableDiet;
public function __construct( $options = null )
{
parent::__construct($options);
$this->detailsService = new Expt_Service_DetailsService;
$this->_refTableDiet = new Expt_Model_RefTableDietModel; // var_dump($this->_refTableDiet);die;
$this->setName('mouse_form')
->setDescription('This is the Experiment Details Form')
//->setAction() // set in controller-Action
->setAttrib('enctype', 'application/x-www-form-urlencoded')
->setAttrib('method', 'post')
->setAttrib('id', 'expt_details_form')
->setAttrib('class', 'appform');
$formFeName = 'expt_number';
//======================================
$this->addElement( ${$formFeName} = new Zend_Form_Element_Text("$formFeName"));
${$formFeName}->setRequired(true)
->setLabel('Eperiment Number')
//->setValue('')
//->setDescription('Hr.')
->setAttrib( 'size', 15) // size of the form field
->setAttrib( 'maxlength', 255) // size of table field length
->addFilter('StripTags')
->addFilter('StringTrim')
->removeDecorator('label')
->removeDecorator('HtmlTag')
->removeDecorator('DtDdWrapper')
//->removeDecorator('Errors')
->addValidator('NotEmpty', false, array('messages'=>'Please enter the mouse assigned id number.')) // only works when setRequired(true)
//->addValidator('regex', true, array('/^[\d]/', 'messages'=>'Only numeric values allowed.'))
//->addValidator('Between', true ,array(0, 24, 'messages'=>'Hours value must be between 0 and 24.'))
;
$this->set_formElementName( $formFeName );
$this->set_formElementObject( ${$formFeName} );
$this->set_formElementObjectsAssoc( $formFeName, ${$formFeName} );
unset( $formFeName );
//=============================================================================
$formFeName = 'diet';
//=====================================================
$options_{$formFeName} = array( '0' => ' Please Select Diet' );
$options_{$formFeName} = $this->_refTableDiet->getAssocArray('diet_id', 'diet', 'diet_id ASC', $options_{$formFeName} );
$this->addElement( ${$formFeName} = new Zend_Form_Element_Select("$formFeName"));
//$this->addElement( ${$formFeName} = new Zend_Form_Element_MultiCheckbox("$formFeName"));
${$formFeName}->setRequired(true)
->setLabel('Location')
//->setValue('')
//->setDescription('test')
->setMultiOptions($options_{$formFeName})
->setAttrib( 'title', 'location')
->removeDecorator('label')
->removeDecorator('HtmlTag')
->removeDecorator('DtDdWrapper')
//->removeDecorator('Errors')
->addValidator('NotEmpty', false, array('messages'=>'Value is required.')) // only works when setRequired(true)
->addValidator('regex', true, array('/[^0]/', 'messages'=>'Please specify'))
;
$this->set_formElementName( $formFeName );
$this->set_formElementObject( ${$formFeName} );
$this->set_formElementObjectsAssoc( $formFeName, ${$formFeName} );
unset( $formFeName );
//===========================================================
$formFeName = 'submit';
//======================
$this->addElement( ${$formFeName} = new Zend_Form_Element_Submit("$formFeName"));
${$formFeName}->setAttrib('id', 'submitbutton')
->setAttrib( 'style', 'background:#ff9999;color:black;')
->removeDecorator('DtDdWrapper')
;
$this->set_formElementName( $formFeName );
$this->set_formElementObject( ${$formFeName} );
$this->set_formElementObjectsAssoc( $formFeName, ${$formFeName} );
unset( $formFeName );
//=============================================================================
} // end function: __construct
} // end class: Expt_Form_DetailsForm
This might look like a lot of needless and time consuming code, but all I have to do is copy and paste from some template code and make a few changes. Sometimes all I may need to do is only assign the name for the code blocks corresponding $formFeName variable.
The key=>values that I use for the select options are pulled from the model using the following function.
PHP Code:
public function getAssocArray($keyColumn=null, $valueColumn=null, $where=null, array $arrFirstPairs=null )
{
$arrPairs = array();
if ( ($keyColumn == null) || ($valueColumn == null) ){
// Throw exception, both inputs are required.
}
if ( $where == null ) {
$where = $valueColumn . ' ' . 'ASC';
}
if ( $arrFirstPairs != null ) {
$arrPairs = $arrFirstPairs; //print_r($arrPairs);die;
}
$result = $this->fetchAll(null, $where)->toArray();
// $arrPairs[0] = 'Select Type';
foreach ( $result as $row ) {
$arrPairs[$row[$keyColumn]] = $row[$valueColumn];
}
return $arrPairs;
}
You can see that I remove the form decorators for each of the elements, so that associated/imbedded html tags do not interfere with the layout in the view helper.
Hope this has been helpful for someone out there struggling with how to get that form element on your page in just the precise way that you want it displayed. One of these days I'll have to devote some serious study time to understand how decorators work. They must be a good thing; Else, why was it included in the framework.
All the best,
jim