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