Commit | Line | Data |
---|---|---|
6a488035 | 1 | <?php |
6a488035 TO |
2 | /* |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 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 | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * | |
15 | * @package CRM | |
ca5cec67 | 16 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
17 | */ |
18 | class CRM_Core_BAO_CustomQuery { | |
7da04cde | 19 | const PREFIX = 'custom_value_'; |
6a488035 TO |
20 | |
21 | /** | |
d2e5d2ce | 22 | * The set of custom field ids. |
6a488035 TO |
23 | * |
24 | * @var array | |
25 | */ | |
26 | protected $_ids; | |
27 | ||
28 | /** | |
d2e5d2ce | 29 | * The select clause. |
6a488035 TO |
30 | * |
31 | * @var array | |
32 | */ | |
33 | public $_select; | |
34 | ||
35 | /** | |
d2e5d2ce | 36 | * The name of the elements that are in the select clause. |
6a488035 TO |
37 | * used to extract the values |
38 | * | |
39 | * @var array | |
40 | */ | |
41 | public $_element; | |
42 | ||
43 | /** | |
d2e5d2ce | 44 | * The tables involved in the query. |
6a488035 TO |
45 | * |
46 | * @var array | |
47 | */ | |
48 | public $_tables; | |
49 | public $_whereTables; | |
50 | ||
51 | /** | |
d2e5d2ce | 52 | * The where clause. |
6a488035 TO |
53 | * |
54 | * @var array | |
55 | */ | |
56 | public $_where; | |
57 | ||
58 | /** | |
d2e5d2ce | 59 | * The english language version of the query. |
6a488035 TO |
60 | * |
61 | * @var array | |
62 | */ | |
63 | public $_qill; | |
64 | ||
65 | /** | |
b4fb2d23 | 66 | * No longer needed due to CRM-17646 refactoring, but still used in some places |
6a488035 TO |
67 | * |
68 | * @var array | |
518fa0ee | 69 | * @deprecated |
6a488035 TO |
70 | */ |
71 | public $_options; | |
72 | ||
73 | /** | |
d2e5d2ce | 74 | * The custom fields information. |
6a488035 TO |
75 | * |
76 | * @var array | |
77 | */ | |
78 | public $_fields; | |
79 | ||
acd6c6ab | 80 | /** |
81 | * @return array | |
82 | */ | |
83 | public function getFields() { | |
84 | return $this->_fields; | |
85 | } | |
86 | ||
6a488035 TO |
87 | /** |
88 | * Searching for contacts? | |
89 | * | |
d51c6add | 90 | * @var bool |
6a488035 TO |
91 | */ |
92 | protected $_contactSearch; | |
93 | ||
247ad911 | 94 | protected $_locationSpecificCustomFields; |
442df34b | 95 | |
6a488035 | 96 | /** |
d2e5d2ce | 97 | * This stores custom data group types and tables that it extends. |
6a488035 TO |
98 | * |
99 | * @var array | |
6a488035 | 100 | */ |
518fa0ee | 101 | public static $extendsMap = [ |
6a488035 TO |
102 | 'Contact' => 'civicrm_contact', |
103 | 'Individual' => 'civicrm_contact', | |
104 | 'Household' => 'civicrm_contact', | |
105 | 'Organization' => 'civicrm_contact', | |
106 | 'Contribution' => 'civicrm_contribution', | |
95974e8e | 107 | 'ContributionRecur' => 'civicrm_contribution_recur', |
6a488035 TO |
108 | 'Membership' => 'civicrm_membership', |
109 | 'Participant' => 'civicrm_participant', | |
110 | 'Group' => 'civicrm_group', | |
111 | 'Relationship' => 'civicrm_relationship', | |
112 | 'Event' => 'civicrm_event', | |
113 | 'Case' => 'civicrm_case', | |
114 | 'Activity' => 'civicrm_activity', | |
115 | 'Pledge' => 'civicrm_pledge', | |
116 | 'Grant' => 'civicrm_grant', | |
117 | 'Address' => 'civicrm_address', | |
5b37ca7b EM |
118 | 'Campaign' => 'civicrm_campaign', |
119 | 'Survey' => 'civicrm_survey', | |
be2fb01f | 120 | ]; |
6a488035 TO |
121 | |
122 | /** | |
d2e5d2ce | 123 | * Class constructor. |
6a488035 TO |
124 | * |
125 | * Takes in a set of custom field ids andsets up the data structures to | |
126 | * generate a query | |
127 | * | |
6a0b768e TO |
128 | * @param array $ids |
129 | * The set of custom field ids. | |
fd31fa4c EM |
130 | * |
131 | * @param bool $contactSearch | |
132 | * @param array $locationSpecificFields | |
442df34b | 133 | */ |
be2fb01f | 134 | public function __construct($ids, $contactSearch = FALSE, $locationSpecificFields = []) { |
688e7a0d | 135 | $this->_ids = $ids; |
247ad911 | 136 | $this->_locationSpecificCustomFields = $locationSpecificFields; |
6a488035 | 137 | |
be2fb01f CW |
138 | $this->_select = []; |
139 | $this->_element = []; | |
140 | $this->_tables = []; | |
141 | $this->_whereTables = []; | |
142 | $this->_where = []; | |
143 | $this->_qill = []; | |
144 | $this->_options = []; | |
6a488035 | 145 | |
6a488035 | 146 | $this->_contactSearch = $contactSearch; |
1f61a7b1 | 147 | $this->_fields = CRM_Core_BAO_CustomField::getFields('ANY', FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE); |
6a488035 TO |
148 | |
149 | if (empty($this->_ids)) { | |
150 | return; | |
151 | } | |
152 | ||
153 | // initialize the field array | |
154 | $tmpArray = array_keys($this->_ids); | |
155 | $idString = implode(',', $tmpArray); | |
353ffa53 | 156 | $query = " |
6a488035 TO |
157 | SELECT f.id, f.label, f.data_type, |
158 | f.html_type, f.is_search_range, | |
159 | f.option_group_id, f.custom_group_id, | |
160 | f.column_name, g.table_name, | |
161 | f.date_format,f.time_format | |
162 | FROM civicrm_custom_field f, | |
163 | civicrm_custom_group g | |
164 | WHERE f.custom_group_id = g.id | |
165 | AND g.is_active = 1 | |
166 | AND f.is_active = 1 | |
167 | AND f.id IN ( $idString )"; | |
168 | ||
169 | $dao = CRM_Core_DAO::executeQuery($query); | |
170 | while ($dao->fetch()) { | |
b4fb2d23 | 171 | // Deprecated (and poorly named) cache of field attributes |
be2fb01f CW |
172 | $this->_options[$dao->id] = [ |
173 | 'attributes' => [ | |
b4fb2d23 CW |
174 | 'label' => $dao->label, |
175 | 'data_type' => $dao->data_type, | |
176 | 'html_type' => $dao->html_type, | |
be2fb01f CW |
177 | ], |
178 | ]; | |
75cda526 | 179 | |
be2fb01f | 180 | $options = CRM_Core_PseudoConstant::get('CRM_Core_BAO_CustomField', 'custom_' . $dao->id, [], 'search'); |
75cda526 CW |
181 | if ($options) { |
182 | $this->_options[$dao->id] += $options; | |
183 | } | |
6a488035 | 184 | |
b4fb2d23 | 185 | if ($dao->html_type == 'Select Date') { |
6a488035 TO |
186 | $this->_options[$dao->id]['attributes']['date_format'] = $dao->date_format; |
187 | $this->_options[$dao->id]['attributes']['time_format'] = $dao->time_format; | |
188 | } | |
6a488035 TO |
189 | } |
190 | } | |
191 | ||
192 | /** | |
d2e5d2ce | 193 | * Generate the select clause and the associated tables. |
6a488035 | 194 | */ |
00be9182 | 195 | public function select() { |
6a488035 TO |
196 | if (empty($this->_fields)) { |
197 | return; | |
198 | } | |
199 | ||
697aad03 | 200 | foreach (array_keys($this->_ids) as $id) { |
494d81e9 SL |
201 | // Ignore any custom field ids within the ids array that are not present in the fields array. |
202 | if (empty($this->_fields[$id])) { | |
203 | continue; | |
204 | } | |
697aad03 | 205 | $field = $this->_fields[$id]; |
f2d54c7b | 206 | |
207 | if ($this->_contactSearch && $field['search_table'] === 'contact_a') { | |
208 | CRM_Contact_BAO_Query::$_openedPanes[ts('Custom Fields')] = TRUE; | |
209 | } | |
210 | ||
6a488035 TO |
211 | $name = $field['table_name']; |
212 | $fieldName = 'custom_' . $field['id']; | |
213 | $this->_select["{$name}_id"] = "{$name}.id as {$name}_id"; | |
214 | $this->_element["{$name}_id"] = 1; | |
215 | $this->_select[$fieldName] = "{$field['table_name']}.{$field['column_name']} as $fieldName"; | |
216 | $this->_element[$fieldName] = 1; | |
dcf0d348 | 217 | |
7f175707 | 218 | $this->joinCustomTableForField($field); |
6a488035 TO |
219 | } |
220 | } | |
221 | ||
222 | /** | |
192d36c5 | 223 | * Generate the where clause and also the english language equivalent. |
410e3761 | 224 | * |
225 | * @throws \CRM_Core_Exception | |
6a488035 | 226 | */ |
00be9182 | 227 | public function where() { |
6a488035 TO |
228 | foreach ($this->_ids as $id => $values) { |
229 | ||
192d36c5 | 230 | // Fixed for Issue CRM 607 |
6a488035 TO |
231 | if (CRM_Utils_Array::value($id, $this->_fields) === NULL || |
232 | !$values | |
233 | ) { | |
234 | continue; | |
235 | } | |
236 | ||
6a488035 TO |
237 | foreach ($values as $tuple) { |
238 | list($name, $op, $value, $grouping, $wildcard) = $tuple; | |
239 | ||
6a488035 | 240 | $field = $this->_fields[$id]; |
6a488035 | 241 | |
3130209f CW |
242 | $fieldName = "{$field['table_name']}.{$field['column_name']}"; |
243 | ||
05c5cbc8 | 244 | $isSerialized = CRM_Core_BAO_CustomField::isSerialized($field); |
245 | ||
3130209f | 246 | // fix $value here to escape sql injection attacks |
7ecb613a | 247 | $qillValue = NULL; |
9f388466 CW |
248 | if (!is_array($value)) { |
249 | $value = CRM_Core_DAO::escapeString(trim($value)); | |
8cee0c70 | 250 | $qillValue = CRM_Core_BAO_CustomField::displayValue($value, $id); |
7ecb613a | 251 | } |
252 | elseif (count($value) && in_array(key($value), CRM_Core_DAO::acceptedSQLOperators(), TRUE)) { | |
253 | $op = key($value); | |
8cee0c70 | 254 | $qillValue = strstr($op, 'NULL') ? NULL : CRM_Core_BAO_CustomField::displayValue($value[$op], $id); |
9f388466 | 255 | } |
c94d39fd | 256 | else { |
ec28b24d | 257 | $op = strstr($op, 'IN') ? $op : 'IN'; |
8cee0c70 | 258 | $qillValue = CRM_Core_BAO_CustomField::displayValue($value, $id); |
c94d39fd | 259 | } |
3130209f | 260 | |
2c261619 | 261 | $qillOp = CRM_Utils_Array::value($op, CRM_Core_SelectValues::getSearchBuilderOperators(), $op); |
3130209f | 262 | |
7f175707 | 263 | // Ensure the table is joined in (eg if in where but not select). |
264 | $this->joinCustomTableForField($field); | |
6a488035 TO |
265 | switch ($field['data_type']) { |
266 | case 'String': | |
16b6d3d4 | 267 | case 'StateProvince': |
268 | case 'Country': | |
3130209f CW |
269 | |
270 | if ($field['is_search_range'] && is_array($value)) { | |
4c2fe77b | 271 | //didn't found any field under any of these three data-types as searchable by range |
6a488035 TO |
272 | } |
273 | else { | |
05c5cbc8 | 274 | // fix $value here to escape sql injection attacks |
275 | if (!is_array($value)) { | |
16b6d3d4 | 276 | if ($field['data_type'] == 'String') { |
d215c0e1 | 277 | $value = CRM_Utils_Type::escape($value, 'String'); |
16b6d3d4 | 278 | } |
bb0300b9 | 279 | elseif ($value) { |
16b6d3d4 | 280 | $value = CRM_Utils_Type::escape($value, 'Integer'); |
281 | } | |
be2fb01f | 282 | $value = str_replace(['[', ']', ','], ['\[', '\]', '[:comma:]'], $value); |
2f32a341 | 283 | $value = str_replace('|', '[:separator:]', $value); |
05c5cbc8 | 284 | } |
c94d39fd | 285 | elseif ($isSerialized) { |
286 | if (in_array(key($value), CRM_Core_DAO::acceptedSQLOperators(), TRUE)) { | |
287 | $op = key($value); | |
288 | $value = $value[$op]; | |
289 | } | |
7bcee799 | 290 | // CRM-19006: escape characters like comma, | before building regex pattern |
291 | $value = (array) $value; | |
292 | foreach ($value as $key => $val) { | |
be2fb01f | 293 | $value[$key] = str_replace(['[', ']', ','], ['\[', '\]', '[:comma:]'], $val); |
894223d8 | 294 | $value[$key] = str_replace('|', '[:separator:]', $value[$key]); |
804f8b8e JM |
295 | if ($field['data_type'] == 'String') { |
296 | $value[$key] = CRM_Utils_Type::escape($value[$key], 'String'); | |
297 | } | |
298 | elseif ($value) { | |
299 | $value[$key] = CRM_Utils_Type::escape($value[$key], 'Integer'); | |
300 | } | |
7bcee799 | 301 | } |
302 | $value = implode(',', $value); | |
05c5cbc8 | 303 | } |
3130209f | 304 | |
2c261619 | 305 | // CRM-14563,CRM-16575 : Special handling of multi-select custom fields |
78fe145d | 306 | if ($isSerialized && !CRM_Utils_System::isNull($value) && !strstr($op, 'NULL') && !strstr($op, 'LIKE')) { |
528f09a1 | 307 | $sp = CRM_Core_DAO::VALUE_SEPARATOR; |
2f32a341 | 308 | $value = str_replace(",", "$sp|$sp", $value); |
be2fb01f | 309 | $value = str_replace(['[:comma:]', '(', ')'], [',', '[(]', '[)]'], $value); |
2f32a341 | 310 | |
c94d39fd | 311 | $op = (strstr($op, '!') || strstr($op, 'NOT')) ? 'NOT RLIKE' : 'RLIKE'; |
528f09a1 | 312 | $value = $sp . $value . $sp; |
c94d39fd | 313 | if (!$wildcard) { |
528f09a1 | 314 | foreach (explode("|", $value) as $val) { |
e5ccf3d9 | 315 | $val = str_replace('[:separator:]', '\|', $val); |
528f09a1 | 316 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $val, 'String'); |
317 | } | |
318 | } | |
319 | else { | |
e5ccf3d9 | 320 | $value = str_replace('[:separator:]', '\|', $value); |
528f09a1 | 321 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); |
2c261619 | 322 | } |
6a488035 | 323 | } |
528f09a1 | 324 | else { |
325 | //FIX for custom data query fired against no value(NULL/NOT NULL) | |
326 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); | |
327 | } | |
b4fb2d23 | 328 | $this->_qill[$grouping][] = $field['label'] . " $qillOp $qillValue"; |
6a488035 | 329 | } |
3130209f | 330 | break; |
6a488035 TO |
331 | |
332 | case 'ContactReference': | |
333 | $label = $value ? CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name') : ''; | |
334 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); | |
2c261619 | 335 | $this->_qill[$grouping][] = $field['label'] . " $qillOp $label"; |
3130209f | 336 | break; |
6a488035 TO |
337 | |
338 | case 'Int': | |
4c2fe77b | 339 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer'); |
fe7f4414 | 340 | $this->_qill[$grouping][] = ts("%1 %2 %3", [1 => $field['label'], 2 => $qillOp, 3 => $qillValue]); |
3130209f | 341 | break; |
6a488035 TO |
342 | |
343 | case 'Boolean': | |
16b6d3d4 | 344 | if (!is_array($value)) { |
345 | if (strtolower($value) == 'yes' || strtolower($value) == strtolower(ts('Yes'))) { | |
346 | $value = 1; | |
347 | } | |
348 | else { | |
349 | $value = (int) $value; | |
350 | } | |
351 | $value = ($value == 1) ? 1 : 0; | |
352 | $qillValue = $value ? 'Yes' : 'No'; | |
6a488035 | 353 | } |
6a488035 | 354 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer'); |
be2fb01f | 355 | $this->_qill[$grouping][] = ts("%1 %2 %3", [1 => $field['label'], 2 => $qillOp, 3 => $qillValue]); |
3130209f | 356 | break; |
6a488035 TO |
357 | |
358 | case 'Link': | |
16b6d3d4 | 359 | case 'Memo': |
6a488035 | 360 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); |
be2fb01f | 361 | $this->_qill[$grouping][] = ts("%1 %2 %3", [1 => $field['label'], 2 => $qillOp, 3 => $qillValue]); |
3130209f | 362 | break; |
6a488035 TO |
363 | |
364 | case 'Money': | |
ec28b24d | 365 | $value = CRM_Utils_Array::value($op, (array) $value, $value); |
16b6d3d4 | 366 | if (is_array($value)) { |
6a488035 | 367 | foreach ($value as $key => $val) { |
e45c5e68 | 368 | // @todo - this clean money should be in the form layer - it's highly likely to be doing more harm than good here |
369 | // Note the only place I can find that this code is reached by is searching a custom money field in advanced search. | |
370 | // with euro style comma separators this doesn't work - with or without this cleanMoney. | |
371 | // So this should be removed but is not increasing the brokeness IMHO | |
372 | $value[$op][$key] = CRM_Utils_Rule::cleanMoney($value[$key]); | |
6a488035 | 373 | } |
16b6d3d4 | 374 | } |
375 | else { | |
e45c5e68 | 376 | // @todo - this clean money should be in the form layer - it's highly likely to be doing more harm than good here |
377 | // comments per above apply. cleanMoney | |
16b6d3d4 | 378 | $value = CRM_Utils_Rule::cleanMoney($value); |
379 | } | |
380 | ||
381 | case 'Float': | |
4c2fe77b | 382 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float'); |
be2fb01f | 383 | $this->_qill[$grouping][] = ts("%1 %2 %3", [1 => $field['label'], 2 => $qillOp, 3 => $qillValue]); |
3130209f | 384 | break; |
6a488035 | 385 | |
6a488035 | 386 | case 'Date': |
2206409b | 387 | if (substr($name, -9, 9) !== '_relative' |
388 | && substr($name, -4, 4) !== '_low' | |
389 | && substr($name, -5, 5) !== '_high') { | |
7f175707 | 390 | // Relative dates are handled in the buildRelativeDateQuery function. |
391 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Date'); | |
392 | list($qillOp, $qillVal) = CRM_Contact_BAO_Query::buildQillForFieldValue(NULL, $field['label'], $value, $op, [], CRM_Utils_Type::T_DATE); | |
393 | $this->_qill[$grouping][] = "{$field['label']} $qillOp '$qillVal'"; | |
394 | } | |
3130209f | 395 | break; |
6a488035 | 396 | |
6a488035 | 397 | case 'File': |
481a74f4 | 398 | if ($op == 'IS NULL' || $op == 'IS NOT NULL' || $op == 'IS EMPTY' || $op == 'IS NOT EMPTY') { |
6a488035 TO |
399 | switch ($op) { |
400 | case 'IS EMPTY': | |
401 | $op = 'IS NULL'; | |
402 | break; | |
2aa397bc | 403 | |
6a488035 TO |
404 | case 'IS NOT EMPTY': |
405 | $op = 'IS NOT NULL'; | |
406 | break; | |
407 | } | |
408 | $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op); | |
2c261619 | 409 | $this->_qill[$grouping][] = $field['label'] . " {$qillOp} "; |
6a488035 | 410 | } |
3130209f | 411 | break; |
6a488035 TO |
412 | } |
413 | } | |
414 | } | |
415 | } | |
416 | ||
417 | /** | |
d2e5d2ce | 418 | * Function that does the actual query generation. |
6a488035 TO |
419 | * basically ties all the above functions together |
420 | * | |
a6c01b45 CW |
421 | * @return array |
422 | * array of strings | |
6a488035 | 423 | */ |
00be9182 | 424 | public function query() { |
6a488035 TO |
425 | $this->select(); |
426 | ||
427 | $this->where(); | |
428 | ||
429 | $whereStr = NULL; | |
430 | if (!empty($this->_where)) { | |
be2fb01f | 431 | $clauses = []; |
6a488035 TO |
432 | foreach ($this->_where as $grouping => $values) { |
433 | if (!empty($values)) { | |
434 | $clauses[] = ' ( ' . implode(' AND ', $values) . ' ) '; | |
435 | } | |
436 | } | |
437 | if (!empty($clauses)) { | |
438 | $whereStr = ' ( ' . implode(' OR ', $clauses) . ' ) '; | |
439 | } | |
440 | } | |
441 | ||
be2fb01f | 442 | return [ |
353ffa53 | 443 | implode(' , ', $this->_select), |
6a488035 TO |
444 | implode(' ', $this->_tables), |
445 | $whereStr, | |
be2fb01f | 446 | ]; |
6a488035 TO |
447 | } |
448 | ||
7f175707 | 449 | /** |
450 | * Join the custom table for the field in (if not already in the query). | |
451 | * | |
452 | * @param array $field | |
453 | */ | |
454 | protected function joinCustomTableForField($field) { | |
455 | $name = $field['table_name']; | |
456 | $join = "\nLEFT JOIN $name ON $name.entity_id = {$field['search_table']}.id"; | |
457 | $this->_tables[$name] = $this->_tables[$name] ?? $join; | |
458 | $this->_whereTables[$name] = $this->_whereTables[$name] ?? $join; | |
410e3761 | 459 | |
460 | $joinTable = $field['search_table']; | |
461 | if ($joinTable) { | |
462 | $joinClause = 1; | |
463 | $joinTableAlias = $joinTable; | |
464 | // Set location-specific query | |
465 | if (isset($this->_locationSpecificCustomFields[$field['id']])) { | |
466 | list($locationType, $locationTypeId) = $this->_locationSpecificCustomFields[$field['id']]; | |
467 | $joinTableAlias = "$locationType-address"; | |
468 | $joinClause = "\nLEFT JOIN $joinTable `$locationType-address` ON (`$locationType-address`.contact_id = contact_a.id AND `$locationType-address`.location_type_id = $locationTypeId)"; | |
469 | } | |
470 | $this->_tables[$name] = "\nLEFT JOIN $name ON $name.entity_id = `$joinTableAlias`.id"; | |
471 | if (!empty($this->_ids[$field['id']])) { | |
472 | $this->_whereTables[$name] = $this->_tables[$name]; | |
473 | } | |
474 | if ($joinTable !== 'contact_a') { | |
475 | $this->_whereTables[$joinTableAlias] = $this->_tables[$joinTableAlias] = $joinClause; | |
476 | } | |
477 | } | |
7f175707 | 478 | } |
479 | ||
6a488035 | 480 | } |