UPDATE: Solved Checking to see if the current request was a post wasn't enough. The forms were still passed to the helper in order of creation. If the first form passed to the helper wasn't the posted form, there wasn't enough validation to prevent its details from being used instead of the expected posted form.
Added if
additional clause in helper...
if ($postId)
should have been
if ($postId === $formId)
Pretty straight forward really... only took me 2 days to find the answer.
--- Original Post Below ---
I have tried to implement my own PRG (Post/Redirect/Get) pattern in ZF1.
I use a custom form class that extends Zend_Form
to add a setUniqueFormId
method which is basically a hidden element with the form name. The forms are passed to the action helper along with 2 variables ($persistData
and $redirectUrl
).
The problem is that the when I have multiple forms, the first the values passed from the last call to the helper are used.$persistData
and $redirectUrl
values are always used for any subsequent forms even though these have been changed.
Any thoughts on why this would be the case? Any help much appreciated.
Update: I think this is an issue with using an action helper. Each time it is called and new values are passed, all previous values are changed. I'm not that familiar with the internals of the action helper broker. Can anyone shed any light or make a suggestion?
--- Controller Action ---
// Create 2 new forms
$testForm1 = new Application_Form_Test;
$testForm2 = new Application_Form_Test;
// Call a custom function on each form tp create a hidden field called
// "unique_form_id" to help identify the form that has posted the data
$testForm1->setUniqueFormId('test_form_1');
$testForm2->setUniqueFormId('test_form_2');
// Call "Post Redirect Get" Helper and pass a boolean variable for $persistData
$formData1 = $this->_helper->postRedirectGet($testForm1, true);
$formData2 = $this->_helper->postRedirectGet($testForm2, false);
--- Controller Action Helper ---
public function direct($form, $persistData = false, $redirectUrl = null)
{
$formId = $form->getElement('unique_form_id')->getValue();
$currentUrl = implode (
'/',
array (
$this->getRequest()->getModuleName(),
$this->getRequest()->getControllerName(),
$this->getRequest()->getActionName()
)
);
$session = new Zend_Session_Namespace('prg');
$redirectUrl = $redirectUrl ? $redirectUrl : $currentUrl;
if ($this->getRequest()->isPost())
{
$postId = $this->getRequest()->getPost('unique_form_id');
if ($postId)
{
$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector');
$postUrl = $currentUrl;
$session->$postUrl->$postId = array (
'url' => (string) $redirectUrl,
'id' => (string) $postId,
'post' => (array) $this->getRequest()->getPost(),
'persist' => (bool) $persistData
);
Zend_Session::writeClose(true);
$response = $redirector ->setCode(303)
->setExit(true)
->gotoUrl($redirectUrl);
return $response;
}
else {
return false;
}
}
else {
$urlSessionData = $session->$currentUrl;
// Results shown below
Zend_Debug::dump($urlSessionData);
if ($urlSessionData->$formId != null)
{
$formSessionData = $urlSessionData->$formId;
$formPersist = $formSessionData['persist'];
$formPostData = $formSessionData['post'];
if (!$formPersist)
{
unset($urlSessionData->$formId);
}
if(!empty($formPostData))
{
$form->isValid($formPostData);
}
return $formPostData;
}
else {
return false;
}
}
}
--- Front Controller Plugin ---
function preDispatch()
{
$session = new Zend_Session_Namespace('prg');
$currentUrl = implode (
'/',
array (
$this->getRequest()->getModuleName(),
$this->getRequest()->getControllerName(),
$this->getRequest()->getActionName()
)
);
// Check if current url is in prg sesison
// If not, we have moved to another URL or its our first visit to the $currentUrl
if ($session->$currentUrl === null)
{
// Remove all prg sessions
Zend_Session::namespaceUnset('prg');
}
return;
}
--- Dump Result ---
object(stdClass)#54 (2)
{
["test_form_1"] => array(4)
{
["url"] => string(21) "admin/timeclock/index"
["id"] => string(11) "test_form_1"
["post"] => array(4)
{
["test_element"] => string(0) ""
["submit"] => string(5) "Submit"
["unique_form_id"] => string(11) "test_form_1"
}
["persist"] => bool(false) <-- Expected to be 'true'
}
["test_form_2"] => array(4)
{
["url"] => string(21) "admin/timeclock/index"
["id"] => string(11) "test_form_2"
["post"] => array(4)
{
["test_element"] => string(0) ""
["submit"] => string(5) "Submit"
["unique_form_id"] => string(11) "test_form_2"
}
["persist"] => bool(false) <-- Expected to be 'false'
}
}
I (stupidly) didn't check if the form passed to the helper after a form submit was the form that was posted. This meant that if the posted form wasn't the first form that was posted, the values passed along with the first form were the values stored in the session.
if ($postId)
should have been if ($postId === $formId)
public function direct($form, $persistData = false, $redirectUrl = null)
{
$formId = $form->getElement('unique_form_id')->getValue();
$currentUrl = implode (
'/',
array (
$this->getRequest()->getModuleName(),
$this->getRequest()->getControllerName(),
$this->getRequest()->getActionName()
)
);
$session = new Zend_Session_Namespace('prg');
$redirectUrl = $redirectUrl ? $redirectUrl : $currentUrl;
if ($this->getRequest()->isPost())
{
$postId = $this->getRequest()->getPost('unique_form_id');
if ($postId === $formId)
{
$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector');
$postUrl = $currentUrl;
$session->$postUrl->$postId = array (
'url' => (string) $redirectUrl,
'id' => (string) $postId,
'post' => (array) $this->getRequest()->getPost(),
'persist' => (bool) $persistData
);
Zend_Session::writeClose(true);
$response = $redirector ->setCode(303)
->setExit(true)
->gotoUrl($redirectUrl);
return $response;
}
else {
return false;
}
}
else {
$urlSessionData = $session->$currentUrl;
// Results shown below
Zend_Debug::dump($urlSessionData);
if ($urlSessionData->$formId != null)
{
$formSessionData = $urlSessionData->$formId;
$formPersist = $formSessionData['persist'];
$formPostData = $formSessionData['post'];
if (!$formPersist)
{
unset($urlSessionData->$formId);
}
if(!empty($formPostData))
{
$form->isValid($formPostData);
}
return $formPostData;
}
else {
return false;
}
}
}