<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
Zend_Controller_Action_Helper_MultiPageForm provides support for multi-page forms and Post-Redirect-Get with Zend_Form. This proposal heavily based on Simon Mundy's Multiform action helper. Credit to this idea should go to Simon. I merely made it play nice with Zend_Form Zend Framework: Zend_Controller_Action_Helper_MultiPageForm Component Proposal
Proposed Component Name
Zend_Controller_Action_Helper_MultiPageForm
Developer Notes
http://framework.zend.com/wiki/display/ZFDEV/Zend_Controller_Action_Helper_MultiPageForm
Proposers
Jurriën Stutterheim
Matthew Weier O'Phinney (Zend Liaison)
Revision
0.1 - 1 January 2008: Initial revision. (wiki revision: 6)
Table of Contents
1. Overview
2. References
3. Component Requirements, Constraints, and Acceptance Criteria
4. Dependencies on Other Framework Components
- Zend_Exception
- Zend_Session
- Zend_Controller_Action_Helper_Abstract
5. Theory of Operation
The helper makes use of Zend_Form's subform support to provide multi-page forms. Each subform is essentially a form page.
At the end of the ride all the filtered/validated data is collected and made available to the developer to process it.
A session is used to store the data between requests.
Each subform needs a corresponding controller action. The subform and action have the same name.
The action serves two purposes. It allows custom logic for the data handling and it renders the view.
There is some more functionality that could be added to the helper, but I would like to discuss the options of that first.
One of those possibilities could be the branches idea of Mitchell's form proposal.
Another is the ability to allow unique instances of the same form to be open and filled in simultaneously. However, this would heavily increase the helper's complexity. This probably would be an option for a second iteration.
6. Milestones / Tasks
- Milestone 1: [DONE] Rewrite Simon's helper to specialize it for Zend_Form
- Milestone 2: Discuss points mentioned above.
- Milestone 3: Update proposal to reflect comments and results of discussions.
- Milestone 4: Helper checked in to incubator.
- Milestone 5: Documentation & unit test.
- Milestone 6: Helper accepted into core.
7. Class Index
- Zend_Controller_Action_Helper_MultiPageForm
8. Use Cases
| UC-01: Basic usage |
|---|
10 Comments
comments.show.hideMay 07, 2008
Simon Mundy
<p>One thing that's got me puzzled is how you would use subgroups within each form, rather than one subgroup-per-action. For example, I may have one page with a group of checkboxes that are contained within one subgroup (by necessity - the display group does something else with them...) - how then do I represent this?</p>
<p>The original thinking for the Multiform helper was to provide less dependance on a particular component and try to design more for an interface. Granted, it was before Zend_Form was mature, so the method names were more closely matched to PEAR's HTML_Form. But it allowed a lot more flexibility in implementation.</p>
<p>If it helps by example, here is a current multipage form implementation I'm using together with Zend_Form and my own multipage form helper. It's for an accommodation booking system:-</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[<?php
class Booking_AddController extends Zend_Controller_Action
{
public function init()
public function indexAction()
public function personalAction()
{
$multiform = $this->_helper->multiform;
// Implemented the SPL observer interface to my form instances - it triggers update()
// when a successful form update
$form = new App_Form_BookingPersonal();
$form->attach(new App_Registrar_BookingPersonal($this));
$form->populate($multiform->getActionValues());
if ($this->getRequest()->isPost())
$this->view->form = $form;
}
public function accommodationAction()
{
$multiform = $this->_helper->multiform;
// Implemented the SPL observer interface to my form instances - it triggers update()
// when a successful form update
$form = new App_Form_BookingAccommodation();
$form->attach(new App_Registrar_BookingAccommodation($this));
$form->populate($multiform->getActionValues());
if ($this->getRequest()->isPost())
$this->view->form = $form;
}
public function reviewAction()
{
$multiform = $this->_helper->multiform;
// Implemented the SPL observer interface to my form instances - it triggers update()
// when a successful form update
$form = new App_Form_BookingReview();
$form->attach(new App_Registrar_BookingReview($this));
$form->populate($multiform->getActionValues());
if ($this->getRequest()->isPost())
$this->view->form = $form;
}
public function submitAction()
public function cancelAction()
public function thankyouAction()
}]]></ac:plain-text-body></ac:macro>
<p>I believe this strategy works well - it only ever performs validation if $_POST data exists, and is smart enough to know if the 'back' or 'cancel' actions are triggered then it should save the form data but ignore the validation errors.</p>
<p>Ultimately, it prevents the action helper from being <em>too</em> helpful - as a developer you are free to code your actions precisely the way you need to and arrange the 'update' method as you see fit. Unless I'm mistaken it looks like the proposal here performs its checking during the preDispatch loop?</p>
<p>ANyway, that's my 2c for now - look forward to seeing how this progresses.</p>
May 21, 2008
Benjamin Jeanjean
<p>Can we have your action helper code ?</p>
Jun 02, 2008
Matthew Weier O'Phinney
<ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Comments</ac:parameter><ac:rich-text-body>
<p>The Zend Framework team approves this proposal for immediate development in the<br />
standard incubator, with the following suggestions:</p>
<ul>
<li><strong>Allow custom mappings.</strong> Currently, the proposal states that each sub form should map to an action of the same name. It would be more flexible to allow explicit mappings - which would allow the developer to handle all sub forms in a single action, or to provide custom URL schemas.</li>
<li><strong>Provide an AJAX use case,</strong> if feasible. One potential use case for multi-page forms is to use AJAX to submit one page, and then return the next form as the XHR response if valid. A use case showing this in the manual would be a nice addition, though not necessary.</li>
</ul>
</ac:rich-text-body></ac:macro>
Mar 18, 2009
Wil Sinclair
<p>This proposal has not been updated in the past 6 months. Archiving for now.</p>
Mar 18, 2009
Jurrien Stutterheim
<p>The component itself has been approved for the standard incubator, where it has been sitting for quite a while now. Wouldn't it make more sense to keep this in the standard incubator wiki section?</p>
Apr 01, 2009
Colin Guthrie
<p>I like the idea of this helper.</p>
<p>My own comments relate to how it handles PRG in a multiform scenario.</p>
<p>I would like to suggest that the helper allows you to supply a naming convention to permit a PRG.</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
$multiform->setActions(
array(
'first',
'second',
'third',
)
);
$multiform->setPRGActionSuffix('-do');
]]></ac:plain-text-body></ac:macro>
<p>This way you could have the action methods: firstAction(), secondAction() thirdAction() etc. which would display the forms as normal, and firstDoAction(), etc. which would (in a PRG scenario) <strong>always</strong> redirect after it has processed the form.</p>
<p>By adopting this technique, the back button would never break, even after a multiple failure on a single stage. firstDoAction() would redirect to either firstAction() on failure or secondAction() on success.</p>
<p>An alternative to a setPRGActionSuffix() method would be to make setActions() accept an associative array where the keys are the GET actions and the values are the POST actions.</p>
Oct 02, 2009
Marcus Stöhr
<p>I recently trying to get this running and found a small bug in the latest Incubator version:</p>
<p>Was:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
if (!$this->_activeFormName) {
$formName = $this->getRequest()
>getParams($this>_formRoutePart);]]></ac:plain-text-body></ac:macro>
<p>Fixed:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
if (!$this->_activeFormName) {
$formName = $this->getRequest()
>getParams($this>_formNameRoutePart);]]></ac:plain-text-body></ac:macro>
<p>However, I'm not getting this running. After setting up my form using the basic usecase, I get the following warning:</p>
<p>Additionally, I'm unable to set the action for the form, thus it is empty in the resulting code.</p>
Nov 08, 2009
Sébastien Cramatte
<p>It seems that in the latest Incubator still persists this bug :</p>
<p>Bugged</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
if (!$this->_activeFormName) {
$formName = $this->getRequest()
>getParams($this>_formNameRoutePart);]]></ac:plain-text-body></ac:macro>
<p>Fixed </p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
if (!$this->_activeFormName) {
$formName = $this->getRequest()
>getParam($this>_formNameRoutePart);]]></ac:plain-text-body></ac:macro>
Nov 08, 2009
Sébastien Cramatte
<p>Fixing the small tipo bug above I've been able to run the order form.</p>
<p>What occurs is that I don't know how to show multiform navigation. <br />
Does it exits a view helper ? Do I must create buttons in each subform ?</p>
<p>Posting a complete working example would be nice.</p>
<p>Thank you</p>
Nov 17, 2009
Sasa Stamenkovic
<p>Isn't it bad/slow to initialize all subforms on each action?</p>