Commit | Line | Data |
---|---|---|
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 |
13 | namespace Civi\Api4\Generic; |
14 | ||
3c7c8fa6 | 15 | use Civi\Api4\Query\Api4SelectQuery; |
9d2afe25 | 16 | use 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 | */ |
28 | class DAOGetAction extends AbstractGetAction { | |
29 | use Traits\DAOActionTrait; | |
30 | ||
39e0f675 | 31 | /** |
60a62215 | 32 | * Fields to return. Defaults to all standard (non-custom, non-extra) fields `['*']`. |
2f69b203 | 33 | * |
d836e5b3 AS |
34 | * The keyword `"custom.*"` selects all custom fields (except those belonging to multi-record custom field sets). So to select all standard + custom fields, select `['*', 'custom.*']`. |
35 | * | |
36 | * Multi-record custom field sets are represented as their own entity, so join to that entity to get those custom fields. | |
39e0f675 | 37 | * |
fc95d9a5 | 38 | * Use the dot notation to perform joins in the select clause, e.g. selecting `['*', 'contact.*']` from `Email::get()` |
39e0f675 CW |
39 | * will select all fields for the email + all fields for the related contact. |
40 | * | |
41 | * @var array | |
42 | * @inheritDoc | |
43 | */ | |
44 | protected $select = []; | |
45 | ||
16f5a13d CW |
46 | /** |
47 | * Joins to other entities. | |
48 | * | |
90908aac CW |
49 | * Each join is an array of properties: |
50 | * | |
51 | * ``` | |
52 | * [Entity, Required, Bridge, [field, op, value]...] | |
53 | * ``` | |
54 | * | |
55 | * - `Entity`: the name of the api entity to join onto. | |
56 | * - `Required`: `TRUE` for an `INNER JOIN`, `FALSE` for a `LEFT JOIN`. | |
465bc32a | 57 | * - `Bridge` (optional): Name of a Bridge to incorporate into the join. |
90908aac CW |
58 | * - `[field, op, value]...`: zero or more conditions for the ON clause, using the same nested format as WHERE and HAVING |
59 | * but with the difference that "value" is interpreted as an expression (e.g. can be the name of a field). | |
60 | * Enclose literal values with quotes. | |
61 | * | |
16f5a13d | 62 | * @var array |
465bc32a | 63 | * @see \Civi\Api4\Generic\Traits\EntityBridge |
16f5a13d CW |
64 | */ |
65 | protected $join = []; | |
66 | ||
f0acec37 CW |
67 | /** |
68 | * Field(s) by which to group the results. | |
69 | * | |
70 | * @var array | |
71 | */ | |
72 | protected $groupBy = []; | |
73 | ||
74 | /** | |
75 | * Clause for filtering results after grouping and filters are applied. | |
76 | * | |
77 | * Each expression should correspond to an item from the SELECT array. | |
78 | * | |
79 | * @var array | |
80 | */ | |
81 | protected $having = []; | |
82 | ||
44a3178f EM |
83 | /** |
84 | * @throws \API_Exception | |
85 | * @throws \CRM_Core_Exception | |
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(); | |
44a3178f EM |
90 | if (!$baoName) { |
91 | // In some cases (eg. site spin-up) the code may attempt to call the api before the entity name is registered. | |
92 | throw new \API_Exception("BAO for {$this->getEntityName()} is not available. This could be a load-order issue"); | |
93 | } | |
06f83d5c | 94 | if (!$baoName::tableHasBeenAdded()) { |
3519db92 | 95 | \Civi::log()->warning("Could not read from {$this->getEntityName()} before table has been added. Upgrade required.", ['civi.tag' => 'upgrade_needed']); |
06f83d5c CW |
96 | return; |
97 | } | |
98 | ||
19b53e5b | 99 | $this->setDefaultWhereClause(); |
39e0f675 | 100 | $this->expandSelectClauseWildcards(); |
651c4c95 | 101 | $this->getObjects($result); |
19b53e5b C |
102 | } |
103 | ||
3c7c8fa6 | 104 | /** |
651c4c95 | 105 | * @param \Civi\Api4\Generic\Result $result |
3c7c8fa6 | 106 | */ |
651c4c95 CW |
107 | protected function getObjects(Result $result) { |
108 | $getCount = in_array('row_count', $this->getSelect()); | |
109 | $onlyCount = $this->getSelect() === ['row_count']; | |
110 | ||
111 | if (!$onlyCount) { | |
112 | $query = new Api4SelectQuery($this); | |
113 | $rows = $query->run(); | |
114 | \CRM_Utils_API_HTMLInputCoder::singleton()->decodeRows($rows); | |
115 | $result->exchangeArray($rows); | |
116 | // No need to fetch count if we got a result set below the limit | |
117 | if (!$this->getLimit() || count($rows) < $this->getLimit()) { | |
118 | $result->rowCount = count($rows) + $this->getOffset(); | |
119 | $getCount = FALSE; | |
120 | } | |
121 | } | |
122 | if ($getCount) { | |
123 | $query = new Api4SelectQuery($this); | |
124 | $result->rowCount = $query->getCount(); | |
3c7c8fa6 | 125 | } |
3c7c8fa6 CW |
126 | } |
127 | ||
1f76bc10 PF |
128 | /** |
129 | * @param string $fieldName | |
130 | * @param string $op | |
131 | * @param mixed $value | |
132 | * @param bool $isExpression | |
133 | * @return $this | |
134 | * @throws \API_Exception | |
135 | */ | |
136 | public function addWhere(string $fieldName, string $op, $value = NULL, bool $isExpression = FALSE) { | |
137 | if (!in_array($op, CoreUtil::getOperators())) { | |
138 | throw new \API_Exception('Unsupported operator'); | |
139 | } | |
140 | $this->where[] = [$fieldName, $op, $value, $isExpression]; | |
141 | return $this; | |
142 | } | |
143 | ||
f0acec37 CW |
144 | /** |
145 | * @return array | |
146 | */ | |
147 | public function getGroupBy(): array { | |
148 | return $this->groupBy; | |
149 | } | |
150 | ||
151 | /** | |
152 | * @param array $groupBy | |
153 | * @return $this | |
154 | */ | |
155 | public function setGroupBy(array $groupBy) { | |
156 | $this->groupBy = $groupBy; | |
157 | return $this; | |
158 | } | |
159 | ||
160 | /** | |
161 | * @param string $field | |
162 | * @return $this | |
163 | */ | |
164 | public function addGroupBy(string $field) { | |
165 | $this->groupBy[] = $field; | |
166 | return $this; | |
167 | } | |
168 | ||
169 | /** | |
170 | * @param string $expr | |
171 | * @param string $op | |
172 | * @param mixed $value | |
173 | * @return $this | |
174 | * @throws \API_Exception | |
175 | */ | |
176 | public function addHaving(string $expr, string $op, $value = NULL) { | |
9d2afe25 | 177 | if (!in_array($op, CoreUtil::getOperators())) { |
f0acec37 CW |
178 | throw new \API_Exception('Unsupported operator'); |
179 | } | |
180 | $this->having[] = [$expr, $op, $value]; | |
181 | return $this; | |
182 | } | |
183 | ||
16f5a13d CW |
184 | /** |
185 | * @param string $entity | |
266e8deb | 186 | * @param string|bool $type |
90908aac | 187 | * @param string $bridge |
16f5a13d CW |
188 | * @param array ...$conditions |
189 | * @return DAOGetAction | |
190 | */ | |
266e8deb | 191 | public function addJoin(string $entity, $type = 'LEFT', $bridge = NULL, ...$conditions): DAOGetAction { |
90908aac CW |
192 | if ($bridge) { |
193 | array_unshift($conditions, $bridge); | |
194 | } | |
266e8deb | 195 | array_unshift($conditions, $entity, $type); |
16f5a13d CW |
196 | $this->join[] = $conditions; |
197 | return $this; | |
198 | } | |
199 | ||
200 | /** | |
201 | * @param array $join | |
202 | * @return DAOGetAction | |
203 | */ | |
204 | public function setJoin(array $join): DAOGetAction { | |
205 | $this->join = $join; | |
206 | return $this; | |
207 | } | |
208 | ||
209 | /** | |
210 | * @return array | |
211 | */ | |
212 | public function getJoin(): array { | |
213 | return $this->join; | |
214 | } | |
215 | ||
19b53e5b | 216 | } |