Merge pull request #18148 from civicrm/5.29
[civicrm-core.git] / Civi / Api4 / Generic / DAOGetAction.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
3c7c8fa6
CW
22use Civi\Api4\Query\Api4SelectQuery;
23
19b53e5b 24/**
e3c6d5ff 25 * Retrieve $ENTITIES based on criteria specified in the `where` parameter.
19b53e5b 26 *
fc95d9a5 27 * Use the `select` param to determine which fields are returned, defaults to `[*]`.
19b53e5b
C
28 *
29 * Perform joins on other related entities using a dot notation.
c9e3ae2e
CW
30 *
31 * @method $this setHaving(array $clauses)
32 * @method array getHaving()
19b53e5b
C
33 */
34class DAOGetAction extends AbstractGetAction {
35 use Traits\DAOActionTrait;
36
39e0f675 37 /**
2f69b203
CW
38 * Fields to return. Defaults to all non-custom fields `['*']`.
39 *
40 * The keyword `"custom.*"` selects all custom fields. So to select all core + custom fields, select `['*', 'custom.*']`.
39e0f675 41 *
fc95d9a5 42 * Use the dot notation to perform joins in the select clause, e.g. selecting `['*', 'contact.*']` from `Email::get()`
39e0f675
CW
43 * will select all fields for the email + all fields for the related contact.
44 *
45 * @var array
46 * @inheritDoc
47 */
48 protected $select = [];
49
16f5a13d
CW
50 /**
51 * Joins to other entities.
52 *
90908aac
CW
53 * Each join is an array of properties:
54 *
55 * ```
56 * [Entity, Required, Bridge, [field, op, value]...]
57 * ```
58 *
59 * - `Entity`: the name of the api entity to join onto.
60 * - `Required`: `TRUE` for an `INNER JOIN`, `FALSE` for a `LEFT JOIN`.
61 * - `Bridge` (optional): Name of a BridgeEntity to incorporate into the join.
62 * - `[field, op, value]...`: zero or more conditions for the ON clause, using the same nested format as WHERE and HAVING
63 * but with the difference that "value" is interpreted as an expression (e.g. can be the name of a field).
64 * Enclose literal values with quotes.
65 *
16f5a13d 66 * @var array
90908aac 67 * @see \Civi\Api4\Generic\BridgeEntity
16f5a13d
CW
68 */
69 protected $join = [];
70
f0acec37
CW
71 /**
72 * Field(s) by which to group the results.
73 *
74 * @var array
75 */
76 protected $groupBy = [];
77
78 /**
79 * Clause for filtering results after grouping and filters are applied.
80 *
81 * Each expression should correspond to an item from the SELECT array.
82 *
83 * @var array
84 */
85 protected $having = [];
86
19b53e5b 87 public function _run(Result $result) {
06f83d5c
CW
88 // Early return if table doesn't exist yet due to pending upgrade
89 $baoName = $this->getBaoName();
90 if (!$baoName::tableHasBeenAdded()) {
3519db92 91 \Civi::log()->warning("Could not read from {$this->getEntityName()} before table has been added. Upgrade required.", ['civi.tag' => 'upgrade_needed']);
06f83d5c
CW
92 return;
93 }
94
19b53e5b 95 $this->setDefaultWhereClause();
39e0f675 96 $this->expandSelectClauseWildcards();
651c4c95 97 $this->getObjects($result);
19b53e5b
C
98 }
99
3c7c8fa6 100 /**
651c4c95 101 * @param \Civi\Api4\Generic\Result $result
3c7c8fa6 102 */
651c4c95
CW
103 protected function getObjects(Result $result) {
104 $getCount = in_array('row_count', $this->getSelect());
105 $onlyCount = $this->getSelect() === ['row_count'];
106
107 if (!$onlyCount) {
108 $query = new Api4SelectQuery($this);
109 $rows = $query->run();
110 \CRM_Utils_API_HTMLInputCoder::singleton()->decodeRows($rows);
111 $result->exchangeArray($rows);
112 // No need to fetch count if we got a result set below the limit
113 if (!$this->getLimit() || count($rows) < $this->getLimit()) {
114 $result->rowCount = count($rows) + $this->getOffset();
115 $getCount = FALSE;
116 }
117 }
118 if ($getCount) {
119 $query = new Api4SelectQuery($this);
120 $result->rowCount = $query->getCount();
3c7c8fa6 121 }
3c7c8fa6
CW
122 }
123
f0acec37
CW
124 /**
125 * @return array
126 */
127 public function getGroupBy(): array {
128 return $this->groupBy;
129 }
130
131 /**
132 * @param array $groupBy
133 * @return $this
134 */
135 public function setGroupBy(array $groupBy) {
136 $this->groupBy = $groupBy;
137 return $this;
138 }
139
140 /**
141 * @param string $field
142 * @return $this
143 */
144 public function addGroupBy(string $field) {
145 $this->groupBy[] = $field;
146 return $this;
147 }
148
149 /**
150 * @param string $expr
151 * @param string $op
152 * @param mixed $value
153 * @return $this
154 * @throws \API_Exception
155 */
156 public function addHaving(string $expr, string $op, $value = NULL) {
157 if (!in_array($op, \CRM_Core_DAO::acceptedSQLOperators())) {
158 throw new \API_Exception('Unsupported operator');
159 }
160 $this->having[] = [$expr, $op, $value];
161 return $this;
162 }
163
16f5a13d
CW
164 /**
165 * @param string $entity
166 * @param bool $required
90908aac 167 * @param string $bridge
16f5a13d
CW
168 * @param array ...$conditions
169 * @return DAOGetAction
170 */
90908aac
CW
171 public function addJoin(string $entity, bool $required = FALSE, $bridge = NULL, ...$conditions): DAOGetAction {
172 if ($bridge) {
173 array_unshift($conditions, $bridge);
174 }
16f5a13d
CW
175 array_unshift($conditions, $entity, $required);
176 $this->join[] = $conditions;
177 return $this;
178 }
179
180 /**
181 * @param array $join
182 * @return DAOGetAction
183 */
184 public function setJoin(array $join): DAOGetAction {
185 $this->join = $join;
186 return $this;
187 }
188
189 /**
190 * @return array
191 */
192 public function getJoin(): array {
193 return $this->join;
194 }
195
19b53e5b 196}