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