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