SearchKit - support additional functions
authorColeman Watts <coleman@civicrm.org>
Sun, 25 Jul 2021 06:23:57 +0000 (02:23 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 29 Jul 2021 04:24:38 +0000 (00:24 -0400)
Civi/Api4/Query/SqlFunctionDATE.php [new file with mode: 0644]
Civi/Api4/Query/SqlFunctionTIME.php [new file with mode: 0644]
Civi/Api4/Query/SqlFunctionYEAR.php [new file with mode: 0644]
ext/search_kit/ang/crmSearchAdmin/crmSearchFunction.component.js
ext/search_kit/ang/crmSearchAdmin/crmSearchFunction.html

diff --git a/Civi/Api4/Query/SqlFunctionDATE.php b/Civi/Api4/Query/SqlFunctionDATE.php
new file mode 100644 (file)
index 0000000..5c198b9
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Query;
+
+/**
+ * Sql function
+ */
+class SqlFunctionDATE extends SqlFunction {
+
+  protected static $category = self::CATEGORY_DATE;
+
+  protected static function params(): array {
+    return [
+      [
+        'max_expr' => 1,
+        'optional' => FALSE,
+      ],
+    ];
+  }
+
+  /**
+   * @return string
+   */
+  public static function getTitle(): string {
+    return ts('Date Only');
+  }
+
+  /**
+   * Ensure is processed as type Date
+   *
+   * @see \Civi\Api4\Utils\FormattingUtil::formatOutputValues
+   * @param string $value
+   * @param string $dataType
+   * @return string|array
+   */
+  public function formatOutputValue($value, &$dataType) {
+    $dataType = 'Date';
+    return $value;
+  }
+
+}
diff --git a/Civi/Api4/Query/SqlFunctionTIME.php b/Civi/Api4/Query/SqlFunctionTIME.php
new file mode 100644 (file)
index 0000000..5664134
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Query;
+
+/**
+ * Sql function
+ */
+class SqlFunctionTIME extends SqlFunction {
+
+  protected static $category = self::CATEGORY_DATE;
+
+  protected static function params(): array {
+    return [
+      [
+        'max_expr' => 1,
+        'optional' => FALSE,
+      ],
+    ];
+  }
+
+  /**
+   * @return string
+   */
+  public static function getTitle(): string {
+    return ts('Time Only');
+  }
+
+  /**
+   * Prevent reformatting
+   *
+   * @see \Civi\Api4\Utils\FormattingUtil::formatOutputValues
+   * @param string $value
+   * @param string $dataType
+   * @return string|array
+   */
+  public function formatOutputValue($value, &$dataType) {
+    $dataType = NULL;
+    return $value;
+  }
+
+}
diff --git a/Civi/Api4/Query/SqlFunctionYEAR.php b/Civi/Api4/Query/SqlFunctionYEAR.php
new file mode 100644 (file)
index 0000000..6632e60
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Query;
+
+/**
+ * Sql function
+ */
+class SqlFunctionYEAR extends SqlFunction {
+
+  protected static $category = self::CATEGORY_DATE;
+
+  protected static function params(): array {
+    return [
+      [
+        'max_expr' => 1,
+        'optional' => FALSE,
+      ],
+    ];
+  }
+
+  /**
+   * @return string
+   */
+  public static function getTitle(): string {
+    return ts('Year Only');
+  }
+
+  /**
+   * Prevent reformatting
+   *
+   * @see \Civi\Api4\Utils\FormattingUtil::formatOutputValues
+   * @param string $value
+   * @param string $dataType
+   * @return string|array
+   */
+  public function formatOutputValue($value, &$dataType) {
+    $dataType = NULL;
+    return $value;
+  }
+
+}
index 2ebd28e86d48a46ac76be92cc1507e77eff91f50..7ea57ecd4b75d552c90c03eec57feeda04a9dd09 100644 (file)
@@ -24,7 +24,7 @@
       $scope.$watch('$ctrl.expr', function(expr) {
         var fieldInfo = searchMeta.parseExpr(expr);
         ctrl.path = fieldInfo.path + fieldInfo.suffix;
-        ctrl.field = fieldInfo.field;
+        ctrl.field = [fieldInfo.field];
         ctrl.fn = !fieldInfo.fn ? '' : fieldInfo.fn.name;
         ctrl.modifier = fieldInfo.modifier || null;
         initFunction();
@@ -42,6 +42,7 @@
         }
       }
 
+      // On-demand options for dropdown function selector
       this.getFunctions = function() {
         var allowedTypes = [], functions = [];
         if (ctrl.expr && ctrl.field) {
             allowedTypes.push('aggregate');
           } else {
             allowedTypes.push('comparison', 'string');
-            if (_.includes(['Integer', 'Float', 'Date', 'Timestamp'], ctrl.field.data_type)) {
+            if (_.includes(['Integer', 'Float', 'Date', 'Timestamp'], ctrl.field[0].data_type)) {
               allowedTypes.push('math');
             }
-            if (_.includes(['Date', 'Timestamp'], ctrl.field.data_type)) {
+            if (_.includes(['Date', 'Timestamp'], ctrl.field[0].data_type)) {
               allowedTypes.push('date');
             }
           }
-          _.each(allowedTypes, function (type) {
+          _.each(allowedTypes, function(type) {
+            var allowedFunctions = _.filter(CRM.crmSearchAdmin.functions, function(fn) {
+              return fn.category === type &&
+                fn.params.length &&
+                // For now, only support functions that take a single field
+                fn.params[0].min_expr === 1 &&
+                fn.params[0].max_expr === 1 &&
+                !_.includes(fn.params[0].cant_be, 'SqlField') &&
+                (!fn.params[0].must_be.length || _.includes(fn.params[0].must_be, 'SqlField'));
+            });
             functions.push({
               text: allTypes[type],
-              children: formatForSelect2(_.where(CRM.crmSearchAdmin.functions, {category: type}), 'name', 'title')
+              children: formatForSelect2(allowedFunctions, 'name', 'title')
             });
           });
         }
index 2274f262d975da0d722f524c5cdb8d4e7388583e..258433196acae54d5bce51e20ab26ed211c43222 100644 (file)
@@ -1,5 +1,5 @@
 <div class="form-inline">
-  <label>{{ $ctrl.field.label }}:</label>
+  <label>{{ $ctrl.field[0].label }}:</label>
   <input class="form-control" style="width: 15em;" ng-model="$ctrl.fn" crm-ui-select="{data: $ctrl.getFunctions, placeholder: ts('Select')}" ng-change="$ctrl.selectFunction()">
   <label ng-if="$ctrl.modifierName">
     <input type="checkbox" ng-checked="!!$ctrl.modifier" ng-click="$ctrl.toggleModifier()">