Answers.Body: <p>Here is what I do in a page:</p>
  
  <pre><code>$session = CRM_Core_Session::singleton();
  $session-&gt;pushUserContext(CRM_Utils_System::url('civicrm/pumexpenseclaims/page/claimlevel', 'reset=1', true));
  </code></pre>
  
  <p>Then in the form I do nothing in the postProcess. The only thing I take into consideration is when I press something like delete on the page where I take an action but do not need a form. If that is the case I tend to do this:</p>
  
  <pre><code>$session = CRM_Core_Session::singleton();
  CRM_Utils_System::redirect($session-&gt;readUserContext());
  </code></pre>
  
  <p>Mind you, it could well be that this pattern no longer works in 4.7? What are the issues you run in to?</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-07T19:11:20.523Z
Answers.Text: when you say "in a page", where do you mean, specifically? I've added a call to pushUserContext in buildQuickForm but it doesn't seem to have any effect.
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-08T07:24:44.593Z
Answers.Text: In most cases I have a list of items on a page, which then leads to an action on a form? Strange that the pushUserContext has no effect....
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-08T07:25:58.840Z
Answers.Text: Check this page https://github.com/CiviCooP/org.civicoop.civirules/blob/master/CRM/Civirules/Page/Rule.php with this related form https://github.com/CiviCooP/org.civicoop.civirules/blob/master/CRM/Civirules/Form/Rule.php
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-08T12:38:46.327Z
Answers.Text: hey @erik. so in your code, a redirect, or similar, must be happening somewhere (in core, I presume) but I don't know where. Do you? Knowing where that happens might help me debug why it isn't happening in my case.
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-08T12:40:05.493Z
Answers.Text: I do not know either, I would expect that at some point in the CRM_Core_Form it would revert back to the user context?
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-04-01T08:28:23.467Z
Answers.Text: Would be good to know what type of button you are using on these pages, Erik
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-04-03T15:28:09.283Z
Answers.Text: I am not really using any button, when the user presses saves or cancel they go back to the userContext?
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-04-04T06:14:16.567Z
Answers.Text: saves and cancel are buttons :) looking at https://github.com/CiviCooP/org.civicoop.civirules/blob/master/CRM/Civirules/Form/Rule.phphttps://github.com/CiviCooP/org.civicoop.civirules/blob/master/CRM/Civirules/Form/Rule.php they have the type next and cancel.
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-04-04T06:41:02.453Z
Answers.Text: Allright, you mean in that sense :-) Yes I use the cancel and save buttons, with next and cancel type.
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-02T11:15:05.793Z
Answers.LastActivityDate: 2017-02-02T11:15:05.793Z
Answers.UserDisplayName: ErikH - CiviCooP
Answers.Body: <p>I tend to set the userContext in my page, which will then make my form return to where I wanted it. Does that make sense?</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-02T10:49:52.340Z
Answers.Text: I did try doing that, but didn't get it working - do you want to expand on your answer with an example? stackexchange will reward your quality answer handsomely, I am sure ;)
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-02T10:53:18.010Z
Answers.Text: If you could also explain if there is anything to take into account when the page is loaded via a pop up vs normally, many riches will flow your way...
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-02T10:45:57.567Z
Answers.LastActivityDate: 2017-02-02T10:45:57.567Z
Answers.UserDisplayName: ErikH - CiviCooP
Answers.Body: <p>Here's how Volunteer does it:</p>
  
  <ul>
  <li>Form class <a href="https://github.com/civicrm/org.civicrm.volunteer/blob/fcebff0828181884908d5030775e95f08a7ca7a8/CRM/Volunteer/Form/VolunteerSignUp.php#L45-L52" rel="nofollow noreferrer">declares</a> a property <code>$_destination</code>.</li>
  <li>During the <code>preProcess</code> stage, a method <a href="https://github.com/civicrm/org.civicrm.volunteer/blob/fcebff0828181884908d5030775e95f08a7ca7a8/CRM/Volunteer/Form/VolunteerSignUp.php#L743-L769" rel="nofollow noreferrer"><code>setDestination()</code></a> decides how to set that property based on context.</li>
  <li>During the <code>postProcess</code>, <a href="https://github.com/civicrm/org.civicrm.volunteer/blame/fcebff0828181884908d5030775e95f08a7ca7a8/CRM/Volunteer/Form/VolunteerSignUp.php#L450" rel="nofollow noreferrer"><code>CRM_Core_Session::singleton()-&gt;pushUserContext($this-&gt;_destination);</code></a> takes care of the redirect. Note that doing it this way rather than using <code>redirect</code> is more <a href="https://github.com/civicrm/org.civicrm.volunteer/commit/0b140799d0f1cc9aea7736b1cf3497141e9fee1d" rel="nofollow noreferrer">extensible</a>.</li>
  <li>Ensure that the type of your submit button is 'done'.</li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-03-31T08:57:28.943Z
Answers.Text: This didn't work for me initially. I dug around in a few of the relevant classes `CRM_Core_Controller`, `HTML_QuickForm_Controller`, `CRM_Core_QuickForm_Action` and CRM_Core_QuickForm_Action_*` * including *=Submit and *=Done and found that this approach works when the type of the submit button is 'done'.
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-02-10T16:26:07.213Z
Answers.LastActivityDate: 2017-03-31T12:16:43.373Z
Answers.LastEditDate: 2017-03-31T12:16:43.373Z
Answers.UserDisplayName: universalhandle
Answers.Body: <p>Use the built in button <strong>types</strong> and corresponding <code>CRM_Core_QuickForm_Action_*</code> classes that are invoked when those buttons are clicked.</p>
  
  <p>For example, clicking on a button created with</p>
  
  <pre><code>$this-&gt;addButtons(array(
    array(
      'type' =&gt; 'submit',
      'name' =&gt; ts('Submit'),
      'isDefault' =&gt; TRUE,
    ),
  ));
  </code></pre>
  
  <p>Will call <code>CRM_Core_QuickForm_Action_Submit-&gt;perform()</code> which redirects you to the value of <code>$form-&gt;controller-&gt;_destination</code> (and if <code>$form-&gt;controller-&gt;_destination</code> is not set, will display the form again).</p>
  
  <p>So in the simplest case, you can just add a line along the lines of the following to your form:</p>
  
  <pre><code>$this-&gt;controller-&gt;_destination = CRM_Utils_System::url('civicrm/something', 'reset=1');
  </code></pre>
  
  <p>Probably the best way to understand the other actions is to have a look at the <code>perform()</code> methods in the <code>CRM_Core_QuickForm_Action_Submit_*</code> classes.</p>
  
  <p>GinkgoFJG's answer (and possibly Erik's) works when the button type is 'done', which makes sense when you have a look at the comments the inline code documentation for <code>CRM_Core_QuickForm_Action_Done-&gt;perform()</code>.</p>
  
  <pre><code>// Processes the request.
  // [...] validate the page
  // and if success, call post process
  // when done processing pop to user context
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-01T15:24:44.023Z
Answers.Text: Michael, you did quite some investigation...but is not totally clear to me. So what do I do if I want to 'interrupt' the form processing and end it what do I do exactly?
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-01T16:57:04.213Z
Answers.Text: @ErikH-CiviCooP - hmm, would you like to flesh out some details - maybe as a new question? - and I'll do my best to answer as I think that the answer probably depends on what exactly you mean by 'interrupt' and 'end' :)
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-02T07:25:29.927Z
Answers.Text: will do. I have a solution but it might be interesting for other visitors too :-)
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-02T07:57:31.193Z
Answers.Text: Here is my new question: https://civicrm.stackexchange.com/questions/19743/recommended-way-to-deal-with-delete-action-in-a-page
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-03-31T09:23:43.780Z
Answers.LastActivityDate: 2017-04-01T08:26:31.713Z
Answers.LastEditDate: 2017-04-01T08:26:31.713Z
Answers.UserDisplayName: michaelmcandrew
Body: <p>I often find myself writing calls to CRM_Utils_Redirect in my postProcess methods.</p>
  
  <p>But in core code I don't see this. I see the use of methods like $session->replaceUserContext and postProcess functions that end seemingly without telling me where to go next.</p>
  
  <p>I feel like CiviCRM is often clever enough to go to load different pages on form submission based on where you came from. I have no solid proof of that but lets give Civi the benefit of the doubt on that one :)</p>
  
  <p>I'm guessing there is a structure somewhere that is telling CiviCRM what page to load next but I have failed to spot what that is.</p>
  
  <p>I'm interested in the canonical way that CiviCRM does this (if there is a canoncial way) and knowing how legacy that is, and also what I <em>should</em> be doing.</p>
  
  <p>If anyone could enlighten me, I'd be grateful :)</p>
  
  <p>PS. I am not so interested in "you should write that in angular" enlightenment, at least not in the answer to this question.</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-12-01T13:42:44.040Z
Comments.Text: just wanted to reference this answer: https://civicrm.stackexchange.com/a/2200/133 for anyone that comes across this question since it seems related.
Comments.UserDisplayName: michaelmcandrew
Tags: <developer>
Title: What's the recommended way to handle redirection after quickform submissions?
ThreadText: # What's the recommended way to handle redirection after quickform submissions?
  
  (Asked by: username_0 on 2017-02-02)
  
  I often find myself writing calls to CRM\_Utils\_Redirect in my postProcess methods.
  
  But in core code I don't see this. I see the use of methods like $session->replaceUserContext and postProcess functions that end seemingly without telling me where to go next.
  
  I feel like CiviCRM is often clever enough to go to load different pages on form submission based on where you came from. I have no solid proof of that but lets give Civi the benefit of the doubt on that one :)
  
  I'm guessing there is a structure somewhere that is telling CiviCRM what page to load next but I have failed to spot what that is.
  
  I'm interested in the canonical way that CiviCRM does this (if there is a canoncial way) and knowing how legacy that is, and also what I *should* be doing.
  
  If anyone could enlighten me, I'd be grateful :)
  
  PS. I am not so interested in "you should write that in angular" enlightenment, at least not in the answer to this question.
  
  **Tags:** developer
  
  > **Comments:**
  > **username_0**: just wanted to reference this answer: https://civicrm.stackexchange.com/a/2200/133 for anyone that comes across this question since it seems related.  
  
  ---
  
  ## 4 answers
  
  ### Answer by username_0 on 2017-03-31. Score: 4 | Accepted answer
  
  Use the built in button **types** and corresponding `CRM_Core_QuickForm_Action_*` classes that are invoked when those buttons are clicked.
  
  For example, clicking on a button created with
  
  ```
  $this->addButtons(array(
    array(
      'type' => 'submit',
      'name' => ts('Submit'),
      'isDefault' => TRUE,
    ),
  ));
  
  ```
  
  Will call `CRM_Core_QuickForm_Action_Submit->perform()` which redirects you to the value of `$form->controller->_destination` (and if `$form->controller->_destination` is not set, will display the form again).
  
  So in the simplest case, you can just add a line along the lines of the following to your form:
  
  ```
  $this->controller->_destination = CRM_Utils_System::url('civicrm/something', 'reset=1');
  
  ```
  
  Probably the best way to understand the other actions is to have a look at the `perform()` methods in the `CRM_Core_QuickForm_Action_Submit_*` classes.
  
  GinkgoFJG's answer (and possibly Erik's) works when the button type is 'done', which makes sense when you have a look at the comments the inline code documentation for `CRM_Core_QuickForm_Action_Done->perform()`.
  
  ```
  // Processes the request.
  // [...] validate the page
  // and if success, call post process
  // when done processing pop to user context
  
  ```
  
  > **Comments:**
  > **username_1**: Michael, you did quite some investigation...but is not totally clear to me. So what do I do if I want to 'interrupt' the form processing and end it what do I do exactly?  
  > **username_0**: @username_1 - hmm, would you like to flesh out some details - maybe as a new question? - and I'll do my best to answer as I think that the answer probably depends on what exactly you mean by 'interrupt' and 'end' :)  
  > **username_1**: will do. I have a solution but it might be interesting for other visitors too :-)  
  > **username_1**: Here is my new question: https://civicrm.stackexchange.com/questions/19743/recommended-way-to-deal-with-delete-action-in-a-page  
  
  ---
  
  ### Answer by username_1 on 2017-02-02. Score: 3
  
  Here is what I do in a page:
  
  ```
  $session = CRM_Core_Session::singleton();
  $session->pushUserContext(CRM_Utils_System::url('civicrm/pumexpenseclaims/page/claimlevel', 'reset=1', true));
  
  ```
  
  Then in the form I do nothing in the postProcess. The only thing I take into consideration is when I press something like delete on the page where I take an action but do not need a form. If that is the case I tend to do this:
  
  ```
  $session = CRM_Core_Session::singleton();
  CRM_Utils_System::redirect($session->readUserContext());
  
  ```
  
  Mind you, it could well be that this pattern no longer works in 4.7? What are the issues you run in to?
  
  > **Comments:**
  > **username_0**: when you say "in a page", where do you mean, specifically? I've added a call to pushUserContext in buildQuickForm but it doesn't seem to have any effect.  
  > **username_1**: In most cases I have a list of items on a page, which then leads to an action on a form? Strange that the pushUserContext has no effect....  
  > **username_1**: Check this page https://github.com/username_1/org.username_1.civirules/blob/master/CRM/Civirules/Page/Rule.php with this related form https://github.com/username_1/org.username_1.civirules/blob/master/CRM/Civirules/Form/Rule.php  
  > **username_0**: hey @erik. so in your code, a redirect, or similar, must be happening somewhere (in core, I presume) but I don't know where. Do you? Knowing where that happens might help me debug why it isn't happening in my case.  
  > **username_1**: I do not know either, I would expect that at some point in the CRM_Core_Form it would revert back to the user context?  
  > **username_0**: Would be good to know what type of button you are using on these pages, Erik  
  > **username_1**: I am not really using any button, when the user presses saves or cancel they go back to the userContext?  
  > **username_0**: saves and cancel are buttons :) looking at https://github.com/username_1/org.username_1.civirules/blob/master/CRM/Civirules/Form/Rule.phphttps://github.com/username_1/org.username_1.civirules/blob/master/CRM/Civirules/Form/Rule.php they have the type next and cancel.  
  > **username_1**: Allright, you mean in that sense :-) Yes I use the cancel and save buttons, with next and cancel type.  
  
  ---
  
  ### Answer by username_1 on 2017-02-02. Score: 1
  
  I tend to set the userContext in my page, which will then make my form return to where I wanted it. Does that make sense?
  
  > **Comments:**
  > **username_0**: I did try doing that, but didn't get it working - do you want to expand on your answer with an example? stackexchange will reward your quality answer handsomely, I am sure ;)  
  > **username_0**: If you could also explain if there is anything to take into account when the page is loaded via a pop up vs normally, many riches will flow your way...  
  
  ---
  
  ### Answer by username_2 on 2017-02-10. Score: 1
  
  Here's how Volunteer does it:
  
  * Form class [declares](https://github.com/civicrm/org.civicrm.volunteer/blob/fcebff0828181884908d5030775e95f08a7ca7a8/CRM/Volunteer/Form/VolunteerSignUp.php#L45-L52) a property `$_destination`.
  * During the `preProcess` stage, a method [`setDestination()`](https://github.com/civicrm/org.civicrm.volunteer/blob/fcebff0828181884908d5030775e95f08a7ca7a8/CRM/Volunteer/Form/VolunteerSignUp.php#L743-L769) decides how to set that property based on context.
  * During the `postProcess`, [`CRM_Core_Session::singleton()->pushUserContext($this->_destination);`](https://github.com/civicrm/org.civicrm.volunteer/blame/fcebff0828181884908d5030775e95f08a7ca7a8/CRM/Volunteer/Form/VolunteerSignUp.php#L450) takes care of the redirect. Note that doing it this way rather than using `redirect` is more [extensible](https://github.com/civicrm/org.civicrm.volunteer/commit/0b140799d0f1cc9aea7736b1cf3497141e9fee1d).
  * Ensure that the type of your submit button is 'done'.
  
  > **Comments:**
  > **username_0**: This didn't work for me initially. I dug around in a few of the relevant classes `CRM_Core_Controller`, `HTML_QuickForm_Controller`, `CRM_Core_QuickForm_Action` and CRM_Core_QuickForm_Action_*` * including *=Submit and *=Done and found that this approach works when the type of the submit button is 'done'.  
  
  ---
  
  