Answers.Body: <p><strong>The way I did it</strong></p>
  
  <p>In my most recent extension with a fair amount of CRUD happening via the UI, I used a different form at a specific URL (civicrm/sms/conversation/confirmdelete) for deleting. This gave the  user the chance to see what they were deleting and confirm it.</p>
  
  <p>I then set the context in preProcess of that form, deleted the entity in postProcess, and let the controller handle redirection.</p>
  
  <pre><code>$this-&gt;context = CRM_Utils_System::url('civicrm/sms/conversation/view', "id={$this-&gt;conversationId}");
  $this-&gt;controller-&gt;_destination = $this-&gt;context;
  $session-&gt;pushUserContext($this-&gt;context);
  </code></pre>
  
  <p>IIRC, it was setting <code>$this-&gt;controller-&gt;_destination = $this-&gt;context;</code> that enabled the magic to happen in postProcess, and mean that I didn't have to add any calls to <code>CRM_Utils_System::redirect()</code>.</p>
  
  <p>FWIW I generalised this form to allow it to delete any of the entities that my extension was creating.</p>
  
  <p>See the form here: 
  <a href="https://github.com/3sd/civicrm-sms-conversation/blob/master/CRM/SmsConversation/Form/ConfirmDelete.php" rel="nofollow noreferrer">https://github.com/3sd/civicrm-sms-conversation/blob/master/CRM/SmsConversation/Form/ConfirmDelete.php</a></p>
  
  <p><strong>Is this the CiviCRM way?</strong></p>
  
  <p>Since I wasn't sure how 'CiviCRM' this method was, I just had a quick look at how we handle deleting <em>contacts</em> and <em>membership types</em>.</p>
  
  <p><strong><em>Contacts</em></strong></p>
  
  <p>For contacts, the URLs look as follows:
  civicrm/contact/view/delete?&amp;reset=1&amp;delete=1&amp;cid=2 which maps to CRM_Contact_Form_Task_Delete, i.e. a special form, just for deleting contacts, which (although I haven't looked in details) seems to be a bit like what I did.</p>
  
  <p><strong><em>Membership types</em></strong></p>
  
  <p>civicrm/admin/member/membershipType/add?action=delete&amp;id=1 maps to CRM_Member_Form_MembershipType. Looking at <a href="https://github.com/civicrm/civicrm-core/blob/master/CRM/Member/Form/MembershipType.php" rel="nofollow noreferrer">the class</a> and its <a href="https://github.com/civicrm/civicrm-core/blob/master/templates/CRM/Member/Form/MembershipType.tpl" rel="nofollow noreferrer">associated template</a></p>
  
  <p><strong>preProcess</strong> sets an appropriate context (this is where you would put your URL to your 'page listing stuff', I think).</p>
  
  <pre><code>$url = CRM_Utils_System::url('civicrm/admin/member/membershipType', 'reset=1');
  $session-&gt;pushUserContext($url);
  </code></pre>
  
  <p>It also assigns the action to the template</p>
  
  <pre><code>$this-&gt;assign('action', $this-&gt;_action);
  </code></pre>
  
  <p><strong>buildForm</strong> checks to see if this is a delete action, and if so, just returns, since it doesn't need to add any form elements</p>
  
  <pre><code>if ($this-&gt;_action &amp; CRM_Core_Action::DELETE) {
    return;
  }
  </code></pre>
  
  <p><strong>postProcess</strong> does a similar check</p>
  
  <pre><code>public function postProcess() {
    if ($this-&gt;_action &amp; CRM_Core_Action::DELETE) {
      try {
        CRM_Member_BAO_MembershipType::del($this-&gt;_id);
      }
  ...
  </code></pre>
  
  <p>And the template has a similar if else</p>
  
  <pre><code>{if $action eq 8}
    &lt;div class="messages status no-popup"&gt;
      {ts}WARNING: Deleting this option will result in the loss of all membership records of this type.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
    &lt;/div&gt;
    &lt;div&gt; {include file="CRM/common/formButtons.tpl"}&lt;/div&gt;
  {else}
  </code></pre>
  
  <p><strong>So what is the right way?</strong></p>
  
  <p>No comment :) You decide.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-02T11:08:15.803Z
Answers.LastActivityDate: 2017-08-02T11:08:15.803Z
Answers.UserDisplayName: michaelmcandrew
Body: <p>When developing extensions I have always followed this path when I had a page listing stuff (for example books) and an action link to delete the book:</p>
  
  <ol>
  <li>Create the page and add a link to the form <code>CRM_Utils_System::url(/ "civicrm/myext/form/myform", "action=delete&amp;reset=1", TRUE)</code></li>
  <li><p>In the form, pick up the delete action in the preProcess method like so:</p>
  
  <p><code>
  if ($this-&gt;_action == CRM_Core_ACTION::DELETE) {
  //do my stuff
  $url = CRM_Utils_System::url("civicrm/myext/page/mypage", "reset=1", TRUE);
  CRM_Utils_System::redirect($url);
  }</code></p></li>
  </ol>
  
  <p>I understood that I should not use the CRM_Util_System::redirect() but should use the <code>CRM_Core_Session::singleton-&gt;pushUserContext($url)</code> instead. But what is then the recommended way to ignore the rest of my form processing so that the controller returns to the userContext (being my page)?</p>
  
Tags: <extension><developer><forms><redirect>
Title: Recommended way to deal with delete action in a page?
ThreadText: # Recommended way to deal with delete action in a page?
  
  (Asked by: username_0 on 2017-08-02)
  
  When developing extensions I have always followed this path when I had a page listing stuff (for example books) and an action link to delete the book:
  
  1. Create the page and add a link to the form `CRM_Utils_System::url(/ "civicrm/myext/form/myform", "action=delete&reset=1", TRUE)`
  2. In the form, pick up the delete action in the preProcess method like so:
  
     `if ($this->_action == CRM_Core_ACTION::DELETE) {
     //do my stuff
     $url = CRM_Utils_System::url("civicrm/myext/page/mypage", "reset=1", TRUE);
     CRM_Utils_System::redirect($url);
     }`
  
  I understood that I should not use the CRM\_Util\_System::redirect() but should use the `CRM_Core_Session::singleton->pushUserContext($url)` instead. But what is then the recommended way to ignore the rest of my form processing so that the controller returns to the userContext (being my page)?
  
  **Tags:** extension, developer, forms, redirect
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2017-08-02. Score: 3
  
  **The way I did it**
  
  In my most recent extension with a fair amount of CRUD happening via the UI, I used a different form at a specific URL (civicrm/sms/conversation/confirmdelete) for deleting. This gave the user the chance to see what they were deleting and confirm it.
  
  I then set the context in preProcess of that form, deleted the entity in postProcess, and let the controller handle redirection.
  
  ```
  $this->context = CRM_Utils_System::url('civicrm/sms/conversation/view', "id={$this->conversationId}");
  $this->controller->_destination = $this->context;
  $session->pushUserContext($this->context);
  
  ```
  
  IIRC, it was setting `$this->controller->_destination = $this->context;` that enabled the magic to happen in postProcess, and mean that I didn't have to add any calls to `CRM_Utils_System::redirect()`.
  
  FWIW I generalised this form to allow it to delete any of the entities that my extension was creating.
  
  See the form here:
  <https://github.com/3sd/civicrm-sms-conversation/blob/master/CRM/SmsConversation/Form/ConfirmDelete.php>
  
  **Is this the CiviCRM way?**
  
  Since I wasn't sure how 'CiviCRM' this method was, I just had a quick look at how we handle deleting *contacts* and *membership types*.
  
  ***Contacts***
  
  For contacts, the URLs look as follows:
  civicrm/contact/view/delete?&reset=1&delete=1&cid=2 which maps to CRM\_Contact\_Form\_Task\_Delete, i.e. a special form, just for deleting contacts, which (although I haven't looked in details) seems to be a bit like what I did.
  
  ***Membership types***
  
  civicrm/admin/member/membershipType/add?action=delete&id=1 maps to CRM\_Member\_Form\_MembershipType. Looking at [the class](https://github.com/civicrm/civicrm-core/blob/master/CRM/Member/Form/MembershipType.php) and its [associated template](https://github.com/civicrm/civicrm-core/blob/master/templates/CRM/Member/Form/MembershipType.tpl)
  
  **preProcess** sets an appropriate context (this is where you would put your URL to your 'page listing stuff', I think).
  
  ```
  $url = CRM_Utils_System::url('civicrm/admin/member/membershipType', 'reset=1');
  $session->pushUserContext($url);
  
  ```
  
  It also assigns the action to the template
  
  ```
  $this->assign('action', $this->_action);
  
  ```
  
  **buildForm** checks to see if this is a delete action, and if so, just returns, since it doesn't need to add any form elements
  
  ```
  if ($this->_action & CRM_Core_Action::DELETE) {
    return;
  }
  
  ```
  
  **postProcess** does a similar check
  
  ```
  public function postProcess() {
    if ($this->_action & CRM_Core_Action::DELETE) {
      try {
        CRM_Member_BAO_MembershipType::del($this->_id);
      }
  ...
  
  ```
  
  And the template has a similar if else
  
  ```
  {if $action eq 8}
    <div class="messages status no-popup">
      {ts}WARNING: Deleting this option will result in the loss of all membership records of this type.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
    </div>
    <div> {include file="CRM/common/formButtons.tpl"}</div>
  {else}
  
  ```
  
  **So what is the right way?**
  
  No comment :) You decide.
  
  
  ---
  
  