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