From da85973f34f4e2ccb050ba929145bd088751e629 Mon Sep 17 00:00:00 2001
From: Jaap Jansma <jaap.jansma@civicoop.org>
Date: Tue, 15 Aug 2023 14:02:26 +0200
Subject: [PATCH] Fix for #103: contribution search redirect.

---
 CHANGELOG.md                                  |  1 +
 .../Controller/DataProcessorContactSearch.php | 11 +++-
 .../Form/Output/AbstractUIOutputForm.php      |  7 +++
 .../Controller/ActivitySearch.php             | 15 +++++-
 .../Controller/CaseSearch.php                 | 15 +++++-
 .../Controller/ContributionSearch.php         | 15 +++++-
 .../Controller/MembershipSearch.php           | 15 +++++-
 .../Controller/ParticipantSearch.php          | 15 +++++-
 CRM/DataprocessorSearch/Controller/Search.php | 53 +++++++++++++++----
 .../StateMachine/Search.php                   | 11 +++-
 10 files changed, 139 insertions(+), 19 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 145d1b1d..5dcf6488 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 # Version 1.76 (not yet released)
 
+* Fix for #103: contribution search redirect.
 * Added permission 'access dataprocessor definitions' that facilitates reading the DataProcessor Output Definitions without granting access CiviCRM. Created for the [Drupal CMRF Reference module](https://www.drupal.org/project/cmrf_reference).
 * Fix for aggregate on case for activities.
 
diff --git a/CRM/Contact/Controller/DataProcessorContactSearch.php b/CRM/Contact/Controller/DataProcessorContactSearch.php
index 63e2e256..03e232eb 100644
--- a/CRM/Contact/Controller/DataProcessorContactSearch.php
+++ b/CRM/Contact/Controller/DataProcessorContactSearch.php
@@ -33,7 +33,9 @@ class CRM_Contact_Controller_DataProcessorContactSearch extends CRM_Dataprocesso
     return 'CRM_Contact_Selector_DataProcessorContactSearch';
   }
 
-
+  public function getUrlForSearchRedirectReplacement():? string {
+    return '/civicrm/contact/search';
+  }
 
   public function getSearchName(): string {
     return 'Basic';
@@ -43,7 +45,12 @@ class CRM_Contact_Controller_DataProcessorContactSearch extends CRM_Dataprocesso
     return 'CRM_Contact_Form_DataProcessorContactSearch';
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_Contact_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php b/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php
index 51650e4d..5c786611 100644
--- a/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php
+++ b/CRM/Dataprocessor/Form/Output/AbstractUIOutputForm.php
@@ -140,6 +140,13 @@ abstract class CRM_Dataprocessor_Form_Output_AbstractUIOutputForm extends CRM_Co
     }
   }
 
+  /**
+   * @return array|\CRM_Dataprocessor_BAO_DataProcessorOutput
+   */
+  public function getDataProcessorOutput(): array {
+    return $this->dataProcessorOutput;
+  }
+
   /**
    * This function could be override in child classes to change default configuration.
    *
diff --git a/CRM/DataprocessorSearch/Controller/ActivitySearch.php b/CRM/DataprocessorSearch/Controller/ActivitySearch.php
index a576c774..5c10b49b 100644
--- a/CRM/DataprocessorSearch/Controller/ActivitySearch.php
+++ b/CRM/DataprocessorSearch/Controller/ActivitySearch.php
@@ -24,7 +24,20 @@ class CRM_DataprocessorSearch_Controller_ActivitySearch extends CRM_Dataprocesso
     return 'CRM_DataprocessorSearch_Form_ActivitySearch';
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  public function getComponent(): string {
+    return 'Activity';
+  }
+
+  public function getUrlForSearchRedirectReplacement():? string {
+    return '/civicrm/activity/search';
+  }
+
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_Activity_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/DataprocessorSearch/Controller/CaseSearch.php b/CRM/DataprocessorSearch/Controller/CaseSearch.php
index f3722d64..959fc6b4 100644
--- a/CRM/DataprocessorSearch/Controller/CaseSearch.php
+++ b/CRM/DataprocessorSearch/Controller/CaseSearch.php
@@ -24,7 +24,20 @@ class CRM_DataprocessorSearch_Controller_CaseSearch extends CRM_DataprocessorSea
     return 'CRM_DataprocessorSearch_Form_CaseSearch';
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  public function getComponent(): string {
+    return 'Case';
+  }
+
+  public function getUrlForSearchRedirectReplacement():? string {
+    return '/civicrm/case/search';
+  }
+
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_Case_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/DataprocessorSearch/Controller/ContributionSearch.php b/CRM/DataprocessorSearch/Controller/ContributionSearch.php
index ba641d68..228a9d27 100644
--- a/CRM/DataprocessorSearch/Controller/ContributionSearch.php
+++ b/CRM/DataprocessorSearch/Controller/ContributionSearch.php
@@ -24,7 +24,20 @@ class CRM_DataprocessorSearch_Controller_ContributionSearch extends CRM_Dataproc
     return 'CRM_DataprocessorSearch_Form_ContributionSearch';
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  public function getComponent(): string {
+    return 'Contribute';
+  }
+
+  public function getUrlForSearchRedirectReplacement():? string {
+    return '/civicrm/contribute/search';
+  }
+
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_Contribute_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/DataprocessorSearch/Controller/MembershipSearch.php b/CRM/DataprocessorSearch/Controller/MembershipSearch.php
index 7ef3d8c1..85e08c7c 100644
--- a/CRM/DataprocessorSearch/Controller/MembershipSearch.php
+++ b/CRM/DataprocessorSearch/Controller/MembershipSearch.php
@@ -24,7 +24,20 @@ class CRM_DataprocessorSearch_Controller_MembershipSearch extends CRM_Dataproces
     return 'CRM_DataprocessorSearch_Form_MembershipSearch';
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  public function getComponent(): string {
+    return 'Member';
+  }
+
+  public function getUrlForSearchRedirectReplacement():? string {
+    return '/civicrm/member/search';
+  }
+
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_Member_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/DataprocessorSearch/Controller/ParticipantSearch.php b/CRM/DataprocessorSearch/Controller/ParticipantSearch.php
index 495b6268..3367c8fd 100644
--- a/CRM/DataprocessorSearch/Controller/ParticipantSearch.php
+++ b/CRM/DataprocessorSearch/Controller/ParticipantSearch.php
@@ -24,7 +24,20 @@ class CRM_DataprocessorSearch_Controller_ParticipantSearch extends CRM_Dataproce
     return 'CRM_DataprocessorSearch_Form_ParticipantSearch';
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  public function getComponent(): string {
+    return 'Event';
+  }
+
+  public function getUrlForSearchRedirectReplacement():? string {
+    return '/civicrm/event/search';
+  }
+
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_Event_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/DataprocessorSearch/Controller/Search.php b/CRM/DataprocessorSearch/Controller/Search.php
index 6fcfb7fc..4ba987b5 100644
--- a/CRM/DataprocessorSearch/Controller/Search.php
+++ b/CRM/DataprocessorSearch/Controller/Search.php
@@ -44,6 +44,40 @@ class CRM_DataprocessorSearch_Controller_Search extends CRM_Core_Controller {
     return 'CRM_DataprocessorSearch_Form_Search';
   }
 
+  public function getUrlForSearchRedirectReplacement():? string {
+    return null;
+  }
+
+  public function getUrlForDestination():? string {
+    $searchForm = $this->getPage($this->getSearchName());
+    if ($searchForm instanceof CRM_DataprocessorSearch_Form_AbstractSearch && $output = $searchForm->getDataProcessorOutput()) {
+      $factory = dataprocessor_get_factory();
+      $outputClass = $factory->getOutputByName($output['type']);
+      if ($outputClass instanceof \Civi\DataProcessor\Output\UIFormOutputInterface) {
+        return $outputClass->getUrlToUi($output, $searchForm->getDataProcessor());
+      }
+    }
+    return null;
+  }
+
+  public function replaceSearchRedirect() {
+    $session = CRM_Core_Session::singleton();
+    $currentRedirect = $session->readUserContext();
+    if ($this->getUrlForSearchRedirectReplacement() && stripos($currentRedirect, $this->getUrlForSearchRedirectReplacement()) === 0) {
+      $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
+      $urlPath = CRM_Utils_System::currentPath();
+      $urlParams = 'force=1';
+      if ($qfKey) {
+        $urlParams .= "&qfKey=$qfKey";
+      }
+      $session->replaceUserContext(CRM_Utils_System::url($urlPath, $urlParams));
+    }
+    $currentRedirect = $session->readUserContext();
+    if ($this->getUrlForDestination() && stripos($currentRedirect, $this->getUrlForDestination()) === 0) {
+      $this->setDestination($currentRedirect);
+    }
+  }
+
   /**
    * Process the request, overrides the default QFC run method
    * This routine actually checks if the QFC is modal and if it
@@ -68,17 +102,11 @@ class CRM_DataprocessorSearch_Controller_Search extends CRM_Core_Controller {
       if ($searchForm instanceof CRM_DataprocessorSearch_Form_AbstractSearch) {
         $searchForm->preProcess();
       }
-      $this->resetPage($pageName);
 
-      $session = CRM_Core_Session::singleton();
-      $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
-      $urlPath = CRM_Utils_System::currentPath();
-      $urlParams = 'force=1';
-      if ($qfKey) {
-        $urlParams .= "&qfKey=$qfKey";
+      if ($action == 'next') {
+        $this->replaceSearchRedirect();
+        $this->resetPage($pageName);
       }
-
-      $this->setDestination(CRM_Utils_System::url($urlPath, $urlParams));
     }
 
     return parent::run();
@@ -91,7 +119,12 @@ class CRM_DataprocessorSearch_Controller_Search extends CRM_Core_Controller {
     return $this->get('selectorName');
   }
 
-  public function getTaskClass(string $selectedTask):? string {
+  /**
+   * @param string $selectedTask
+   *
+   * @return string|array|null
+   */
+  public function getTaskClass(string $selectedTask) {
     [$task] = CRM_DataprocessorSearch_Task::getTask($selectedTask);
     if ($task) {
       return $task;
diff --git a/CRM/DataprocessorSearch/StateMachine/Search.php b/CRM/DataprocessorSearch/StateMachine/Search.php
index a10c3bb4..56e29989 100644
--- a/CRM/DataprocessorSearch/StateMachine/Search.php
+++ b/CRM/DataprocessorSearch/StateMachine/Search.php
@@ -35,7 +35,14 @@ class CRM_DataprocessorSearch_StateMachine_Search extends CRM_Core_StateMachine
       $this->_task = $this->getExportFormClass($controller);
     }
 
-    if ($this->_task) {
+    if (is_array($this->_task)) {
+      foreach ($this->_task as $t) {
+        if ($t) {
+          $this->_pages[$t] = NULL;
+        }
+      }
+    }
+    elseif ($this->_task) {
       $this->_pages[$this->_task] = NULL;
     }
 
@@ -80,7 +87,7 @@ class CRM_DataprocessorSearch_StateMachine_Search extends CRM_Core_StateMachine
    *
    * @return string
    */
-  private function getTaskClass(CRM_DataprocessorSearch_Controller_Search $controller):? string {
+  private function getTaskClass(CRM_DataprocessorSearch_Controller_Search $controller) {
     // total hack, check POST vars and then session to determine stuff
     $value = CRM_Utils_Array::value('task', $_POST);
     if (!isset($value)) {
-- 
GitLab