Merge pull request #12006 from civicrm/5.1
[civicrm-core.git] / CRM / Core / BAO / CustomValueTable.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
8c9251b3 6 | Copyright CiviCRM LLC (c) 2004-2018 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
8c9251b3 31 * @copyright CiviCRM LLC (c) 2004-2018
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Core_BAO_CustomValueTable {
36
b5c2afd0 37 /**
100fef9d 38 * @param array $customParams
b5c2afd0
EM
39 *
40 * @throws Exception
41 */
00be9182 42 public static function create(&$customParams) {
6a488035
TO
43 if (empty($customParams) ||
44 !is_array($customParams)
45 ) {
46 return;
47 }
8ef12e64 48
63b7d442
AS
49 $paramFieldsExtendContactForEntities = array();
50
6a488035
TO
51 foreach ($customParams as $tableName => $tables) {
52 foreach ($tables as $index => $fields) {
353ffa53
TO
53 $sqlOP = NULL;
54 $hookID = NULL;
55 $hookOP = NULL;
56 $entityID = NULL;
6a488035 57 $isMultiple = FALSE;
353ffa53
TO
58 $set = array();
59 $params = array();
60 $count = 1;
6a488035
TO
61 foreach ($fields as $field) {
62 if (!$sqlOP) {
353ffa53
TO
63 $entityID = $field['entity_id'];
64 $hookID = $field['custom_group_id'];
6a488035
TO
65 $isMultiple = $field['is_multiple'];
66 if (array_key_exists('id', $field)) {
353ffa53
TO
67 $sqlOP = "UPDATE $tableName ";
68 $where = " WHERE id = %{$count}";
6a488035
TO
69 $params[$count] = array($field['id'], 'Integer');
70 $count++;
71 $hookOP = 'edit';
72 }
73 else {
353ffa53
TO
74 $sqlOP = "INSERT INTO $tableName ";
75 $where = NULL;
6a488035
TO
76 $hookOP = 'create';
77 }
78 }
79
80 // fix the value before we store it
81 $value = $field['value'];
82 $type = $field['type'];
83 switch ($type) {
84 case 'StateProvince':
85 $type = 'Integer';
86 if (is_array($value)) {
87 $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $value) . CRM_Core_DAO::VALUE_SEPARATOR;
88 $type = 'String';
89 }
ec28b24d 90 elseif (!is_numeric($value) && !strstr($value, CRM_Core_DAO::VALUE_SEPARATOR)) {
6a488035
TO
91 //fix for multi select state, CRM-3437
92 $mulValues = explode(',', $value);
93 $validStates = array();
94 foreach ($mulValues as $key => $stateVal) {
95 $states = array();
96 $states['state_province'] = trim($stateVal);
97
98 CRM_Utils_Array::lookupValue($states, 'state_province',
99 CRM_Core_PseudoConstant::stateProvince(), TRUE
100 );
a7488080 101 if (empty($states['state_province_id'])) {
6a488035
TO
102 CRM_Utils_Array::lookupValue($states, 'state_province',
103 CRM_Core_PseudoConstant::stateProvinceAbbreviation(), TRUE
104 );
105 }
ec28b24d 106 $validStates[] = CRM_Utils_Array::value('state_province_id', $states);
6a488035
TO
107 }
108 $value = implode(CRM_Core_DAO::VALUE_SEPARATOR,
109 $validStates
110 );
111 $type = 'String';
112 }
113 elseif (!$value) {
114 // CRM-3415
115 // using type of timestamp allows us to sneak in a null into db
116 // gross but effective hack
117 $value = NULL;
118 $type = 'Timestamp';
119 }
ec28b24d 120 else {
121 $type = 'String';
122 }
6a488035
TO
123 break;
124
125 case 'Country':
126 $type = 'Integer';
8007b543 127 $mulValues = explode(',', $value);
6a488035
TO
128 if (is_array($value)) {
129 $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $value) . CRM_Core_DAO::VALUE_SEPARATOR;
130 $type = 'String';
131 }
ec28b24d 132 elseif (!is_numeric($value) && !strstr($value, CRM_Core_DAO::VALUE_SEPARATOR)) {
6a488035
TO
133 //fix for multi select country, CRM-3437
134 $mulValues = explode(',', $value);
135 $validCountries = array();
136 foreach ($mulValues as $key => $countryVal) {
137 $countries = array();
138 $countries['country'] = trim($countryVal);
139 CRM_Utils_Array::lookupValue($countries, 'country',
140 CRM_Core_PseudoConstant::country(), TRUE
141 );
a7488080 142 if (empty($countries['country_id'])) {
6a488035
TO
143 CRM_Utils_Array::lookupValue($countries, 'country',
144 CRM_Core_PseudoConstant::countryIsoCode(), TRUE
145 );
146 }
8415b361 147 $validCountries[] = CRM_Utils_Array::value('country_id', $countries);
6a488035
TO
148 }
149 $value = implode(CRM_Core_DAO::VALUE_SEPARATOR,
150 $validCountries
151 );
152 $type = 'String';
153 }
154 elseif (!$value) {
155 // CRM-3415
156 // using type of timestamp allows us to sneak in a null into db
157 // gross but effective hack
158 $value = NULL;
159 $type = 'Timestamp';
160 }
ec28b24d 161 else {
162 $type = 'String';
163 }
6a488035
TO
164 break;
165
166 case 'File':
167 if (!$field['file_id']) {
168 CRM_Core_Error::fatal();
169 }
170
171 // need to add/update civicrm_entity_file
172 $entityFileDAO = new CRM_Core_DAO_EntityFile();
173 $entityFileDAO->file_id = $field['file_id'];
174 $entityFileDAO->find(TRUE);
175
176 $entityFileDAO->entity_table = $field['table_name'];
177 $entityFileDAO->entity_id = $field['entity_id'];
178 $entityFileDAO->file_id = $field['file_id'];
179 $entityFileDAO->save();
180 $entityFileDAO->free();
181 $value = $field['file_id'];
182 $type = 'String';
183 break;
184
185 case 'Date':
186 $value = CRM_Utils_Date::isoToMysql($value);
187 break;
188
189 case 'Int':
190 if (is_numeric($value)) {
191 $type = 'Integer';
192 }
193 else {
194 $type = 'Timestamp';
195 }
196 break;
197
198 case 'ContactReference':
199 if ($value == NULL) {
200 $type = 'Timestamp';
201 }
202 else {
203 $type = 'Integer';
204 }
205 break;
206
207 case 'RichTextEditor':
208 $type = 'String';
209 break;
210
211 case 'Boolean':
212 //fix for CRM-3290
213 $value = CRM_Utils_String::strtoboolstr($value);
214 if ($value === FALSE) {
215 $type = 'Timestamp';
216 }
217 break;
218
219 default:
220 break;
221 }
fd630ef9 222 if (strtolower($value) === "null") {
223 // when unsetting a value to null, we don't need to validate the type
224 // https://projectllr.atlassian.net/browse/VGQBMP-20
225 $set[$field['column_name']] = $value;
f931b74c 226 }
227 else {
fd630ef9 228 $set[$field['column_name']] = "%{$count}";
229 $params[$count] = array($value, $type);
230 $count++;
231 }
63b7d442
AS
232
233 $fieldExtends = CRM_Utils_Array::value('extends', $field);
234 if (
235 CRM_Utils_Array::value('entity_table', $field) == 'civicrm_contact'
236 || $fieldExtends == 'Contact'
237 || $fieldExtends == 'Individual'
238 || $fieldExtends == 'Organization'
239 || $fieldExtends == 'Household'
240 ) {
241 $paramFieldsExtendContactForEntities[$entityID]['custom_' . CRM_Utils_Array::value('custom_field_id', $field)] = CRM_Utils_Array::value('custom_field_id', $field);
242 }
6a488035
TO
243 }
244
245 if (!empty($set)) {
246 $setClause = array();
247 foreach ($set as $n => $v) {
248 $setClause[] = "$n = $v";
249 }
250 $setClause = implode(',', $setClause);
251 if (!$where) {
252 // do this only for insert
253 $set['entity_id'] = "%{$count}";
254 $params[$count] = array($entityID, 'Integer');
255 $count++;
256
65aae70e 257 $fieldNames = implode(',', CRM_Utils_Type::escapeAll(array_keys($set), 'MysqlColumnNameOrAlias'));
6a488035 258 $fieldValues = implode(',', array_values($set));
353ffa53 259 $query = "$sqlOP ( $fieldNames ) VALUES ( $fieldValues )";
6a488035
TO
260 // for multiple values we dont do on duplicate key update
261 if (!$isMultiple) {
262 $query .= " ON DUPLICATE KEY UPDATE $setClause";
263 }
264 }
265 else {
266 $query = "$sqlOP SET $setClause $where";
267 }
268 $dao = CRM_Core_DAO::executeQuery($query, $params);
269
270 CRM_Utils_Hook::custom($hookOP,
271 $hookID,
272 $entityID,
273 $fields
274 );
275 }
276 }
277 }
63b7d442
AS
278
279 if (!empty($paramFieldsExtendContactForEntities)) {
280 CRM_Contact_BAO_Contact::updateGreetingsOnTokenFieldChange($paramFieldsExtendContactForEntities, array('contact_id' => $entityID));
281 }
6a488035
TO
282 }
283
284 /**
fe482240 285 * Given a field return the mysql data type associated with it.
6a488035 286 *
6a0b768e 287 * @param string $type
fd31fa4c
EM
288 * @param int $maxLength
289 *
72b3a70c
CW
290 * @return string
291 * the mysql data store placeholder
6a488035
TO
292 */
293 public static function fieldToSQLType($type, $maxLength = 255) {
294 if (!isset($maxLength) ||
295 !is_numeric($maxLength) ||
296 $maxLength <= 0
297 ) {
298 $maxLength = 255;
299 }
300
301 switch ($type) {
302 case 'String':
303 case 'Link':
304 return "varchar($maxLength)";
305
306 case 'Boolean':
307 return 'tinyint';
308
309 case 'Int':
310 return 'int';
2aa397bc 311
6a488035
TO
312 // the below three are FK's, and have constraints added to them
313
314 case 'ContactReference':
315 case 'StateProvince':
316 case 'Country':
317 case 'File':
318 return 'int unsigned';
319
320 case 'Float':
321 return 'double';
322
323 case 'Money':
324 return 'decimal(20,2)';
325
326 case 'Memo':
327 case 'RichTextEditor':
328 return 'text';
329
330 case 'Date':
331 return 'datetime';
332
333 default:
334 CRM_Core_Error::fatal();
335 }
336 }
337
b5c2afd0 338 /**
c490a46a 339 * @param array $params
b5c2afd0 340 * @param $entityTable
100fef9d 341 * @param int $entityID
b5c2afd0 342 */
00be9182 343 public static function store(&$params, $entityTable, $entityID) {
6a488035
TO
344 $cvParams = array();
345 foreach ($params as $fieldID => $param) {
346 foreach ($param as $index => $customValue) {
347 $cvParam = array(
348 'entity_table' => $entityTable,
349 'entity_id' => $entityID,
350 'value' => $customValue['value'],
351 'type' => $customValue['type'],
352 'custom_field_id' => $customValue['custom_field_id'],
353 'custom_group_id' => $customValue['custom_group_id'],
354 'table_name' => $customValue['table_name'],
355 'column_name' => $customValue['column_name'],
356 'is_multiple' => CRM_Utils_Array::value('is_multiple', $customValue),
357 'file_id' => $customValue['file_id'],
358 );
359
fe482240 360 // Fix Date type to be timestamp, since that is how we store in db.
6a488035
TO
361 if ($cvParam['type'] == 'Date') {
362 $cvParam['type'] = 'Timestamp';
363 }
364
a7488080 365 if (!empty($customValue['id'])) {
6a488035
TO
366 $cvParam['id'] = $customValue['id'];
367 }
368 if (!array_key_exists($customValue['table_name'], $cvParams)) {
369 $cvParams[$customValue['table_name']] = array();
370 }
371
372 if (!array_key_exists($index, $cvParams[$customValue['table_name']])) {
373 $cvParams[$customValue['table_name']][$index] = array();
374 }
375
376 $cvParams[$customValue['table_name']][$index][] = $cvParam;
377 }
378 }
379 if (!empty($cvParams)) {
380 self::create($cvParams);
381 }
382 }
383
b5c2afd0 384 /**
fe482240
EM
385 * Post process function.
386 *
c490a46a 387 * @param array $params
b5c2afd0 388 * @param $entityTable
100fef9d 389 * @param int $entityID
b5c2afd0
EM
390 * @param $customFieldExtends
391 */
5fc3ea24 392 public static function postProcess(&$params, $entityTable, $entityID, $customFieldExtends) {
6a488035 393 $customData = CRM_Core_BAO_CustomField::postProcess($params,
6a488035
TO
394 $entityID,
395 $customFieldExtends
396 );
397
398 if (!empty($customData)) {
399 self::store($customData, $entityTable, $entityID);
400 }
401 }
402
403 /**
404 * Return an array of all custom values associated with an entity.
405 *
6a0b768e
TO
406 * @param int $entityID
407 * Identification number of the entity.
408 * @param string $entityType
409 * Type of entity that the entityID corresponds to, specified.
6a488035
TO
410 * as a string with format "'<EntityName>'". Comma separated
411 * list may be used to specify OR matches. Allowable values
412 * are enumerated types in civicrm_custom_group.extends field.
413 * Optional. Default value assumes entityID references a
414 * contact entity.
6a0b768e
TO
415 * @param array $fieldIDs
416 * Optional list of fieldIDs that we want to retrieve. If this.
6a488035
TO
417 * is set the entityType is ignored
418 *
77b97be7 419 * @param bool $formatMultiRecordField
c693f065 420 * @param array $DTparams - CRM-17810 dataTable params for the multiValued custom fields.
77b97be7 421 *
a6c01b45
CW
422 * @return array
423 * Array of custom values for the entity with key=>value
6a488035
TO
424 * pairs specified as civicrm_custom_field.id => custom value.
425 * Empty array if no custom values found.
6a488035 426 */
c693f065 427 public static function &getEntityValues($entityID, $entityType = NULL, $fieldIDs = NULL, $formatMultiRecordField = FALSE, $DTparams = NULL) {
6a488035
TO
428 if (!$entityID) {
429 // adding this here since an empty contact id could have serious repurcussions
430 // like looping forever
431 CRM_Core_Error::fatal('Please file an issue with the backtrace');
432 return NULL;
433 }
434
435 $cond = array();
436 if ($entityType) {
437 $cond[] = "cg.extends IN ( '$entityType' )";
438 }
439 if ($fieldIDs &&
440 is_array($fieldIDs)
441 ) {
442 $fieldIDList = implode(',', $fieldIDs);
443 $cond[] = "cf.id IN ( $fieldIDList )";
444 }
445 if (empty($cond)) {
446 $cond[] = "cg.extends IN ( 'Contact', 'Individual', 'Household', 'Organization' )";
447 }
448 $cond = implode(' AND ', $cond);
449
e87c8fb7 450 $limit = $orderBy = '';
c693f065 451 if (!empty($DTparams['rowCount']) && $DTparams['rowCount'] > 0) {
d51e02d3 452 $limit = " LIMIT " . CRM_Utils_Type::escape($DTparams['offset'], 'Integer') . ", " . CRM_Utils_Type::escape($DTparams['rowCount'], 'Integer');
c693f065 453 }
c693f065 454 if (!empty($DTparams['sort'])) {
455 $orderBy = ' ORDER BY ' . CRM_Utils_Type::escape($DTparams['sort'], 'String');
456 }
457
fe482240 458 // First find all the fields that extend this type of entity.
6a488035
TO
459 $query = "
460SELECT cg.table_name,
461 cg.id as groupID,
462 cg.is_multiple,
463 cf.column_name,
34f51a07
N
464 cf.id as fieldID,
465 cf.data_type as fieldDataType
6a488035
TO
466FROM civicrm_custom_group cg,
467 civicrm_custom_field cf
468WHERE cf.custom_group_id = cg.id
469AND cg.is_active = 1
470AND cf.is_active = 1
471AND $cond
472";
473 $dao = CRM_Core_DAO::executeQuery($query);
474
475 $select = $fields = $isMultiple = array();
476
477 while ($dao->fetch()) {
478 if (!array_key_exists($dao->table_name, $select)) {
479 $fields[$dao->table_name] = array();
480 $select[$dao->table_name] = array();
481 }
482 $fields[$dao->table_name][] = $dao->fieldID;
483 $select[$dao->table_name][] = "{$dao->column_name} AS custom_{$dao->fieldID}";
484 $isMultiple[$dao->table_name] = $dao->is_multiple ? TRUE : FALSE;
77b97be7 485 $file[$dao->table_name][$dao->fieldID] = $dao->fieldDataType;
6a488035
TO
486 }
487
1c66bdc7 488 $result = $sortedResult = array();
6a488035 489 foreach ($select as $tableName => $clauses) {
1c66bdc7 490 if (!empty($DTparams['sort'])) {
491 $query = CRM_Core_DAO::executeQuery("SELECT id FROM {$tableName} WHERE entity_id = {$entityID}");
492 $count = 1;
493 while ($query->fetch()) {
494 $sortedResult["{$query->id}"] = $count;
495 $count++;
496 }
497 }
498
c693f065 499 $query = "SELECT SQL_CALC_FOUND_ROWS id, " . implode(', ', $clauses) . " FROM $tableName WHERE entity_id = $entityID {$orderBy} {$limit}";
6a488035 500 $dao = CRM_Core_DAO::executeQuery($query);
e87c8fb7 501 if (!empty($DTparams)) {
502 $result['count'] = CRM_Core_DAO::singleValueQuery('SELECT FOUND_ROWS()');
503 }
6a488035
TO
504 while ($dao->fetch()) {
505 foreach ($fields[$tableName] as $fieldID) {
506 $fieldName = "custom_{$fieldID}";
507 if ($isMultiple[$tableName]) {
508 if ($formatMultiRecordField) {
d8f34a6e 509 $result["{$dao->id}"]["{$fieldID}"] = $dao->$fieldName;
fe482240
EM
510 }
511 else {
6a488035
TO
512 $result["{$fieldID}_{$dao->id}"] = $dao->$fieldName;
513 }
514 }
515 else {
d8f34a6e 516 $result[$fieldID] = $dao->$fieldName;
6a488035
TO
517 }
518 }
519 }
520 }
e525d6af 521 if (!empty($sortedResult)) {
522 $result['sortedResult'] = $sortedResult;
1c66bdc7 523 }
6a488035
TO
524 return $result;
525 }
526
527 /**
100fef9d 528 * Take in an array of entityID, custom_XXX => value
6a488035
TO
529 * and set the value in the appropriate table. Should also be able
530 * to set the value to null. Follows api parameter/return conventions
531 *
532 * @array $params
533 *
c490a46a 534 * @param array $params
2a6da8d7
EM
535 *
536 * @throws Exception
6a488035 537 * @return array
6a488035 538 */
00be9182 539 public static function setValues(&$params) {
6a488035
TO
540
541 if (!isset($params['entityID']) ||
542 CRM_Utils_Type::escape($params['entityID'], 'Integer', FALSE) === NULL
543 ) {
544 return CRM_Core_Error::createAPIError(ts('entityID needs to be set and of type Integer'));
545 }
546
547 // first collect all the id/value pairs. The format is:
548 // custom_X => value or custom_X_VALUEID => value (for multiple values), VALUEID == -1, -2 etc for new insertions
549 $values = array();
550 $fieldValues = array();
551 foreach ($params as $n => $v) {
552 if ($customFieldInfo = CRM_Core_BAO_CustomField::getKeyID($n, TRUE)) {
553 $fieldID = (int ) $customFieldInfo[0];
554 if (CRM_Utils_Type::escape($fieldID, 'Integer', FALSE) === NULL) {
555 return CRM_Core_Error::createAPIError(ts('field ID needs to be of type Integer for index %1',
353ffa53
TO
556 array(1 => $fieldID)
557 ));
6a488035
TO
558 }
559 if (!array_key_exists($fieldID, $fieldValues)) {
560 $fieldValues[$fieldID] = array();
561 }
562 $id = -1;
563 if ($customFieldInfo[1]) {
564 $id = (int ) $customFieldInfo[1];
565 }
566 $fieldValues[$fieldID][] = array(
567 'value' => $v,
568 'id' => $id,
569 );
570 }
571 }
572
573 $fieldIDList = implode(',', array_keys($fieldValues));
574
575 // format it so that we can just use create
576 $sql = "
577SELECT cg.table_name as table_name ,
578 cg.id as cg_id ,
579 cg.is_multiple as is_multiple,
63b7d442 580 cg.extends as extends,
6a488035
TO
581 cf.column_name as column_name,
582 cf.id as cf_id ,
583 cf.data_type as data_type
584FROM civicrm_custom_group cg,
585 civicrm_custom_field cf
586WHERE cf.custom_group_id = cg.id
587AND cf.id IN ( $fieldIDList )
588";
589
590 $dao = CRM_Core_DAO::executeQuery($sql);
591 $cvParams = array();
592
593 while ($dao->fetch()) {
594 $dataType = $dao->data_type == 'Date' ? 'Timestamp' : $dao->data_type;
595 foreach ($fieldValues[$dao->cf_id] as $fieldValue) {
596 // Format null values correctly
597 if ($fieldValue['value'] === NULL || $fieldValue['value'] === '') {
598 switch ($dataType) {
599 case 'String':
600 case 'Int':
601 case 'Link':
602 case 'Boolean':
603 $fieldValue['value'] = '';
604 break;
605
606 case 'Timestamp':
607 $fieldValue['value'] = NULL;
608 break;
609
610 case 'StateProvince':
611 case 'Country':
612 case 'Money':
613 case 'Float':
2aa397bc 614 $fieldValue['value'] = (int) 0;
6a488035
TO
615 break;
616 }
617 }
618 // Ensure that value is of the right data type
619 elseif (CRM_Utils_Type::escape($fieldValue['value'], $dataType, FALSE) === NULL) {
620 return CRM_Core_Error::createAPIError(ts('value: %1 is not of the right field data type: %2',
353ffa53
TO
621 array(
622 1 => $fieldValue['value'],
623 2 => $dao->data_type,
624 )
625 ));
6a488035
TO
626 }
627
628 $cvParam = array(
629 'entity_id' => $params['entityID'],
630 'value' => $fieldValue['value'],
631 'type' => $dataType,
632 'custom_field_id' => $dao->cf_id,
633 'custom_group_id' => $dao->cg_id,
634 'table_name' => $dao->table_name,
635 'column_name' => $dao->column_name,
636 'is_multiple' => $dao->is_multiple,
63b7d442 637 'extends' => $dao->extends,
6a488035
TO
638 );
639
e7dcccf0
CW
640 if ($cvParam['type'] == 'File') {
641 $cvParam['file_id'] = $fieldValue['value'];
642 }
643
6a488035
TO
644 if (!array_key_exists($dao->table_name, $cvParams)) {
645 $cvParams[$dao->table_name] = array();
646 }
647
648 if (!array_key_exists($fieldValue['id'], $cvParams[$dao->table_name])) {
649 $cvParams[$dao->table_name][$fieldValue['id']] = array();
650 }
651
652 if ($fieldValue['id'] > 0) {
653 $cvParam['id'] = $fieldValue['id'];
654 }
655 $cvParams[$dao->table_name][$fieldValue['id']][] = $cvParam;
656 }
657 }
658
659 if (!empty($cvParams)) {
660 self::create($cvParams);
661 return array('is_error' => 0, 'result' => 1);
662 }
663
664 return CRM_Core_Error::createAPIError(ts('Unknown error'));
665 }
666
667 /**
100fef9d 668 * Take in an array of entityID, custom_ID
6a488035
TO
669 * and gets the value from the appropriate table.
670 *
671 * To get the values of custom fields with IDs 13 and 43 for contact ID 1327, use:
672 * $params = array( 'entityID' => 1327, 'custom_13' => 1, 'custom_43' => 1 );
673 *
b44e3f84 674 * Entity Type will be inferred by the custom fields you request
6a488035
TO
675 * Specify $params['entityType'] if you do not supply any custom fields to return
676 * and entity type is other than Contact
677 *
678 * @array $params
679 *
c490a46a 680 * @param array $params
2a6da8d7
EM
681 *
682 * @throws Exception
6a488035 683 * @return array
6a488035 684 */
00be9182 685 public static function &getValues(&$params) {
6a488035
TO
686 if (empty($params)) {
687 return NULL;
688 }
689 if (!isset($params['entityID']) ||
690 CRM_Utils_Type::escape($params['entityID'],
691 'Integer', FALSE
692 ) === NULL
693 ) {
694 return CRM_Core_Error::createAPIError(ts('entityID needs to be set and of type Integer'));
695 }
696
697 // first collect all the ids. The format is:
698 // custom_ID
699 $fieldIDs = array();
700 foreach ($params as $n => $v) {
701 $key = $idx = NULL;
702 if (substr($n, 0, 7) == 'custom_') {
703 $idx = substr($n, 7);
704 if (CRM_Utils_Type::escape($idx, 'Integer', FALSE) === NULL) {
705 return CRM_Core_Error::createAPIError(ts('field ID needs to be of type Integer for index %1',
353ffa53
TO
706 array(1 => $idx)
707 ));
6a488035
TO
708 }
709 $fieldIDs[] = (int ) $idx;
710 }
711 }
712
713 $default = array('Contact', 'Individual', 'Household', 'Organization');
714 if (!($type = CRM_Utils_Array::value('entityType', $params)) ||
715 in_array($params['entityType'], $default)
716 ) {
717 $type = NULL;
718 }
719 else {
720 $entities = CRM_Core_SelectValues::customGroupExtends();
721 if (!array_key_exists($type, $entities)) {
722 if (in_array($type, $entities)) {
723 $type = $entities[$type];
724 if (in_array($type, $default)) {
725 $type = NULL;
726 }
727 }
728 else {
729 return CRM_Core_Error::createAPIError(ts('Invalid entity type') . ': "' . $type . '"');
730 }
731 }
732 }
733
734 $values = self::getEntityValues($params['entityID'],
735 $type,
736 $fieldIDs
737 );
738 if (empty($values)) {
739 // note that this behaviour is undesirable from an API point of view - it should return an empty array
740 // since this is also called by the merger code & not sure the consequences of changing
741 // are just handling undoing this in the api layer. ie. converting the error back into a success
742 $result = array(
743 'is_error' => 1,
744 'error_message' => 'No values found for the specified entity ID and custom field(s).',
745 );
746 return $result;
747 }
748 else {
749 $result = array(
750 'is_error' => 0,
751 'entityID' => $params['entityID'],
752 );
753 foreach ($values as $id => $value) {
754 $result["custom_{$id}"] = $value;
755 }
756 return $result;
757 }
758 }
96025800 759
6a488035 760}