Zend Framework: Post to different action then return to original action if fails validation AND keep form fields - zend-framework

This might sound like an odd scenario, but I've got two forms on one page. One is just posting back to itself. I made the second post to another action to keep the code cleaner. Maybe not the right choice...
The problem I'm having now is that if that second form doesn't validate, I redirect back to the page with the form but I don't know how to keep my form fields filled in with the original information the user entered. Is there a way to do that and keep posting to two separate actions, or do I need to just bite the bullet and have both forms post back to the same action and deal with the messy logic?

I would submit both forms to the same action. There really shouldn't be anything too messy about it. In each form include a hidden field to signify which form is being submitted.
Application_Form_Login:
/* other form elements */
$this->addElement('hidden', 'login', array(
'value' => 1
));
Application_Form_Register:
/* other form elements */
$this->addElement('hidden', 'register', array(
'value' => 1
));
Controller:
$loginForm = new Application_Form_Login();
$registerForm = new Application_Form_Register();
if($this->_request->isPost()) {
if($this->_request->getPost('login')) {
if($loginForm->isValid($this->_request->getPost())) {
// validated, redirect
$this->_helper->redirector('profile', 'user');
}
}
if($this->_request->getPost('register')) {
if($registerForm->isValid($this->_request->getPost())) {
// validated, proceed as needed
}
}
}
$this->view->loginForm = $loginForm;
$this->view->registerForm = $registerForm;
View:
echo $this->loginForm;
echo $this->registerForm;
With this type of a setup, if either of your forms fail validation, isValid() will preserve any data that has been entered and you still redirect on a successful validation of one or both of the forms.

Personally, I think that each form should post to its own controller, as you have. This keeps the code for processing that form in a single place. The issue here is that you want to return to the original page on failed validation. But why? Why not simply redisplay the form in the target controller, just like you would if there were a single form on the page?
For example, consider a login form that appears on every page of a sie (perhaps because it in the site template/layout). It posts to something like AuthController::loginAction(). If the login fails, then you don't typically send him back to the page from which he came. You leave him at the login page, with the form as pre-filled from the $_POST as you want it to be (probably a username, but not his password).
See this answer for a similar discussion.
Update: Had another thought in this. If you really want to handle the processing in two different controllers in order to keep him on the page from which he posted the form, at least extract that form processing out into an action helper. This way, you could at least keep that form-processing DRY.
Update: Rob Allen has just written a great blog post "A form in your layout" in which he describes a method that uses an action-helper with a preDispatch() method that instantiates and processes the form. Very nice.

How do you redirect? I don't see the problem if you just display the form page again. You can prefill you forms using Zend_Form::populate().

Well, I would just keep both forms submitting on the same page.
I don't see why your code should get any less readable. Learn how to use action helpers and your controllers will suddenly look extremely simple and readable:
public function indexAction()
{
$request = $this->getRequest();
// send forms to view, so we can print them
// but also so we can access them in action helpers
$this->view->form = $this->_getForm('Form1', '/');
$this->view->form2 = $this->_getForm('Form2', '/');
if ($request->isPost())
{
// process the first form
if (isset($_POST['form_submit_button']) && $this->view->form->isValid($_POST))
{
$this->_helper->form($this->view->form->getValues());
}
// process the second form
else if (isset($_POST['form2_submit_button']) && $this->view->form2->isValid($_POST))
{
$this->_helper->form2($this->view->form2->getValues());
}
}
Each form's processing would have its own action helper.

Related

Symfony 2.x Form Field Name

When I render a form, form Filed Name is given as an array. For example: search[item], search[keyword] etc. where search is name of the form.
I'm not great on working with forms but I think, the name should be rendered as simply, name="item" or name="keyword".
I've looked at all the documentation, customizing form rendering topic etc. but I can't find any way to change the default behaviour of Symfony form to render form filed name from 'search[item]' to 'item'.
This way, when I ask for the POST data, I can ask simply $this->getRequest()->request->get('item'), as I have to deal with lots of individual parameters.
Help would be great i) To figure out how to achieve what I want. ii) to let me know, why the name is rendered this way. is this the good practice?
Rather than accessing parameters from the Request object, you can bind the Request object to the form.
For example, in your controller method that you post your form to:
namespace Acme\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\Form\MyFormClass;
class MyFormController extends Controller
{
receiveFormAction(Request $request)
{
$form = new MyFormClass();
// you can specify that a route only accepts a post
// request in the routing definition
if ($request->isMethod('POST')) {
// this populates the form object with the data
// from the form submission
$form->bind($request);
if ( ! $form->isValid()) {
throw new \Exception('Invalid form');
}
// an array of the data the format you require
$data = $form->getData();
$data['item'];
$data['keyword'];
// etc.
}
}
}
The above is the way you should be handling forms in Symfony 2, and is how you can leverage the power that the forms component gives you, with validation etc.
Symfony supports multiple forms on a page. They might be instances of the same form or have similar field names. Having the fields for each form all together in an array makes this easy to do.

Zend Framework - Change order of action output

I have two actions for image albums in my controller, the first creates a form to create a new album and handles the POST and the second generates a list of the existing albums. The form posts to the first action and then puts the list action on the actionstack. This order is necessary as otherwise a newly created album wouldn't appear in the list.
So in my HTML output there is first the output of the createAction-view and then of the listAction-view. But for styling reasons I want to change the order of view output of the two actions in my HTML. Is there a way I can have the list followed by the form without changing the order in which the actions are executed?
You should try and avoid using the action stack if at all possible. You can avoid this requirement completely by simply redirecting to the list view after handling the POST data. This also prevents users accidentally submitting the same album again by refreshing the page. If you still want the form to be displayed under the list, just add the form to that action as well so you can output it in the view under your albumn list.
public function createAction()
{
$form = new Yourapp_Form_Album();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()) {
// save the data and redirect
}
}
$this->view->form = $form;
}
public function listAction()
{
// load albums and assign to the view
// if you want the form under the list
$this->view->form = new Yourapp_Form_Album();
}

Zend creating forms based on requests within one controller/action

I don't really know how to word the title well, but here's my issue. I decided instead of having 25 controllers to handle pages, I have one PageController with a viewAction that takes in a :page parameter - for example, http://localhost/website/page/about-us would direct to PageController::viewAction() with a parameter of page = about-us. All of the pages are stored in a templates folder, so the viewrenderer is set to render application\templates\default\about-us.phtml.
I did this so I can consolidate and it seemed like a better approach. My question is the following: lets say when the page request is contact-us, I would need a Zend_Form to be used within the contact page. So, I would need a way within PageController::viewAction() to recognize that the page needs to have a form built, build the form, and also upon submission the need to process it (maybe this should be handled in an abstract process method - not sure).
I have no idea how to implement this. I thought maybe I can store a column with the name of a form and a connecting page identifier. Even better, create a one-to-many page to forms, and then in the submission loop through the forms and check if submitted and if so then process it (maybe there is a isSubmitted() method within zend_form. I really don't know how to handle this, and am looking for any help i can get.
Thanks!
Here is something that came to mind that may work or help point you in a direction that works for you.
This may only work well assuming you were to have no more than one form per page, if you need more than one form on a page, you would have to do something beyond this automatic form handling.
Create a standard location for forms that are attached to pages (e.g. application/forms/page). This is where the automatic forms associated with pages will be kept.
In your viewAction, you could take advantage of the autoloader to see if a form for that page exists. For example:
$page = $this->getParam('page');
$page = ucfirst(preg_replace('/-(\w)/ie', "strtoupper('$1')", $page)); // contact-us -> ContactUs
$class = 'Application_Form_Page_' . $page;
// class_exists will invoke the autoloader to map a class to a file
if (class_exists($class)) {
// a form is defined for this page
$form = new $class();
// check if form was posted
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()) {
// form is valid - determine how to process it
}
}
// assign the form to the view
$this->view->pageForm = $form;
}
All this really leaves out is the action you take to process a specific form. Since the contact form will likely generate an email, and another form may insert data into a database, you will need some sort of callback system or perhaps another class that can be mapped automatically which contains the form processor code.
Anyway something along those lines is what came to mind first, I hope that helps give you some more ideas.

No validations errors to display in symfony 1.4 form

I have a problem with all my forms in symfony 1.4. They work with good datas, my new objects are created ... But when i give bad datas, my forms do nothing as expected but have no errors.
My code in my action :
$this->form = new EtablissementForm();
$this->form->bind(
$request->getParameter($this->form->getName()),
$request->getFiles($this->form->getName())
);
Edit :
Solved. I guess i need some sleep. This was really a dumb mistake. I was sure i had removed a new E...Form(); In my view for my action, actually i did it ... in another file.
So my $form was overwritten by an empty form. So the problem is solved.
if ($this->form->isValid())
{
//some things and a redirect
}
In a nutshell, my form works with good datas. But i don't have any errors to display when i'm giving bad datas. And my form don't add something in my database. Validations works cause it raise exception in bind, but i just get an empty form to display.
Your view needs to have proper scope to $form. Your code above may be incomplete. In the action you show above, if the action ends, and you go to your view, and your view has the following, your validation errors should appear inline with your form.
<?php echo $form ?>

passing values from model to view in CI

I have this library in CI that retrieves my latest twitter updates. It has a function that sends my latest updates as objects to my controller.
I would like to show these twitter updates on the footer of my page, so they're visible at all times.
Now my question is how I call these directly from a view? I know this is not a good practice in MVC but I don't see how else I could do this.
My controller currently takes care of all my different pages (it's a small website) and I don't think it's very good practice to call my twitter class at the end of every page-function in the controller and then send it through to the views.
Typycally I do this in my controller:
<?php
function index(){
$data['page'] = 'home';
//i don't want to call my twitter class here every single time I write a new page. (DRY?!)
$this->load->view('template', $data);
}
?>
And it loads the "template" view that looks like this:
<?php
$this->load->view('header');
$this->load->view('pages/'.$page);
$this->load->view('footer');
?>
So any suggestions how I should do this?
I have a helper library that takes a page Partial and wraps it in the master theme. You can use the optional parameter on your load->view to render to a string.
Then when you render your master page, you can load the twitter updates, and display them. Although, I highly suggest caching your twitter response for 5 minutes at least, will save you a LOT of overhead.
Example:
// Controller somwhere:
$content = $this->load->view('pages/'.$page, array(), true);
$this->myLibrary->masterPage($content);
// Your library:
function masterPage($content)
{
$twitterData = $this->twitter->loadStuff(); // whatever your function is
$twitter = $this->load->view('twitter_bar', array('data' => $twitterData), true);
$this->load->view('master', array('content' => $content, 'twitter' => $twitter);
}
An alternative approach is to use a base controller. All my controllers extend my custom base controller which holds things I need on every page, for example an object containing the current user.