How to create multiple form submit buttons with alternate routes in ZF2 - forms

In ZF2, how do you create multiple submit buttons that each lead to different routes? In the Forms and actions chaper of the ZF2 tutorial, a form is created with a single submit button with the label “Go” that processes the input data and returns to the index page (route). Where do we put the pertinent scripts if we wanted four buttons:
Save action: saves user input, route: return to current page
Save and Close action: saves user input, route: return to index (Album)
Clear action: no action, route: return to current page
Close action: no action, route: return to index (Album)
I assume the buttons are created like this:
namespace Album\Form;
class AlbumForm extends Form
{
public function __construct($name = null)
{
// ... //
$this->add(array(
'name' => 'savebutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Save',
'id' => 'savebutton',
),
));
$this->add(array(
'name' => 'save_closebutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Save & Close',
'id' => 'save_closebutton',
),
));
$this->add(array(
'name' => 'clearbutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Clear',
'id' => 'clearbutton',
),
));
$this->add(array(
'name' => 'closebutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Close',
'id' => 'closebutton',
),
));
}
}
This is what the edit action looks like with only one submit button:
// module/Album/src/Album/Controller/AlbumController.php:
//...
// Add content to this method:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album', array(
'action' => 'add'
));
}
$album = $this->getAlbumTable()->getAlbum($id);
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getAlbumTable()->saveAlbum($form->getData());
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
//...
Since pairs of buttons have the same form action and pairs of buttons have the same route, I image we want to add two if statements somewhere here, unless a switch statement is better.

Quick 'n dirty way to do what you need:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album', array(
'action' => 'add'
));
}
$album = $this->getAlbumTable()->getAlbum($id);
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$input = $form->getData();
if (!empty($input['save_closebutton'])) {
return $this->redirect()->toRoute('album', array(
'controller' => 'AlbumController',
'action' => 'index',
));
}
}
}
return array(
'id' => $id,
'form' => $form,
);
}

Related

Magento 1.9 sending custom form - form data not found in controller

I am having trouble with a simple form. I am quite sure that I miss some critical info about this topic...
I created a custom module, I created a custom form
<?php
class modulename_History_Block_Adminhtml_History_Edit_Form extends Mage_Adminhtml_Block_Widget_Form {
protected function _prepareForm()
{
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'name' => 'edit_form',
'action' => $this->getUrl('*/*/history', array('id' => 'orders_export')),
'method' => 'post',
'enctype' => 'multipart/form-data',
'data' =>'somethingsomethingdarkaside'
));
$this->setForm($form);
$fieldset = $form->addFieldset('Filtrování objednávek', array('legend'=> 'Nastavte filtr pro report objednávek'));
$dateTimeFormatIso = Mage::app()->getLocale()->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT);
$fieldset->addField('date_from', 'date', array(
'label' => 'Změna statusu objednávek od:',
'title' => 'Změna statusu objednávek od:',
'time' => true,
'name' => 'filter_date_from',
'image' => $this->getSkinUrl('images/grid-cal.gif'),
'format' => $dateTimeFormatIso,
'required' => true,
));
$fieldset->addField('export_history_order_status_changed', 'button', array(
'label' => 'Exportovat do souboru:',
'value' => 'Export',
'name' => 'export_history_order_status_changed',
'class' => 'form-button',
'onclick' => "setLocation('{$this->getUrl('*/*/export')}')",
));
$form->setUseContainer(true);
return parent::_prepareForm();
}
And then there is a controller. When the button is pressed, it goes to the correct controller to a correct action. However no data in post received:
<?php
class modulename_History_Adminhtml_History_HistoryController extends Mage_Adminhtml_Controller_Action {
protected function _initAction()
{
return $this;
}
/**
* A page with the form, creating the block with it.
*
*/
public function editAction()
{
$this->_title('Historie objednavky')
->loadLayout()
->_setActiveMenu('modulename/historymenu');
$this->_addContent($this->getLayout()->createBlock('modulename_history/adminhtml_history_edit'));
$this->renderLayout();
}
/**
* A main entrance - when the filter is set and the "export" button pressed then this is the function which starts.
*
* #return bool|Mage_Core_Controller_Varien_Action - either we return a downloadable file or we return false.
*/
public function exportAction()
{
if ($this->_setParameters())
{
if ($this->_setOrdersIds())
{
return $this->_getDownloadFile();
}
}
return false;
}
/**
* Try to get parameters from the admin form. If all correct then we return true. If there is something not set
* then we are unable to continue and we return false.
*
* #return bool - either we were successful with getting the parameters or not.
*/
protected function _setParameters()
{
$parameters = $this->getRequest()->getParams();
$pokus = $this->getRequest()->getPost();
$necf = $this->getRequest()->getPost('edit_form');
$neco = Mage::app()->getRequest()->getParam('edit_form');
}
}
Hellou,
so a competent colleque find an answer within minutes. I mean it was as silly as expected, just remove on click action on button and set the heading from the button to the form. And changed the button to submit. I quess the guy I copied the code from used some other spells of high magic so it worked for him. I hope this will help. Correct form below:
<?php
class modulename_History_Block_Adminhtml_History_Edit_Form extends
Mage_Adminhtml_Block_Widget_Form {
protected function _prepareForm()
{
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'name' => 'edit_form',
//'action' => $this->getUrl('*/*/history', array('id' => 'orders_export')),
'action' => $this->getUrl('*/*/export', array('id' => 'orders_export')),
'method' => 'post',
'enctype' => 'multipart/form-data',
'data' =>'somethingsomethingdarkaside'
));
$this->setForm($form);
$fieldset = $form->addFieldset('Filtrování objednávek', array('legend'=> 'Nastavte filtr pro report objednávek'));
$dateTimeFormatIso = Mage::app()->getLocale()->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT);
$fieldset->addField('date_from', 'date', array(
'label' => 'Změna statusu objednávek od:',
'title' => 'Změna statusu objednávek od:',
'time' => true,
'name' => 'filter_date_from',
'image' => $this->getSkinUrl('images/grid-cal.gif'),
'format' => $dateTimeFormatIso,
'required' => true,
));
$fieldset->addField('export_history_order_status_changed', 'submit', array(
'label' => 'Exportovat do souboru:',
'value' => 'Export',
'name' => 'export_history_order_status_changed',
'class' => 'form-button',
//'onclick' => "setLocation('{$this->getUrl('*/*/export')}')",
));
$form->setUseContainer(true);
return parent::_prepareForm();
}

Translate zend framework 1 form labels and error message

I have a web site which is in English and Arabic. I converted the text into Arabic but the form labels and error message is not converting. I am using gettext adapter and how do i convert this labels. I am using Zend_Form and creating object of this form and passign this to view.
Bootstrap file
protected function _initTranslate() {
$translate = new Zend_Translate('gettext', APPLICATION_PATH . "/lang/", null, array('scan' => Zend_Translate::LOCALE_DIRECTORY));
$registry = Zend_Registry::getInstance();
$registry->set('Zend_Translate', $translate);
//Zend_Form::setDefaultTranslator($translate);
$translate->setLocale('ar');
}
public function _initRoutes() {
$this->bootstrap('FrontController');
$this->_frontController = $this->getResource('FrontController');
$router = $this->_frontController->getRouter();
$langRoute = new Zend_Controller_Router_Route(
':lang', array(
'lang' => 'ar',
'module' => 'default',
'controller' => 'index',
'action' => 'index'
), array(
'lang' => 'en|ar'
)
);
$defaultRoute = new Zend_Controller_Router_Route(
':controller/:action', array(
'module' => 'default',
'controller' => 'index',
'action' => 'index'
)
);
$defaultRoute = $langRoute->chain($defaultRoute);
$router->addRoute('langRoute', $langRoute);
$router->addRoute('defaultRoute', $defaultRoute);
}
protected function _initLanguage() {
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new My_Controller_Plugin_Language());
}
Form
class Application_Form_Contactus extends Zend_Form {
public function init() {
// Set the method for the display form to POST
$this->setMethod('post');
$this->addElement('text', 'name', array('label' => 'Name', 'class' => 'inputbox',
'filters' => array('StringTrim'),
'required' => true));
// Add an email element
$this->addElement('text', 'email', array('label' => 'Email', 'class' => 'inputbox',
'required' => true, 'filters' => array('StringTrim'), 'validators' => array('EmailAddress')));
$this->addElement('submit', 'submit', array(
'required' => false,
'label' => 'Send',
'value' => 'save',
'class' => 'submit-but',
'attribs' => array('type' => 'submit'),
));
}
}
Controller
$form = new Application_Form_Contactus();
$form->setAction($this->view->getSiteUrl() . 'Contactus');
$translate = Zend_Registry::get('Zend_Translate');
$form->element->setTranslator($translate);
$this->view->form = $form;
view
echo $this->form;
Try to attach to the Zend_Form object as a global translator. This will also translate validation error messages :
Zend_Form::setDefaultTranslator($translate);
Or you can do this :
Zend_Validate_Abstract::setDefaultTranslator($translator);
Please see zend form i18n
Try to set default translator.
Zend_Form::setDefaultTranslator($translate);
One more alternate way could be:
$form = new Application_Form_Contactus();
$translate = Zend_Registry::get('Zend_Translate');
foreach ($form->getElements() as $key => $element) {
$element->setTranslator($translate);
}

Basic Zend post workflow issue

I am new to this these technologies, so might not be asking to do this the easiest way, but: I want to create a form and ask for an ID value. Once submit is pressed, I want to take that ID, make an external XML call and then show the XML data. I am stuck on if I can do this in a single url:https://plesk.local:8443/modules/example/index.php/index/form. I would like to have both the form and the list data on the same page, so I can update the ID, press submit and see the new data...over and over...
I am trying to modify the basic "Example1" that Plesk includes. I can modify it and test it, but stuck on exactly how POST works. Ideally I want to have $this->view->form to have both a pm_Form_Simple and pm_View_List_Simple on the same $form view (if this makes sense).
So looking for help on
1) Can I use the same URL and handle the POST/GET from it
2) Can I have both a form and simple list on the same page?
thx!!!!!
Here is the sample controller:
<?php
class IndexController extends pm_Controller_Action
{
public function init()
{
parent::init();
// Init title for all actions
$this->view->pageTitle = 'Example Module';
// Init tabs for all actions
$this->view->tabs = array(
array(
'title' => 'Form',
'action' => 'form',
),
array(
'title' => 'List',
'action' => 'list',
),
);
}
public function indexAction()
{
// Default action will be formAction
$this->_forward('form');
}
public function formAction()
{
// Init form here
$form = new pm_Form_Simple();
$form->addElement('text', 'exampleText', array(
'label' => 'Example Text',
'value' => pm_Settings::get('exampleText'),
'required' => true,
'validators' => array(
array('NotEmpty', true),
),
));
$form->addControlButtons(array(
'cancelLink' => pm_Context::getModulesListUrl(),
));
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getPost())) {
// Form proccessing here
pm_Settings::set('exampleText', $form->getValue('exampleText'));
$this->_status->addMessage('info', 'Data was successfully saved.');
$this->_helper->json(array('redirect' => pm_Context::getBaseUrl()));
}
# NEW - start
if (0)
{
# I want to be back here after the POST
# Want to show the list here after I take the POST parameter and do an external XML call...
$list = $this->_getListRandom();
$this->view->list = $list;
}
# NEW - end
$this->view->form = $form;
}
public function listAction()
{
$list = $this->_getListRandom();
// List object for pm_View_Helper_RenderList
$this->view->list = $list;
}
public function listDataAction()
{
$list = $this->_getListRandom();
// Json data from pm_View_List_Simple
$this->_helper->json($list->fetchData());
}
private function _getListRandom()
{
$data = array();
#$iconPath = pm_Context::getBaseUrl() . 'images/icon_16.gif';
for ($i = 0; $i < 15; $i++) {
$data[] = array(
'column-1' => '' . (string)rand() . '',
'column-2' => (string)rand(),
);
}
$list = new pm_View_List_Simple($this->view, $this->_request);
$list->setData($data);
$list->setColumns(array(
'column-1' => array(
'title' => 'Random with link',
'noEscape' => true,
),
'column-2' => array(
'title' => 'Random with image',
'noEscape' => true,
),
));
// Take into account listDataAction corresponds to the URL /list-data/
$list->setDataUrl(array('action' => 'list-data'));
return $list;
}
}
Yes
Yes
I'm not expirienced in zend, so it just try, I suggest to replace formAction() with following code:
public function formAction()
{
// Init form here
$form = new pm_Form_Simple();
$form->addElement('text', 'exampleText', array(
'label' => 'Example Text',
'value' => pm_Settings::get('exampleText'),
'required' => true,
'validators' => array(
array('NotEmpty', true),
),
));
$form->addControlButtons(array(
'cancelLink' => pm_Context::getModulesListUrl(),
));
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getPost())) {
// Form proccessing here
pm_Settings::set('exampleText', $form->getValue('exampleText'));
$this->_status->addMessage('info', 'Data was successfully saved.');
$list = $this->_getListRandom();
$this->view->list = $list;
$this->view->form = $form;
// Redirects happens on next string, maybe you need to add something to getBaseUrl()
$this->_helper->json(array('redirect' => pm_Context::getBaseUrl()));
}
$this->view->form = $form;
}

$form->isValid says it is invalid, but my form does not show any error message - Zend Framework 2

Im having a problem with the addAction in my CRUD application. On the controller the logic does not pass the $form->isValid() verification but the form does not show any error message.
I tried with this (Thanks Sam):
foreach($form->get('product')->getElements() as $el)
{
echo $el->getName()." = ".$el->getValue()." > ".$el->getMessages()." <br/>";
}
That only show the name and value of the field, but not the error message.
I've tried letting the form totally blank and it fire "Value is required and can't be empty" error messages, but then, i fill each field one by one until i don't get more error messages but the form still invalid.
My form has a Product Fieldset as a base fieldset and a submit button. Inside Product Fieldset i have an ID field, a name field, a price field and a Brand Fieldset. Inside my Brand Fieldset i have a id field. Like this:
ProductForm:
class ProductForm extends Form
{
public function init()
{
// we want to ignore the name passed
parent::__construct('product');
$this->setName('product');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'product',
'type' => 'Administrador\Form\ProductFieldset',
'options' => array(
'use_as_base_fieldset' => true
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Add',
'id' => 'submitbutton',
),
));
}
}
ProductFieldset:
class ProductFieldset extends Fieldset implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
function __construct($name = null)
{
parent::__construct('product_fieldset');
$this->setHydrator(new ArraySerializableHydrator());
$this->setObject(new Product());
}
public function init()
{
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'name',
'type' => 'Text',
'options' => array(
'label' => 'Name',
),
));
$this->add(array(
'name' => 'price',
'type' => 'Text',
'options' => array(
'label' => 'Price',
),
));
$this->add(array(
'name' => 'brand',
'type' => 'BrandFieldset',
));
}
public function setServiceLocator(ServiceLocatorInterface $sl)
{
$this->serviceLocator = $sl;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
BrandFieldset:
class BrandFieldset extends Fieldset
{
function __construct(BrandTable $brandTable)
{
parent::__construct('brand_fieldset');
//$this->setHydrator(new ClassMethodsHydrator(false))->setObject(new Brand());
$this->setHydrator(new ArraySerializableHydrator());
$this->setObject(new Brand());
$brandSelectOptionsArray = $brandTable->populateSelectBrand();
$this->add(array(
'name' => 'id',
'type' => 'Select',
'options' => array(
'label' => 'Brand',
'empty_option' => 'Please select a brand',
'value_options' => $brandSelectOptionsArray,
),
));
}
}
This is my new Form statement in the addAction:
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
Inside my model 'Product' i have the inputFilters, required filter for 'id' field, required filter for 'name' field. And for the Brand field i created other inputFilter and added it to the main inputFilter:
$brandFilter->add($factory->createInput(array(
'name' => 'id',
'required' => true,
'filters' => array(
array('name' => 'Int'),
),
)));
$inputFilter->add($brandFilter, 'brand');
The weird behavior is that my editAction works fine and has the same logic.
Is it there any form of echoing an internal error message from the form, something that helps me to understand WHY the form is not valid.
EDIT 2013-06-01
Here is my full Controller:
class ProductController extends AbstractActionController
{
protected $productTable;
protected $brandTable;
public function indexAction()
{
return new ViewModel(array(
'products' => $this->getProductTable()->fetchAll(),
));
}
public function addAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$product = new Product();
$product->brand = new Brand();
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$product->exchangeArray($form->getData());
$this->getProductTable()->saveProduct($product);
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return new ViewModel(array(
'form' => $form,
));
}
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('product', array(
'action' => 'add'
));
}
// Get the Product with the specified id. An exception is thrown
// if it cannot be found, in which case go to the index page.
try {
$product = $this->getProductTable()->getProduct($id);
}
catch (\Exception $ex) {
return $this->redirect()->toRoute('product', array(
'action' => 'index'
));
}
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$brand = $this->getBrandTable()->getBrand($product->brand);
$product->brand = $brand;
$form->bind($product);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getProductTable()->saveProduct($form->getData());
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
public function deleteAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('product');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->getPost('del', 'No');
if ($del == 'Yes') {
$id = (int) $request->getPost('id');
$this->getProductTable()->deleteProduct($id);
}
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
return array(
'id' => $id,
'product' => $this->getProductTable()->getProduct($id)
);
}
public function getProductTable()
{
if (!$this->productTable) {
$sm = $this->getServiceLocator();
$this->productTable = $sm->get('Administrador\Model\ProductTable');
}
return $this->productTable;
}
public function getBrandTable()
{
if (!$this->brandTable) {
$sm = $this->getServiceLocator();
$this->brandTable = $sm->get('Administrador\Model\BrandTable');
}
return $this->brandTable;
}
}
My case was I passed wrong input filter. isValid returns false, but $form->getMessages() is empty. Form OrderForm had the following:
$form->setInputFilter(new \Application\Form\UserInputFilter($er));
When I changed UserInputFilter to OrderInputFilter it works.
Well, I got the answer :D
This is how the addAction should be:
public function addAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$form->get('submit')->setValue('Add');
$product = new Product();
$product->brand = new Brand();
$form->bind($product); // I need to bind the product to the form to pass the isValid() validation
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$product = $form->getData();
$this->getProductTable()->saveProduct($product);
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return new ViewModel(array(
'form' => $form,
));
}
Apparently i needed to bind and empty product object to the form to be able to pass the isValid() validation. After that i retrieve a product object from the $form->getData().
You can also do: $form->setBindOnValidate(false);

Zend Framework: My form wont render

So I have created a form below with Zend Framework which I'm then going to customise. My first issue is that with the csrf hash security I get an application error. However, when I remove them lines all I get is a blanks screen which is only resolved when I remove the CPATCHA protection. Can anyone explain to me why?
My Form:
class Application_Form_Clips extends Zend_Form
{
public function init()
{
// Set the method for the display form to POST
$this->setMethod('post');
// Add an email element
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
// Add the comment element
$this->addElement('textarea', 'comment', array(
'label' => 'Please Comment:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add a captcha
$this->addElement('captcha', 'captcha', array(
'label' => 'Please enter the 5 letters displayed below:',
'required' => true,
'captcha' => array(
'captcha' => 'Figlet',
'wordLen' => 5,
'timeout' => 300
)
));
// Add the submit button
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Sign Guestbook',
));
// And finally add some CSRF protection
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
}
My Controller:
class AdminController extends Zend_Controller_Action
{
public function init()
{
// get doctrine and the entity manager
$this->doctrine = Zend_Registry::get('doctrine');
$this->entityManager = $this->doctrine->getEntityManager();
// get the users repository
$this->indexVideos = $this->entityManager->getRepository('\ZC\Entity\Videos');
$this->indexClips = $this->entityManager->getRepository('\ZC\Entity\Clips');
}
public function indexAction()
{
// action body
}
public function clipsAction()
{
// get a form
$form = new Application_Form_Clips();
$this->view->form = $form;
}
public function videosAction()
{
// action body
}
}
My View:
<?php echo $this->form; ?>
Basic error, I hadn't uncommented session.pat in my php.ini