ZendFramework Noob: Adding text on top of a form - zend-framework

I've just (as in today) started working on some ZF stuff.
I have a Form that needs to have some text in a div appear at the top of the form, but I have no idea how to include it.
The structure of the form is:
class MyForm extends \app\forms\FormType {
public function init() {
// gets all the form elements of the parent
parent::init();
// A few additional form elements for MyForm created here
}
}
Any help would be apprecaited!

In your controller where you instantiate the form object just set it with the view object like this:
public function actionNameAction()
{
// ...
if (/* some condition to check form page */) {
$this->view->divText = 'your text';
}
}
Then put the div in the action-name.phtml script:
views/scripts/controller/action-name.phtml
Contents:
<?php if (!empty($this->divText)): ?>
<div><?php echo $this->divText; ?></div>
<?php endif; ?>
Additionally, you could pass the view object by reference to your form class. Just overload the construct function like so:
public function __construct($options = null, &$view)
{
parent::__construct($options);
$this->view = $view;
}
Then in your controller when you instantiate your form object do this:
$form = new MyForm(null, $this->view);
Let's go back to your form class once again and modify the init() method:
public function init()
{
// ...
$this->view->divText = 'Text set from within ' . __CLASS__;
}
Using this way, you won't have to put any conditional if statements checking anything in the controller. You're already checking if $this->divText is not empty in the view, so by passing the view object to your form class you can ensure that that text will only be set when the form is being used.

Related

ZEND: Displaying form error messages on failed validation

I have a form say:
class Application_Form_UserDetails extends Zend_Form
{
public function init()
{
$pswd = new Zend_Form_Element_Password('password');
$pswd->setLabel('New password:');
$pswd->setAttrib('size', 25);
$pswd->setRequired(false);
$pswd->addValidator('StringLength', false, array(4,15));
$pswd->addErrorMessage('Wron password');
}
}
In my user details controller class I have:
class UserDetailsController extends Zend_Controller_Action {
public function editAction()
{
$userId = $this->userInfo->id;
$DbTableUsers = new Application_Model_DbTable_User;
$obj = $DbTableUsers->getUserDetails($userId);
$this->view->formUser = new $this->_UserDetails_form_class;
$this->view->formCompany = new $this->_CompanyDetails_form_class;
if ($obj) {
$this->view->formUser->populate($obj);
}
$url = $this->view->url(array('action' => 'update-user-details'));
$this->view->formUser->setAction($url);
}
public function updateUserDetailsAction()
{
$formUser = new $this->_UserDetails_form_class;
if ($formUser->isValid($this->getRequest()->getPost())) {
}
else {
//validation failed
$formUser->markAsError();
$this->view->formUser = $formUser;
$this->_helper->redirector('edit', 'user-details');
}
}
}
The first time Edit action is called the form built and displayed.
User fills the form and sends it (updateUserDetailsAction is called).
In updateUserDetailsAction, on validation failure I mark the form as having errors and want to display the form with error messages that I previously set in updateUserDetailsAction class.
Then I redirect:
$this->_helper->redirector('edit', 'user-details');
in order to display the same form but with errors for the user to re-enter correct values.
The problem is I don't know how to let know the edit action that the form must display validation errors?
On $this->_helper->redirector('edit', 'user-details'); the form is redisplayed
as a new form with cleared erros but I need them displayed.
Do I do this the correct way?
regards
Tom
Problem comes from the fact that you are redirecting and in each method you are creating a new instance of the form, that means the form class is loosing its state - data you injected from the request and any other values passed to this object.
Combine editAction and updateUserDetailsAction into one method:
...
$formUser = new Form();
// populate the form from the model
if ($this->getRequest()->isPost()) {
if ($formUser->isValid($this->getRequest()->getPost())) {
// update the model
}
}
...
and have the form being submitted to the edit action. This will simplify your code and remove code duplication.
If you just wan to fix your code you can instantiate the form object in the init() method of your controller as set it as a property of your controller. This will way you will reuse same instance after redirection. I still think that solution above is much more compact and easier to understand for someone else.

Custom Decorator Label in Zend Framework 2

according to this post: Zend Framework 2 - Form Element Decorators , i've tried the solution from iroybot (thanks to him) and it worked.
but new problem occurs. Here the details:
In the render method in FormCollection.php (View Helper) i throw object like this:
<?php
namespace Cust\View\Helper;
use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\FormCollection as BaseFormCollection;
class FormCollection extends BaseFormCollection
{
public function render(ElementInterface $element)
{
return sprintf('<table class="table table-condensed">%s</table>',parent::render($element));
}
}
and in the render method in FormElement.php (View Helper), i throw :
<?php
namespace Cust\View\Helper;
use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\FormElement as BaseFormElement;
class FormElement extends BaseFormElement
{
public function render(ElementInterface $element)
{
$req = '';
if($element->getOption('required')){
$req = 'required';
}
return sprintf('<tr><td>%s</td><td>%s</td> </tr>',$element->getLabel(),parent::render($element));
}
}
and the form render in the table perfectly. but before table, the label show in the tag label. so the label display twice, first in span tag, and the second in the row of the table...
i don't know how to solve this..
please give me advice..
thanks
bestregards

zend_form decorator on whole form not each individual element

Custom HTML Output on Zend Form Checkbox setLabel Property
In adition to this question.
I want to apply this to all my form_elements without adding it to each individual form_element
class my_form extends Zend_Form
{
public function init()
{
$this->setAction('')
->setMethod('post');
//shouldn't I be able to set the decorator here?
$firstname= new Zend_Form_Element_Text('firstname');
$firstname->setLabel('firstname')
->setRequired(true)
->getDecorator('label')
->setOptions(array('requiredSuffix'=> ' <span class="required">*</span> ', 'escape'=> false))
//here it works but I don't want it on every element.
;
$lastname= new Zend_Form_Element_Text('lastname');
$lastname->setLabel('firstname')
->setRequired(true)
->getDecorator('label')
->setOptions(array('requiredSuffix'=> ' <span class="required">*</span> ', 'escape'=> false))
//here it works but I don't want it on every element.
;
$this->addElements(array($lastname, $firstname));
}
You could make yourself a class that extends the Zend_Form and overload the createElement method :
class My_Base_Form extends Zend_Form
{
public function createElement($type, $name, $options = null)
{
$element = parent::createElement($type, $name, $options);
$element->setOptions(
array('requiredSuffix'=> ' <span class="required">*</span> ')
);
$label = $element->getDecorator('Label');
if (!empty($label)) {
$label->setOption('escape', false);
}
return $element;
}
}
and then you extends that form :
class My_Form extends My_Base_Form
{
public function init()
{
...
// $firstname= new Zend_Form_Element_Text('firstname'); old version
// taking advantage of the createElement
$firstname = $this->createElement('text', 'firstname');
...
}
}
You could use that method for a lot of other things. In the past I've used it to define the default decorators on all my form elements.
You can call setElementDecorators() after addElements() to set decorators for all the elements in the form. See more information in the related Zend Framework documentation.
Hope that helps,

Access views url function in Zend_Form

I have some Forms that for some reasons have to be instantiated in the different modules bootstraps. But in those forms I want to use
$this->setAction($this->getView()->url(array('controller' => 'foo', 'action' => 'bar')));
in the constructor. But since the viewhelper url is not accessible yet since I'm in the bootstrap, is there anyway around this? What I get now is
Fatal error: Uncaught exception 'Zend_Controller_Router_Exception' with message 'Route default is not defined'
on that line. I have NO custom routes so I only use the default router and routes.
If you really need to instantiate the forms so early, then perhaps one possibility is the order of the initializations in your Bootstrap.
In the Bootstrap method where you instantiate your forms, just make sure that you bootstrap the view first. Then grab the view object and pass it to the form during instantiation.
Something like:
protected function _initForms()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$form = new My_Form($view);
// ...
}
Then in your form, you can do something like:
public function __construct($view)
{
$this->setView($view);
}
public function init()
{
// set the action
$this->setAction($this->getView()->url(array(
'controller' => 'foo',
'action' => 'bar',
)));
// create your form elements
// ...
}
Whaddya think?
I decided to change my approach and made the class that manages all the forms accept strings of forms instead of the forms.
static public function registerForm($formClassName, $formName) {
self::$_forms[$formName] = $formClassName;
}
Then I created function to get a form or all forms from the class like so
public function getForm($name) {
if(empty(self::$_forms[$name])) {
throw new Core_Form_Store_Exception;
}
// If the for is instanciated we return it
else if(self::$_forms[$name] instanceof Zend_Form) {
return self::$_forms[$name];
}
else {
// Instanciate the class and return it
$form = new self::$_forms[$name];
self::$_forms[$name] = $form;
return $form;
}
}
getForms() only calls getForm() for each available form. I tired to mimic the interface of the normal Zend_Form a bit when it comes to the names of functions and the order arguments are passed. Now I have it working and as a bonus I don't actually instantiate any form until I need it. And if I only request a specific form from the store class only that form is instantiate and saved for future access.
How about you set the action from the view when rendering the form, eg
<?php echo $this->form->setAction($this->url(array(
'controller' => 'foo',
'action' => 'bar'
))) ?>

Zend Framework: How to pass variables to a custom form element's view helper

So I've created myself a custom form element which has a custom view helper. Now I want to be able to set certain parameters/variables on this form element and be able to access them in my element's view helper. How can I do that?
Here's an example of what I am talking about:
adding the element to the form:
$element = new My_Form_Element_Picker('elementname');
$element->setFoobar('hello');
// or
$form->addElement('Picker', 'elementname', array('foobar' => 'hello'));
form element:
class My_Form_Element_Picker extends Zend_Form_Element_Xhtml
{
public $helper = 'pickerElement';
}
view helper:
class My_View_Helper_PickerElement extends Zend_View_Helper_FormElement
{
public function pickerElement($name, $value = null, $attribs = null)
{
//now I want to check if the 'foobar' option was set, otherwise use a default value
$foobar = 'default';
}
}
There is a fourth optional argument to the view helper that might do the trick for you.
if you define your view helper like this:
public function pickerElement( $name, $value=null, $attribs=null, $options=null ) { }
And then inside your actual form element you define it like this:
class My_Form_Element_Picker extends Zend_Form_Element_Xhtml {
public $helper = 'pickerElement';
public $options = array();
public function setFoobar( $foobar ) {
$this->options['foobar'] = $foobar;
}
}
You will find that the options are passed into the view helper and can be used.
This code is from memory so please forgive any mistakes, this method definitely works for me though.