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 | /** |
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 | ||
44a3178f EM |
81 | /** |
82 | * @throws \API_Exception | |
83 | * @throws \CRM_Core_Exception | |
84 | */ | |
19b53e5b | 85 | public function _run(Result $result) { |
06f83d5c CW |
86 | // Early return if table doesn't exist yet due to pending upgrade |
87 | $baoName = $this->getBaoName(); | |
44a3178f EM |
88 | if (!$baoName) { |
89 | // In some cases (eg. site spin-up) the code may attempt to call the api before the entity name is registered. | |
90 | throw new \API_Exception("BAO for {$this->getEntityName()} is not available. This could be a load-order issue"); | |
91 | } | |
06f83d5c | 92 | if (!$baoName::tableHasBeenAdded()) { |
3519db92 | 93 | \Civi::log()->warning("Could not read from {$this->getEntityName()} before table has been added. Upgrade required.", ['civi.tag' => 'upgrade_needed']); |
06f83d5c CW |
94 | return; |
95 | } | |
96 | ||
19b53e5b | 97 | $this->setDefaultWhereClause(); |
39e0f675 | 98 | $this->expandSelectClauseWildcards(); |
651c4c95 | 99 | $this->getObjects($result); |
19b53e5b C |
100 | } |
101 | ||
3c7c8fa6 | 102 | /** |
651c4c95 | 103 | * @param \Civi\Api4\Generic\Result $result |
3c7c8fa6 | 104 | */ |
651c4c95 CW |
105 | protected function getObjects(Result $result) { |
106 | $getCount = in_array('row_count', $this->getSelect()); | |
107 | $onlyCount = $this->getSelect() === ['row_count']; | |
108 | ||
109 | if (!$onlyCount) { | |
110 | $query = new Api4SelectQuery($this); | |
111 | $rows = $query->run(); | |
112 | \CRM_Utils_API_HTMLInputCoder::singleton()->decodeRows($rows); | |
113 | $result->exchangeArray($rows); | |
114 | // No need to fetch count if we got a result set below the limit | |
115 | if (!$this->getLimit() || count($rows) < $this->getLimit()) { | |
116 | $result->rowCount = count($rows) + $this->getOffset(); | |
117 | $getCount = FALSE; | |
118 | } | |
119 | } | |
120 | if ($getCount) { | |
121 | $query = new Api4SelectQuery($this); | |
122 | $result->rowCount = $query->getCount(); | |
3c7c8fa6 | 123 | } |
3c7c8fa6 CW |
124 | } |
125 | ||
1f76bc10 PF |
126 | /** |
127 | * @param string $fieldName | |
128 | * @param string $op | |
129 | * @param mixed $value | |
130 | * @param bool $isExpression | |
131 | * @return $this | |
132 | * @throws \API_Exception | |
133 | */ | |
134 | public function addWhere(string $fieldName, string $op, $value = NULL, bool $isExpression = FALSE) { | |
135 | if (!in_array($op, CoreUtil::getOperators())) { | |
136 | throw new \API_Exception('Unsupported operator'); | |
137 | } | |
138 | $this->where[] = [$fieldName, $op, $value, $isExpression]; | |
139 | return $this; | |
140 | } | |
141 | ||
f0acec37 CW |
142 | /** |
143 | * @return array | |
144 | */ | |
145 | public function getGroupBy(): array { | |
146 | return $this->groupBy; | |
147 | } | |
148 | ||
149 | /** | |
150 | * @param array $groupBy | |
151 | * @return $this | |
152 | */ | |
153 | public function setGroupBy(array $groupBy) { | |
154 | $this->groupBy = $groupBy; | |
155 | return $this; | |
156 | } | |
157 | ||
158 | /** | |
159 | * @param string $field | |
160 | * @return $this | |
161 | */ | |
162 | public function addGroupBy(string $field) { | |
163 | $this->groupBy[] = $field; | |
164 | return $this; | |
165 | } | |
166 | ||
167 | /** | |
168 | * @param string $expr | |
169 | * @param string $op | |
170 | * @param mixed $value | |
171 | * @return $this | |
172 | * @throws \API_Exception | |
173 | */ | |
174 | public function addHaving(string $expr, string $op, $value = NULL) { | |
9d2afe25 | 175 | if (!in_array($op, CoreUtil::getOperators())) { |
f0acec37 CW |
176 | throw new \API_Exception('Unsupported operator'); |
177 | } | |
178 | $this->having[] = [$expr, $op, $value]; | |
179 | return $this; | |
180 | } | |
181 | ||
16f5a13d CW |
182 | /** |
183 | * @param string $entity | |
266e8deb | 184 | * @param string|bool $type |
90908aac | 185 | * @param string $bridge |
16f5a13d CW |
186 | * @param array ...$conditions |
187 | * @return DAOGetAction | |
188 | */ | |
266e8deb | 189 | public function addJoin(string $entity, $type = 'LEFT', $bridge = NULL, ...$conditions): DAOGetAction { |
90908aac CW |
190 | if ($bridge) { |
191 | array_unshift($conditions, $bridge); | |
192 | } | |
266e8deb | 193 | array_unshift($conditions, $entity, $type); |
16f5a13d CW |
194 | $this->join[] = $conditions; |
195 | return $this; | |
196 | } | |
197 | ||
198 | /** | |
199 | * @param array $join | |
200 | * @return DAOGetAction | |
201 | */ | |
202 | public function setJoin(array $join): DAOGetAction { | |
203 | $this->join = $join; | |
204 | return $this; | |
205 | } | |
206 | ||
207 | /** | |
208 | * @return array | |
209 | */ | |
210 | public function getJoin(): array { | |
211 | return $this->join; | |
212 | } | |
213 | ||
19b53e5b | 214 | } |