* Angular base page for search admin
*/
class CRM_Search_Page_Admin extends CRM_Core_Page {
- /**
- * @var string[]
- */
- private $loadOptions = ['id', 'name', 'label', 'description', 'color', 'icon'];
-
- /**
- * @var array
- */
- private $schema = [];
/**
* @var string[]
public function run() {
$breadCrumb = [
- 'title' => ts('Search'),
+ 'title' => ts('Search Kit'),
'url' => CRM_Utils_System::url('civicrm/search'),
];
CRM_Utils_System::appendBreadCrumb([$breadCrumb]);
- $this->getSchema();
+ $schema = \Civi\Search\Admin::getSchema();
// If user does not have permission to search any entity, bye bye.
- if (!$this->allowedEntities) {
+ if (!$schema) {
CRM_Utils_System::permissionDenied();
}
// Add client-side vars for the search UI
$vars = [
- 'operators' => CRM_Utils_Array::makeNonAssociative($this->getOperators()),
- 'schema' => $this->schema,
- 'links' => $this->getLinks(),
- 'loadOptions' => $this->loadOptions,
- 'functions' => CRM_Api4_Page_Api4Explorer::getSqlFunctions(),
+ 'schema' => $schema,
+ 'links' => \Civi\Search\Admin::getLinks(array_column($schema, 'name')),
];
Civi::resources()
parent::run();
}
- /**
- * @return string[]
- */
- private function getOperators() {
- return [
- '=' => '=',
- '!=' => '≠',
- '>' => '>',
- '<' => '<',
- '>=' => '≥',
- '<=' => '≤',
- 'CONTAINS' => ts('Contains'),
- 'IN' => ts('Is In'),
- 'NOT IN' => ts('Not In'),
- 'LIKE' => ts('Is Like'),
- 'NOT LIKE' => ts('Not Like'),
- 'BETWEEN' => ts('Is Between'),
- 'NOT BETWEEN' => ts('Not Between'),
- 'IS NULL' => ts('Is Null'),
- 'IS NOT NULL' => ts('Not Null'),
- ];
- }
-
- /**
- * Populates $this->schema & $this->allowedEntities
- */
- private function getSchema() {
- $schema = \Civi\Api4\Entity::get()
- ->addSelect('name', 'title', 'titlePlural', 'description', 'icon')
- ->addWhere('name', '!=', 'Entity')
- ->addOrderBy('titlePlural')
- ->setChain([
- 'get' => ['$name', 'getActions', ['where' => [['name', '=', 'get']]], ['params']],
- ])->execute();
- $getFields = ['name', 'label', 'description', 'options', 'input_type', 'input_attrs', 'data_type', 'serialize', 'fk_entity'];
- foreach ($schema as $entity) {
- // Skip if entity doesn't have a 'get' action or the user doesn't have permission to use get
- if ($entity['get']) {
- // Get fields and pre-load options for certain prominent entities
- $loadOptions = in_array($entity['name'], ['Contact', 'Group']) ? $this->loadOptions : FALSE;
- if ($loadOptions) {
- $entity['optionsLoaded'] = TRUE;
- }
- $entity['fields'] = civicrm_api4($entity['name'], 'getFields', [
- 'select' => $getFields,
- 'where' => [['permission', 'IS NULL']],
- 'orderBy' => ['label'],
- 'loadOptions' => $loadOptions,
- ]);
- // Get the names of params this entity supports (minus some obvious ones)
- $params = $entity['get'][0];
- CRM_Utils_Array::remove($params, 'checkPermissions', 'debug', 'chain', 'language');
- unset($entity['get']);
- $this->schema[] = ['params' => array_keys($params)] + array_filter($entity);
- $this->allowedEntities[] = $entity['name'];
- }
- }
- }
-
- /**
- * @return array
- */
- private function getLinks() {
- $results = [];
- $keys = array_flip(['alias', 'entity', 'joinType']);
- foreach (civicrm_api4('Entity', 'getLinks', ['where' => [['entity', 'IN', $this->allowedEntities]]], ['entity' => 'links']) as $entity => $links) {
- $entityLinks = [];
- foreach ($links as $link) {
- if (!empty($link['entity']) && in_array($link['entity'], $this->allowedEntities)) {
- // Use entity.alias as array key to avoid duplicates
- $entityLinks[$link['entity'] . $link['alias']] = array_intersect_key($link, $keys);
- }
- }
- $results[$entity] = array_values($entityLinks);
- }
- return array_filter($results);
- }
-
}
--- /dev/null
+<?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\Search;
+
+/**
+ * Class Admin
+ * @package Civi\Search
+ */
+class Admin {
+
+ /**
+ * @return array
+ */
+ public static function getAdminSettings():array {
+ return [
+ 'operators' => \CRM_Utils_Array::makeNonAssociative(self::getOperators()),
+ 'functions' => \CRM_Api4_Page_Api4Explorer::getSqlFunctions(),
+ ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function getOperators():array {
+ return [
+ '=' => '=',
+ '!=' => '≠',
+ '>' => '>',
+ '<' => '<',
+ '>=' => '≥',
+ '<=' => '≤',
+ 'CONTAINS' => ts('Contains'),
+ 'IN' => ts('Is In'),
+ 'NOT IN' => ts('Not In'),
+ 'LIKE' => ts('Is Like'),
+ 'NOT LIKE' => ts('Not Like'),
+ 'BETWEEN' => ts('Is Between'),
+ 'NOT BETWEEN' => ts('Not Between'),
+ 'IS NULL' => ts('Is Null'),
+ 'IS NOT NULL' => ts('Not Null'),
+ ];
+ }
+
+ /**
+ * Fetch all entities the current user has permission to `get`
+ */
+ public static function getSchema() {
+ $schema = [];
+ $entities = \Civi\Api4\Entity::get()
+ ->addSelect('name', 'title', 'titlePlural', 'description', 'icon')
+ ->addWhere('name', '!=', 'Entity')
+ ->addOrderBy('titlePlural')
+ ->setChain([
+ 'get' => ['$name', 'getActions', ['where' => [['name', '=', 'get']]], ['params']],
+ ])->execute();
+ $getFields = ['name', 'label', 'description', 'options', 'input_type', 'input_attrs', 'data_type', 'serialize', 'fk_entity'];
+ foreach ($entities as $entity) {
+ // Skip if entity doesn't have a 'get' action or the user doesn't have permission to use get
+ if ($entity['get']) {
+ $entity['fields'] = civicrm_api4($entity['name'], 'getFields', [
+ 'select' => $getFields,
+ 'where' => [['permission', 'IS NULL']],
+ 'orderBy' => ['label'],
+ ]);
+ $params = $entity['get'][0];
+ // Entity must support at least these params or it is too weird for search kit
+ if (!array_diff(['select', 'where', 'orderBy', 'limit', 'offset'], array_keys($params))) {
+ \CRM_Utils_Array::remove($params, 'checkPermissions', 'debug', 'chain', 'language', 'select', 'where', 'orderBy', 'limit', 'offset');
+ unset($entity['get']);
+ $schema[] = ['params' => array_keys($params)] + array_filter($entity);
+ }
+ }
+ }
+ return $schema;
+ }
+
+ /**
+ * @return array
+ */
+ public static function getLinks($allowedEntities) {
+ $results = [];
+ $keys = array_flip(['alias', 'entity', 'joinType']);
+ foreach (civicrm_api4('Entity', 'getLinks', ['where' => [['entity', 'IN', $allowedEntities]]], ['entity' => 'links']) as $entity => $links) {
+ $entityLinks = [];
+ foreach ($links as $link) {
+ if (!empty($link['entity']) && in_array($link['entity'], $allowedEntities)) {
+ // Use entity.alias as array key to avoid duplicates
+ $entityLinks[$link['entity'] . $link['alias']] = array_intersect_key($link, $keys);
+ }
+ }
+ $results[$entity] = array_values($entityLinks);
+ }
+ return array_filter($results);
+ }
+
+}
],
'basePages' => [],
'requires' => ['crmUi', 'crmUtil', 'ngRoute', 'crmRouteBinder', 'ui.sortable', 'ui.bootstrap', 'dialogService', 'api4', 'searchActions'],
+ 'settingsFactory' => ['\Civi\Search\Admin', 'getAdminSettings'],
];
if (bracketPos >= 0) {
var parsed = expr.substr(bracketPos).match(/[ ]?([A-Z]+[ ]+)?([\w.:]+)/);
fieldName = parsed[2];
- result.fn = _.find(CRM.vars.search.functions, {name: expr.substring(0, bracketPos)});
+ result.fn = _.find(CRM.searchAdmin.functions, {name: expr.substring(0, bracketPos)});
result.modifier = _.trim(parsed[1]);
}
result.field = expr ? getField(fieldName, searchEntity) : undefined;
function enqueue(entity) {
entity.optionsLoaded = false;
entities[entity.name] = [entity.name, 'getFields', {
- loadOptions: CRM.vars.search.loadOptions,
+ loadOptions: ['id', 'name', 'label', 'description', 'color', 'icon'],
where: [['options', '!=', false]],
select: ['options']
}, {name: 'options'}];
var ts = $scope.ts = CRM.ts(),
ctrl = this;
this.conjunctions = {AND: ts('And'), OR: ts('Or'), NOT: ts('Not')};
- this.operators = CRM.vars.search.operators;
+ this.operators = CRM.searchAdmin.operators;
this.sortOptions = {
axis: 'y',
connectWith: '.api4-clause-group-sortable',
ctrl = this;
this.$onInit = function() {
- ctrl.functions = formatForSelect2(_.where(CRM.vars.search.functions, {category: ctrl.cat}), 'name', 'title');
+ ctrl.functions = formatForSelect2(_.where(CRM.searchAdmin.functions, {category: ctrl.cat}), 'name', 'title');
var fieldInfo = searchMeta.parseExpr(ctrl.expr);
ctrl.path = fieldInfo.path + fieldInfo.suffix;
ctrl.field = fieldInfo.field;
};
function initFunction() {
- ctrl.fnInfo = _.find(CRM.vars.search.functions, {name: ctrl.fn});
+ ctrl.fnInfo = _.find(CRM.searchAdmin.functions, {name: ctrl.fn});
if (ctrl.fnInfo && _.includes(ctrl.fnInfo.params[0].prefix, 'DISTINCT')) {
ctrl.modifierAllowed = true;
}