Commit | Line | Data |
---|---|---|
8bcc0d86 CW |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
41498ac5 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
8bcc0d86 | 5 | | | |
41498ac5 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
8bcc0d86 CW |
9 | +--------------------------------------------------------------------+ |
10 | */ | |
11 | namespace Civi\API; | |
12 | ||
13 | /** | |
14 | */ | |
15 | class Api3SelectQuery extends SelectQuery { | |
16 | ||
17 | protected $apiVersion = 3; | |
18 | ||
19 | /** | |
20 | * @inheritDoc | |
21 | */ | |
22 | protected function buildWhereClause() { | |
c64f69d9 | 23 | $filters = []; |
8bcc0d86 CW |
24 | foreach ($this->where as $key => $value) { |
25 | $table_name = NULL; | |
26 | $column_name = NULL; | |
27 | ||
28 | if (substr($key, 0, 7) == 'filter.') { | |
29 | // Legacy support for old filter syntax per the test contract. | |
30 | // (Convert the style to the later one & then deal with them). | |
31 | $filterArray = explode('.', $key); | |
c64f69d9 | 32 | $value = [$filterArray[1] => $value]; |
8bcc0d86 CW |
33 | $key = 'filters'; |
34 | } | |
35 | ||
36 | // Legacy support for 'filter's construct. | |
37 | if ($key == 'filters') { | |
38 | foreach ($value as $filterKey => $filterValue) { | |
39 | if (substr($filterKey, -4, 4) == 'high') { | |
40 | $key = substr($filterKey, 0, -5); | |
c64f69d9 | 41 | $value = ['<=' => $filterValue]; |
8bcc0d86 CW |
42 | } |
43 | ||
44 | if (substr($filterKey, -3, 3) == 'low') { | |
45 | $key = substr($filterKey, 0, -4); | |
c64f69d9 | 46 | $value = ['>=' => $filterValue]; |
8bcc0d86 CW |
47 | } |
48 | ||
49 | if ($filterKey == 'is_current' || $filterKey == 'isCurrent') { | |
50 | // Is current is almost worth creating as a 'sql filter' in the DAO function since several entities have the concept. | |
51 | $todayStart = date('Ymd000000', strtotime('now')); | |
52 | $todayEnd = date('Ymd235959', strtotime('now')); | |
53 | $a = self::MAIN_TABLE_ALIAS; | |
54 | $this->query->where("($a.start_date <= '$todayStart' OR $a.start_date IS NULL) | |
55 | AND ($a.end_date >= '$todayEnd' OR $a.end_date IS NULL) | |
56 | AND a.is_active = 1"); | |
57 | } | |
58 | } | |
59 | } | |
60 | // Ignore the "options" param if it is referring to api options and not a field in this entity | |
61 | if ( | |
62 | $key === 'options' && is_array($value) | |
63 | && !in_array(\CRM_Utils_Array::first(array_keys($value)), \CRM_Core_DAO::acceptedSQLOperators()) | |
64 | ) { | |
65 | continue; | |
66 | } | |
67 | $field = $this->getField($key); | |
68 | if ($field) { | |
69 | $key = $field['name']; | |
70 | } | |
71 | if (in_array($key, $this->entityFieldNames)) { | |
72 | $table_name = self::MAIN_TABLE_ALIAS; | |
73 | $column_name = $key; | |
74 | } | |
75 | elseif (($cf_id = \CRM_Core_BAO_CustomField::getKeyID($key)) != FALSE) { | |
23a57f3b JV |
76 | // If we check a custom field on 'IS NULL', it should also work when there is no |
77 | // record in the custom value table, see CRM-20740. | |
ada40b3e | 78 | $side = empty($value['IS NULL']) ? 'INNER' : 'LEFT OUTER'; |
23a57f3b | 79 | list($table_name, $column_name) = $this->addCustomField($this->apiFieldSpec['custom_' . $cf_id], $side); |
8bcc0d86 CW |
80 | } |
81 | elseif (strpos($key, '.')) { | |
82 | $fkInfo = $this->addFkField($key, 'INNER'); | |
83 | if ($fkInfo) { | |
84 | list($table_name, $column_name) = $fkInfo; | |
85 | $this->validateNestedInput($key, $value); | |
86 | } | |
87 | } | |
88 | // I don't know why I had to specifically exclude 0 as a key - wouldn't the others have caught it? | |
89 | // We normally silently ignore null values passed in - if people want IS_NULL they can use acceptedSqlOperator syntax. | |
90 | if ((!$table_name) || empty($key) || is_null($value)) { | |
91 | // No valid filter field. This might be a chained call or something. | |
92 | // Just ignore this for the $where_clause. | |
93 | continue; | |
94 | } | |
fe59b2a7 | 95 | $operator = is_array($value) ? \CRM_Utils_Array::first(array_keys($value)) : NULL; |
17e0598e | 96 | if (!in_array($operator, \CRM_Core_DAO::acceptedSQLOperators(), TRUE)) { |
c64f69d9 | 97 | $value = ['=' => $value]; |
8bcc0d86 | 98 | } |
fe59b2a7 CW |
99 | $filters[$key] = \CRM_Core_DAO::createSQLFilter("{$table_name}.{$column_name}", $value); |
100 | } | |
101 | // Support OR groups | |
102 | if (!empty($this->where['options']['or'])) { | |
103 | $orGroups = $this->where['options']['or']; | |
104 | if (is_string($orGroups)) { | |
105 | $orGroups = array_map('trim', explode(',', $orGroups)); | |
106 | } | |
107 | if (!is_array(\CRM_Utils_Array::first($orGroups))) { | |
c64f69d9 | 108 | $orGroups = [$orGroups]; |
fe59b2a7 CW |
109 | } |
110 | foreach ($orGroups as $orGroup) { | |
c64f69d9 | 111 | $orClause = []; |
fe59b2a7 CW |
112 | foreach ($orGroup as $key) { |
113 | if (!isset($filters[$key])) { | |
114 | throw new \CiviCRM_API3_Exception("'$key' specified in OR group but not added to params"); | |
115 | } | |
116 | $orClause[] = $filters[$key]; | |
117 | unset($filters[$key]); | |
8bcc0d86 | 118 | } |
fe59b2a7 | 119 | $this->query->where(implode(' OR ', $orClause)); |
8bcc0d86 CW |
120 | } |
121 | } | |
fe59b2a7 CW |
122 | // Add the remaining params using AND |
123 | foreach ($filters as $filter) { | |
124 | $this->query->where($filter); | |
125 | } | |
8bcc0d86 CW |
126 | } |
127 | ||
128 | /** | |
129 | * @inheritDoc | |
130 | */ | |
131 | protected function getFields() { | |
132 | require_once 'api/v3/Generic.php'; | |
133 | // Call this function directly instead of using the api wrapper to force unique field names off | |
c64f69d9 | 134 | $apiSpec = \civicrm_api3_generic_getfields([ |
8bcc0d86 CW |
135 | 'entity' => $this->entity, |
136 | 'version' => 3, | |
c64f69d9 CW |
137 | 'params' => ['action' => 'get'], |
138 | ], FALSE); | |
8bcc0d86 CW |
139 | return $apiSpec['values']; |
140 | } | |
141 | ||
142 | /** | |
143 | * Fetch a field from the getFields list | |
144 | * | |
145 | * Searches by name, uniqueName, and api.aliases | |
066c4638 TO |
146 | * |
147 | * @param string $fieldName | |
148 | * Field name. | |
149 | * @return NULL|mixed | |
8bcc0d86 CW |
150 | */ |
151 | protected function getField($fieldName) { | |
152 | if (!$fieldName) { | |
153 | return NULL; | |
154 | } | |
155 | if (isset($this->apiFieldSpec[$fieldName])) { | |
156 | return $this->apiFieldSpec[$fieldName]; | |
157 | } | |
158 | foreach ($this->apiFieldSpec as $field) { | |
159 | if ( | |
160 | $fieldName == \CRM_Utils_Array::value('uniqueName', $field) || | |
c64f69d9 | 161 | array_search($fieldName, \CRM_Utils_Array::value('api.aliases', $field, [])) !== FALSE |
8bcc0d86 CW |
162 | ) { |
163 | return $field; | |
164 | } | |
165 | } | |
166 | return NULL; | |
167 | } | |
168 | ||
169 | } |