Merge pull request #18554 from civicrm/5.30
[civicrm-core.git] / Civi / Api4 / Generic / AbstractQueryAction.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
9d2afe25
CW
22use Civi\Api4\Utils\CoreUtil;
23
19b53e5b 24/**
fc95d9a5 25 * Base class for all actions that need to fetch records (`Get`, `Update`, `Delete`, etc.).
19b53e5b
C
26 *
27 * @package Civi\Api4\Generic
28 *
29 * @method $this setWhere(array $wheres)
30 * @method array getWhere()
31 * @method $this setOrderBy(array $order)
32 * @method array getOrderBy()
33 * @method $this setLimit(int $limit)
34 * @method int getLimit()
35 * @method $this setOffset(int $offset)
36 * @method int getOffset()
37 */
38abstract class AbstractQueryAction extends AbstractAction {
39
40 /**
e3c6d5ff 41 * Criteria for selecting $ENTITIES.
19b53e5b 42 *
fc95d9a5
CW
43 * ```php
44 * $example->addWhere('contact_type', 'IN', ['Individual', 'Household'])
45 * ```
19b53e5b
C
46 * @var array
47 */
48 protected $where = [];
49
50 /**
fc95d9a5 51 * Array of field(s) to use in ordering the results.
19b53e5b
C
52 *
53 * Defaults to id ASC
54 *
fc95d9a5 55 * ```php
19b53e5b 56 * $example->addOrderBy('sort_name', 'ASC')
fc95d9a5 57 * ```
19b53e5b
C
58 * @var array
59 */
60 protected $orderBy = [];
61
62 /**
e3c6d5ff 63 * Maximum number of $ENTITIES to return.
19b53e5b 64 *
d71cde6c 65 * Defaults to `0` - unlimited.
19b53e5b 66 *
d71cde6c 67 * Note: the Api Explorer sets this to `25` by default to avoid timeouts.
19b53e5b
C
68 * Change or remove this default for your application code.
69 *
70 * @var int
71 */
72 protected $limit = 0;
73
74 /**
fc95d9a5 75 * Zero-based index of first $ENTITY to return.
19b53e5b 76 *
d71cde6c 77 * Defaults to `0` - first $ENTITY found.
19b53e5b
C
78 *
79 * @var int
80 */
81 protected $offset = 0;
82
83 /**
121ec912 84 * @param string $fieldName
19b53e5b
C
85 * @param string $op
86 * @param mixed $value
87 * @return $this
88 * @throws \API_Exception
89 */
121ec912 90 public function addWhere(string $fieldName, string $op, $value = NULL) {
9d2afe25 91 if (!in_array($op, CoreUtil::getOperators())) {
19b53e5b
C
92 throw new \API_Exception('Unsupported operator');
93 }
121ec912 94 $this->where[] = [$fieldName, $op, $value];
19b53e5b
C
95 return $this;
96 }
97
98 /**
99 * Adds one or more AND/OR/NOT clause groups
100 *
101 * @param string $operator
102 * @param mixed $condition1 ... $conditionN
103 * Either a nested array of arguments, or a variable number of arguments passed to this function.
104 *
105 * @return $this
106 * @throws \API_Exception
107 */
121ec912 108 public function addClause(string $operator, $condition1) {
19b53e5b
C
109 if (!is_array($condition1[0])) {
110 $condition1 = array_slice(func_get_args(), 1);
111 }
112 $this->where[] = [$operator, $condition1];
113 return $this;
114 }
115
116 /**
121ec912
CW
117 * Adds to the orderBy clause
118 * @param string $fieldName
19b53e5b
C
119 * @param string $direction
120 * @return $this
121 */
121ec912
CW
122 public function addOrderBy(string $fieldName, $direction = 'ASC') {
123 $this->orderBy[$fieldName] = $direction;
19b53e5b
C
124 return $this;
125 }
126
127 /**
121ec912 128 * Produces a human-readable where clause, for the reading enjoyment of you humans.
19b53e5b
C
129 *
130 * @param array $whereClause
131 * @param string $op
132 * @return string
133 */
134 protected function whereClauseToString($whereClause = NULL, $op = 'AND') {
135 if ($whereClause === NULL) {
136 $whereClause = $this->where;
137 }
138 $output = '';
139 if (!is_array($whereClause) || !$whereClause) {
140 return $output;
141 }
142 if (in_array($whereClause[0], ['AND', 'OR', 'NOT'])) {
143 $op = array_shift($whereClause);
144 if ($op == 'NOT') {
145 $output = 'NOT ';
146 $op = 'AND';
147 }
148 return $output . '(' . $this->whereClauseToString($whereClause, $op) . ')';
149 }
9d2afe25 150 elseif (isset($whereClause[1]) && in_array($whereClause[1], CoreUtil::getOperators())) {
19b53e5b
C
151 $output = $whereClause[0] . ' ' . $whereClause[1] . ' ';
152 if (isset($whereClause[2])) {
153 $output .= is_array($whereClause[2]) ? '[' . implode(', ', $whereClause[2]) . ']' : $whereClause[2];
154 }
155 }
156 else {
157 $clauses = [];
158 foreach (array_filter($whereClause) as $clause) {
159 $clauses[] = $this->whereClauseToString($clause, $op);
160 }
161 $output = implode(" $op ", $clauses);
162 }
163 return $output;
164 }
165
166}