Merge pull request #17817 from colemanw/getChecksConfig
[civicrm-core.git] / Civi / Api4 / Generic / AbstractGetAction.php
CommitLineData
19b53e5b
C
1<?php
2
380f3545
TO
3/*
4 +--------------------------------------------------------------------+
41498ac5 5 | Copyright CiviCRM LLC. All rights reserved. |
380f3545 6 | |
41498ac5
TO
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
380f3545
TO
10 +--------------------------------------------------------------------+
11 */
12
13/**
14 *
15 * @package CRM
ca5cec67 16 * @copyright CiviCRM LLC https://civicrm.org/licensing
380f3545
TO
17 */
18
19
19b53e5b
C
20namespace Civi\Api4\Generic;
21
39e0f675
CW
22use Civi\Api4\Utils\SelectUtil;
23
19b53e5b 24/**
fc95d9a5 25 * Base class for all `Get` api actions.
19b53e5b
C
26 *
27 * @package Civi\Api4\Generic
28 *
121ec912 29 * @method $this setSelect(array $selects) Set array of fields to be selected (wildcard * allowed)
19b53e5b
C
30 * @method array getSelect()
31 */
32abstract class AbstractGetAction extends AbstractQueryAction {
33
34 /**
fc95d9a5 35 * Fields to return for each $ENTITY. Defaults to all fields `[*]`.
39e0f675
CW
36 *
37 * Use the * wildcard by itself to select all available fields, or use it to match similarly-named fields.
136ca5bb 38 * E.g. `is_*` will match fields named is_primary, is_active, etc.
19b53e5b 39 *
e3c6d5ff 40 * Set to `["row_count"]` to return only the number of $ENTITIES found.
19b53e5b
C
41 *
42 * @var array
43 */
44 protected $select = [];
45
46 /**
47 * Only return the number of found items.
48 *
49 * @return $this
50 */
51 public function selectRowCount() {
52 $this->select = ['row_count'];
53 return $this;
54 }
55
56 /**
57 * Adds field defaults to the where clause.
58 *
59 * Note: it will skip adding field defaults when fetching records by id,
60 * or if that field has already been added to the where clause.
61 *
62 * @throws \API_Exception
63 */
64 protected function setDefaultWhereClause() {
65 if (!$this->_itemsToGet('id')) {
66 $fields = $this->entityFields();
67 foreach ($fields as $field) {
68 if (isset($field['default_value']) && !$this->_whereContains($field['name'])) {
69 $this->addWhere($field['name'], '=', $field['default_value']);
70 }
71 }
72 }
73 }
74
39e0f675
CW
75 /**
76 * Adds all fields matched by the * wildcard
77 *
78 * @throws \API_Exception
79 */
80 protected function expandSelectClauseWildcards() {
b0932d1e 81 $wildFields = array_filter($this->select, function($item) {
f0acec37 82 return strpos($item, '*') !== FALSE && strpos($item, '.') === FALSE && strpos($item, '(') === FALSE && strpos($item, ' ') === FALSE;
b0932d1e
CW
83 });
84 foreach ($wildFields as $item) {
85 $pos = array_search($item, array_values($this->select));
86 $matches = SelectUtil::getMatchingFields($item, array_column($this->entityFields(), 'name'));
87 array_splice($this->select, $pos, 1, $matches);
39e0f675 88 }
b0932d1e 89 $this->select = array_unique($this->select);
39e0f675
CW
90 }
91
19b53e5b
C
92 /**
93 * Helper to parse the WHERE param for getRecords to perform simple pre-filtering.
94 *
95 * This is intended to optimize some common use-cases e.g. calling the api to get
96 * one or more records by name or id.
97 *
98 * Ex: If getRecords fetches a long list of items each with a unique name,
99 * but the user has specified a single record to retrieve, you can optimize the call
136ca5bb 100 * by checking `$this->_itemsToGet('name')` and only fetching the item(s) with that name.
19b53e5b
C
101 *
102 * @param string $field
103 * @return array|null
104 */
105 protected function _itemsToGet($field) {
106 foreach ($this->where as $clause) {
107 // Look for exact-match operators (=, IN, or LIKE with no wildcard)
108 if ($clause[0] == $field && (in_array($clause[1], ['=', 'IN']) || ($clause[1] == 'LIKE' && !(is_string($clause[2]) && strpos($clause[2], '%') !== FALSE)))) {
109 return (array) $clause[2];
110 }
111 }
112 return NULL;
113 }
114
115 /**
07d6d25b 116 * Helper to see if field(s) should be selected by the getRecords function.
19b53e5b
C
117 *
118 * Checks the SELECT, WHERE and ORDER BY params to see what fields are needed.
119 *
120 * Note that if no SELECT clause has been set then all fields should be selected
961e974c 121 * and this function will return TRUE for field expressions that don't contain a :pseudoconstant suffix.
19b53e5b 122 *
07d6d25b
CW
123 * @param string ...$fieldNames
124 * One or more field names to check (uses OR if multiple)
19b53e5b 125 * @return bool
07d6d25b 126 * Returns true if any given fields are in use.
19b53e5b 127 */
07d6d25b 128 protected function _isFieldSelected(string ...$fieldNames) {
961e974c 129 if ((!$this->select && strpos($fieldNames[0], ':') === FALSE) || array_intersect($fieldNames, array_merge($this->select, array_keys($this->orderBy)))) {
19b53e5b
C
130 return TRUE;
131 }
07d6d25b 132 return $this->_whereContains($fieldNames);
19b53e5b
C
133 }
134
135 /**
07d6d25b 136 * Walk through the where clause and check if field(s) are in use.
19b53e5b 137 *
07d6d25b
CW
138 * @param string|array $fieldName
139 * A single fieldName or an array of names (uses OR if multiple)
19b53e5b
C
140 * @param array $clauses
141 * @return bool
07d6d25b 142 * Returns true if any given fields are found in the where clause.
19b53e5b 143 */
07d6d25b 144 protected function _whereContains($fieldName, $clauses = NULL) {
19b53e5b
C
145 if ($clauses === NULL) {
146 $clauses = $this->where;
147 }
07d6d25b 148 $fieldName = (array) $fieldName;
19b53e5b
C
149 foreach ($clauses as $clause) {
150 if (is_array($clause) && is_string($clause[0])) {
07d6d25b 151 if (in_array($clause[0], $fieldName)) {
19b53e5b
C
152 return TRUE;
153 }
154 elseif (is_array($clause[1])) {
07d6d25b 155 return $this->_whereContains($fieldName, $clause[1]);
19b53e5b
C
156 }
157 }
158 }
159 return FALSE;
160 }
161
121ec912
CW
162 /**
163 * Add one or more fields to be selected (wildcard * allowed)
164 * @param string ...$fieldNames
165 * @return $this
166 */
167 public function addSelect(string ...$fieldNames) {
168 $this->select = array_merge($this->select, $fieldNames);
169 return $this;
170 }
171
19b53e5b 172}