Merge pull request #23352 from eileenmcnaughton/leg
[civicrm-core.git] / Civi / Api4 / Generic / AbstractGetAction.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
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 |
10 +--------------------------------------------------------------------+
11 */
12
13 namespace Civi\Api4\Generic;
14
15 /**
16 * Base class for all `Get` api actions.
17 *
18 * @package Civi\Api4\Generic
19 */
20 abstract class AbstractGetAction extends AbstractQueryAction {
21
22 use Traits\SelectParamTrait;
23
24 /**
25 * Only return the number of found items.
26 *
27 * @return $this
28 */
29 public function selectRowCount() {
30 $this->select = ['row_count'];
31 return $this;
32 }
33
34 /**
35 * Adds field defaults to the where clause.
36 *
37 * Note: it will skip adding field defaults when fetching records by id,
38 * or if that field has already been added to the where clause.
39 *
40 * @throws \API_Exception
41 */
42 protected function setDefaultWhereClause() {
43 if (!$this->_itemsToGet('id')) {
44 $fields = $this->entityFields();
45 foreach ($fields as $field) {
46 if (isset($field['default_value']) && !$this->_whereContains($field['name'])) {
47 $this->addWhere($field['name'], '=', $field['default_value']);
48 }
49 }
50 }
51 }
52
53 /**
54 * Helper to parse the WHERE param for getRecords to perform simple pre-filtering.
55 *
56 * This is intended to optimize some common use-cases e.g. calling the api to get
57 * one or more records by name or id.
58 *
59 * Ex: If getRecords fetches a long list of items each with a unique name,
60 * but the user has specified a single record to retrieve, you can optimize the call
61 * by checking `$this->_itemsToGet('name')` and only fetching the item(s) with that name.
62 *
63 * @param string $field
64 * @return array|null
65 */
66 protected function _itemsToGet($field) {
67 foreach ($this->where as $clause) {
68 // Look for exact-match operators (=, IN, or LIKE with no wildcard)
69 if ($clause[0] == $field && (in_array($clause[1], ['=', 'IN'], TRUE) || ($clause[1] == 'LIKE' && !(is_string($clause[2]) && strpos($clause[2], '%') !== FALSE)))) {
70 return (array) $clause[2];
71 }
72 }
73 return NULL;
74 }
75
76 /**
77 * Helper to see if field(s) should be selected by the getRecords function.
78 *
79 * Checks the SELECT, WHERE and ORDER BY params to see what fields are needed.
80 *
81 * Note that if no SELECT clause has been set then all fields should be selected
82 * and this function will return TRUE for field expressions that don't contain a :pseudoconstant suffix.
83 *
84 * @param string ...$fieldNames
85 * One or more field names to check (uses OR if multiple)
86 * @return bool
87 * Returns true if any given fields are in use.
88 */
89 protected function _isFieldSelected(string ...$fieldNames) {
90 if ((!$this->select && strpos($fieldNames[0], ':') === FALSE) || array_intersect($fieldNames, array_merge($this->select, array_keys($this->orderBy)))) {
91 return TRUE;
92 }
93 return $this->_whereContains($fieldNames);
94 }
95
96 /**
97 * Walk through the where clause and check if field(s) are in use.
98 *
99 * @param string|array $fieldName
100 * A single fieldName or an array of names (uses OR if multiple)
101 * @param array $clauses
102 * @return bool
103 * Returns true if any given fields are found in the where clause.
104 */
105 protected function _whereContains($fieldName, $clauses = NULL) {
106 if ($clauses === NULL) {
107 $clauses = $this->where;
108 }
109 $fieldName = (array) $fieldName;
110 foreach ($clauses as $clause) {
111 if (is_array($clause) && is_string($clause[0])) {
112 if (in_array($clause[0], $fieldName)) {
113 return TRUE;
114 }
115 elseif (is_array($clause[1])) {
116 return $this->_whereContains($fieldName, $clause[1]);
117 }
118 }
119 }
120 return FALSE;
121 }
122
123 }