From 92c48f6d5ad25443882af70b2952cab40af33b2f Mon Sep 17 00:00:00 2001
From: Jaap Jansma <jaap.jansma@civicoop.org>
Date: Thu, 20 Feb 2025 13:35:40 +0100
Subject: [PATCH] Added extra filtes to data sources, such as a filter for
 event on the participant data source.

---
 CHANGELOG.md                                  |  1 +
 .../DataSpecification/FieldSpecification.php  | 11 +++++
 .../DataProcessor/DataSpecification/Utils.php | 11 +++++
 Civi/DataProcessor/Source/AbstractSource.php  | 41 ++++++++++++++++---
 4 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 23b3014b..c9341b21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 # Version 1.118 (not yet released)
 
 * Fixed issues with Aggregated Contribution data source
+* Added extra filtes to data sources, such as a filter for event on the participant data source.
 
 # Version 1.117
 
diff --git a/Civi/DataProcessor/DataSpecification/FieldSpecification.php b/Civi/DataProcessor/DataSpecification/FieldSpecification.php
index 68f3f305..c326f67e 100644
--- a/Civi/DataProcessor/DataSpecification/FieldSpecification.php
+++ b/Civi/DataProcessor/DataSpecification/FieldSpecification.php
@@ -33,6 +33,9 @@ class FieldSpecification implements SqlFieldSpecification {
    */
   public $options = null;
 
+  /** @var null|string */
+  public $fkEntity = null;
+
   /**
    * A multi value field is a field which holds multiple values
    * separated by \CRM_Core_DAO::valueSeparator
@@ -69,6 +72,14 @@ class FieldSpecification implements SqlFieldSpecification {
     return $this->options;
   }
 
+  public function getFkEntity() {
+    return $this->fkEntity;
+  }
+
+  public function setFkEntity($fkEntity) {
+    $this->fkEntity = $fkEntity;
+  }
+
   /**
    * @param $function
    *
diff --git a/Civi/DataProcessor/DataSpecification/Utils.php b/Civi/DataProcessor/DataSpecification/Utils.php
index 7689b73f..70ade2a8 100644
--- a/Civi/DataProcessor/DataSpecification/Utils.php
+++ b/Civi/DataProcessor/DataSpecification/Utils.php
@@ -42,6 +42,17 @@ class Utils {
       if (isset($field['serialize']) && $field['serialize'] == \CRM_Core_DAO::SERIALIZE_SEPARATOR_BOOKEND) {
         $fieldSpec->setMultiValueField(true);
       }
+      if (isset($field['FKClassName'])) {
+        $entity = \CRM_Core_DAO_AllCoreTables::getEntityNameForClass($field['FKClassName']);
+        if ($entity) {
+          $fieldSpec->setFkEntity($entity);
+        }
+      } elseif ($field['name'] == 'id') {
+        $entity = \CRM_Core_DAO_AllCoreTables::getEntityNameForClass($daoClass);
+        if ($entity) {
+          $fieldSpec->setFkEntity($entity);
+        }
+      }
       $dataSpecification->addFieldSpecification($fieldSpec->name, $fieldSpec);
     }
   }
diff --git a/Civi/DataProcessor/Source/AbstractSource.php b/Civi/DataProcessor/Source/AbstractSource.php
index 10d2a62d..448887db 100644
--- a/Civi/DataProcessor/Source/AbstractSource.php
+++ b/Civi/DataProcessor/Source/AbstractSource.php
@@ -297,11 +297,39 @@ abstract class AbstractSource implements SourceInterface {
             } else {
               $fields[$alias] = $fieldSpec->title;
             }
-            $form->addElement('select', "{$alias}_op", ts('Operator:'), [
-              '' => E::ts(' - Select - '),
-              'IS NOT NULL' => E::ts('Is not empty'),
-              'IS NULL' => E::ts('Is empty'),
-            ]);
+            if ($fieldSpec->getFkEntity()) {
+              $form->addElement('select', "{$alias}_op", ts('Operator:'), [
+                '' => E::ts(' - Select - '),
+                'IN' => E::ts('Is one of'),
+                'NOT IN' => E::ts('Is not one of'),
+                'IS NOT NULL' => E::ts('Is not empty'),
+                'IS NULL' => E::ts('Is empty'),
+              ]);
+              CRM_Dataprocessor_Utils_Form::addInExcludeEntityRef($form, "{$alias}_value", $fieldSpec->title, [
+                'entity' => $fieldSpec->getFkEntity(),
+                'select' => ['minimumInputLength' => 0],
+                'class' => 'huge crm-form-entityref',
+                'placeholder' => E::ts('- Any -'),
+                'multiple' => 'multiple',
+              ], $isRequired);
+            } else {
+              $form->addElement('select', "{$alias}_op", ts('Operator:'), [
+                '' => E::ts(' - Select - '),
+                '=' => E::ts('Equal to'),
+                '!=' => E::ts('Not equal to'),
+                '>' => E::ts('Greater than'),
+                '>=' => E::ts('Greater than or equal to'),
+                '<' => E::ts('Less than'),
+                '<=' => E::ts('Less than or equal to'),
+                'IS NOT NULL' => E::ts('Is not empty'),
+                'IS NULL' => E::ts('Is empty'),
+              ]);
+              $form->addElement('text', "{$alias}_value", $fieldSpec->title, [
+                'style' => 'min-width:250px',
+                'class' => 'huge',
+                'placeholder' => E::ts('- select -'),
+              ]);
+            }
           }
       }
     }
@@ -357,6 +385,9 @@ abstract class AbstractSource implements SourceInterface {
           'op' => $submittedValues[$alias.'_op'],
           'value' => isset($submittedValues[$alias.'_value']) ? $submittedValues[$alias.'_value'] : ''
         );
+        if ($fieldSpec->getFkEntity() && !is_array($filter_config[$alias]['value'])) {
+          $filter_config[$alias]['value'] = explode(',', $filter_config[$alias]['value']);
+        }
       }
       if (isset($submittedValues[$alias.'_relative'])) {
         $filter_config[$alias] = array(
-- 
GitLab