CRM-16189, modified code to allow sort option values with different column field
[civicrm-core.git] / CRM / Core / PseudoConstant.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2016 |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * Stores all constants and pseudo constants for CRM application.
31 *
32 * examples of constants are "Contact Type" which will always be either
33 * 'Individual', 'Household', 'Organization'.
34 *
35 * pseudo constants are entities from the database whose values rarely
36 * change. examples are list of countries, states, location types,
37 * relationship types.
38 *
39 * currently we're getting the data from the underlying database. this
40 * will be reworked to use caching.
41 *
42 * Note: All pseudoconstants should be uninitialized or default to NULL.
43 * This provides greater consistency/predictability after flushing.
44 *
45 * @package CRM
46 * @copyright CiviCRM LLC (c) 2004-2016
47 */
48 class CRM_Core_PseudoConstant {
49
50 /**
51 * Static cache for pseudoconstant arrays.
52 * @var array
53 */
54 private static $cache;
55
56 /**
57 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
58 *
59 * activity type
60 * @var array
61 */
62 private static $activityType;
63
64 /**
65 * States, provinces
66 * @var array
67 */
68 private static $stateProvince;
69
70 /**
71 * Counties.
72 * @var array
73 */
74 private static $county;
75
76 /**
77 * States/provinces abbreviations
78 * @var array
79 */
80 private static $stateProvinceAbbreviation = array();
81
82 /**
83 * Country.
84 * @var array
85 */
86 private static $country;
87
88 /**
89 * CountryIsoCode.
90 * @var array
91 */
92 private static $countryIsoCode;
93
94 /**
95 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
96 *
97 * group
98 * @var array
99 */
100 private static $group;
101
102 /**
103 * GroupIterator
104 * @var mixed
105 */
106 private static $groupIterator;
107
108 /**
109 * RelationshipType
110 * @var array
111 */
112 private static $relationshipType;
113
114 /**
115 * Civicrm groups that are not smart groups
116 * @var array
117 */
118 private static $staticGroup;
119
120 /**
121 * Currency codes
122 * @var array
123 */
124 private static $currencyCode;
125
126 /**
127 * Payment processor
128 * @var array
129 */
130 private static $paymentProcessor;
131
132 /**
133 * Payment processor types
134 * @var array
135 */
136 private static $paymentProcessorType;
137
138 /**
139 * World Region
140 * @var array
141 */
142 private static $worldRegions;
143
144 /**
145 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
146 *
147 * activity status
148 * @var array
149 */
150 private static $activityStatus;
151
152 /**
153 * Visibility
154 * @var array
155 */
156 private static $visibility;
157
158 /**
159 * Greetings
160 * @var array
161 */
162 private static $greeting;
163
164 /**
165 * Default Greetings
166 * @var array
167 */
168 private static $greetingDefaults;
169
170 /**
171 * Extensions of type module
172 * @var array
173 */
174 private static $extensions;
175
176 /**
177 * Financial Account Type
178 * @var array
179 */
180 private static $accountOptionValues;
181
182 /**
183 * Low-level option getter, rarely accessed directly.
184 * NOTE: Rather than calling this function directly use CRM_*_BAO_*::buildOptions()
185 * @see http://wiki.civicrm.org/confluence/display/CRMDOC/Pseudoconstant+%28option+list%29+Reference
186 *
187 * NOTE: If someone undertakes a refactoring of this, please consider the use-case of
188 * the Setting.getoptions API. There is no DAO/field, but it would be nice to use the
189 * same 'pseudoconstant' struct in *.settings.php. This means loosening the coupling
190 * between $field lookup and the $pseudoconstant evaluation.
191 *
192 * @param string $daoName
193 * @param string $fieldName
194 * @param array $params
195 * - name string name of the option group
196 * - flip boolean results are return in id => label format if false
197 * if true, the results are reversed
198 * - grouping boolean if true, return the value in 'grouping' column (currently unsupported for tables other than option_value)
199 * - localize boolean if true, localize the results before returning
200 * - condition string|array add condition(s) to the sql query - will be concatenated using 'AND'
201 * - keyColumn string the column to use for 'id'
202 * - labelColumn string the column to use for 'label'
203 * - orderColumn string the column to use for sorting, defaults to 'weight' column if one exists, else defaults to labelColumn
204 * - onlyActive boolean return only the action option values
205 * - fresh boolean ignore cache entries and go back to DB
206 * @param string $context : Context string
207 *
208 * @return array|bool
209 * array on success, FALSE on error.
210 *
211 */
212 public static function get($daoName, $fieldName, $params = array(), $context = NULL) {
213 CRM_Core_DAO::buildOptionsContext($context);
214 $flip = !empty($params['flip']);
215 // Merge params with defaults
216 $params += array(
217 'grouping' => FALSE,
218 'localize' => FALSE,
219 'onlyActive' => ($context == 'validate' || $context == 'get') ? FALSE : TRUE,
220 'fresh' => FALSE,
221 'context' => $context,
222 );
223 $entity = CRM_Core_DAO_AllCoreTables::getBriefName(CRM_Core_DAO_AllCoreTables::getCanonicalClassName($daoName));
224
225 // Custom fields are not in the schema
226 if (strpos($fieldName, 'custom_') === 0 && is_numeric($fieldName[7])) {
227 $customField = new CRM_Core_BAO_CustomField();
228 $customField->id = (int) substr($fieldName, 7);
229 $options = $customField->getOptions();
230 if ($options && $flip) {
231 $options = array_flip($options);
232 }
233 $customField->free();
234 return $options;
235 }
236
237 // Core field: load schema
238 $dao = new $daoName();
239 $fieldSpec = $dao->getFieldSpec($fieldName);
240 $dao->free();
241
242 // Ensure we have the canonical name for this field
243 $fieldName = CRM_Utils_Array::value('name', $fieldSpec, $fieldName);
244
245 // Return false if field doesn't exist.
246 if (empty($fieldSpec)) {
247 return FALSE;
248 }
249
250 elseif (!empty($fieldSpec['pseudoconstant'])) {
251 $pseudoconstant = $fieldSpec['pseudoconstant'];
252
253 // if callback is specified..
254 if (!empty($pseudoconstant['callback'])) {
255 $fieldOptions = call_user_func(Civi\Core\Resolver::singleton()->get($pseudoconstant['callback']));
256 //CRM-18223: Allow additions to field options via hook.
257 CRM_Utils_Hook::fieldOptions($entity, $fieldName, $fieldOptions, $params);
258 return $fieldOptions;
259 }
260
261 // Merge params with schema defaults
262 $params += array(
263 'condition' => CRM_Utils_Array::value('condition', $pseudoconstant, array()),
264 'keyColumn' => CRM_Utils_Array::value('keyColumn', $pseudoconstant),
265 'labelColumn' => CRM_Utils_Array::value('labelColumn', $pseudoconstant),
266 );
267
268 if ($context == 'abbreviate') {
269 switch ($fieldName) {
270 case 'state_province_id':
271 $params['labelColumn'] = 'abbreviation';
272 break;
273
274 case 'country_id':
275 $params['labelColumn'] = 'iso_code';
276 break;
277
278 default:
279 }
280 }
281
282 // Fetch option group from option_value table
283 if (!empty($pseudoconstant['optionGroupName'])) {
284 if ($context == 'validate') {
285 $params['labelColumn'] = 'name';
286 }
287 if ($context == 'match') {
288 $params['keyColumn'] = 'name';
289 }
290 // Call our generic fn for retrieving from the option_value table
291 $options = CRM_Core_OptionGroup::values(
292 $pseudoconstant['optionGroupName'],
293 $flip,
294 $params['grouping'],
295 $params['localize'],
296 $params['condition'] ? ' AND ' . implode(' AND ', (array) $params['condition']) : NULL,
297 $params['labelColumn'] ? $params['labelColumn'] : 'label',
298 $params['onlyActive'],
299 $params['fresh'],
300 $params['keyColumn'] ? $params['keyColumn'] : 'value',
301 !empty($params['orderColumn']) ? $params['orderColumn'] : 'weight'
302 );
303 CRM_Utils_Hook::fieldOptions($entity, $fieldName, $options, $params);
304 return $options;
305 }
306
307 // Fetch options from other tables
308 if (!empty($pseudoconstant['table'])) {
309 // Normalize params so the serialized cache string will be consistent.
310 CRM_Utils_Array::remove($params, 'flip', 'fresh');
311 ksort($params);
312 $cacheKey = $daoName . $fieldName . serialize($params);
313
314 // Retrieve cached options
315 if (isset(self::$cache[$cacheKey]) && empty($params['fresh'])) {
316 $output = self::$cache[$cacheKey];
317 }
318 else {
319 $daoName = CRM_Core_DAO_AllCoreTables::getClassForTable($pseudoconstant['table']);
320 if (!class_exists($daoName)) {
321 return FALSE;
322 }
323 // Get list of fields for the option table
324 $dao = new $daoName();
325 $availableFields = array_keys($dao->fieldKeys());
326 $dao->free();
327
328 $select = "SELECT %1 AS id, %2 AS label";
329 $from = "FROM %3";
330 $wheres = array();
331 $order = "ORDER BY %2";
332
333 // Use machine name in certain contexts
334 if ($context == 'validate' || $context == 'match') {
335 $nameField = $context == 'validate' ? 'labelColumn' : 'keyColumn';
336 if (!empty($pseudoconstant['nameColumn'])) {
337 $params[$nameField] = $pseudoconstant['nameColumn'];
338 }
339 elseif (in_array('name', $availableFields)) {
340 $params[$nameField] = 'name';
341 }
342 }
343 // Condition param can be passed as an sql clause string or an array of clauses
344 if (!empty($params['condition'])) {
345 $wheres[] = implode(' AND ', (array) $params['condition']);
346 }
347 // onlyActive param will automatically filter on common flags
348 if (!empty($params['onlyActive'])) {
349 foreach (array('is_active' => 1, 'is_deleted' => 0, 'is_test' => 0, 'is_hidden' => 0) as $flag => $val) {
350 if (in_array($flag, $availableFields)) {
351 $wheres[] = "$flag = $val";
352 }
353 }
354 }
355 // Filter domain specific options
356 if (in_array('domain_id', $availableFields)) {
357 $wheres[] = 'domain_id = ' . CRM_Core_Config::domainID();
358 }
359 $queryParams = array(
360 1 => array($params['keyColumn'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES),
361 2 => array($params['labelColumn'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES),
362 3 => array($pseudoconstant['table'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES),
363 );
364 // Add orderColumn param
365 if (!empty($params['orderColumn'])) {
366 $queryParams[4] = array($params['orderColumn'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES);
367 $order = "ORDER BY %4";
368 }
369 // Support no sorting if $params[orderColumn] is FALSE
370 elseif (isset($params['orderColumn']) && $params['orderColumn'] === FALSE) {
371 $order = '';
372 }
373 // Default to 'weight' if that column exists
374 elseif (in_array('weight', $availableFields)) {
375 $order = "ORDER BY weight";
376 }
377
378 $output = array();
379 $query = "$select $from";
380 if ($wheres) {
381 $query .= " WHERE " . implode($wheres, ' AND ');
382 }
383 $query .= ' ' . $order;
384 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
385 while ($dao->fetch()) {
386 $output[$dao->id] = $dao->label;
387 }
388 $dao->free();
389 // Localize results
390 if (!empty($params['localize']) || $pseudoconstant['table'] == 'civicrm_country' || $pseudoconstant['table'] == 'civicrm_state_province') {
391 $I18nParams = array();
392 if ($pseudoconstant['table'] == 'civicrm_country') {
393 $I18nParams['context'] = 'country';
394 }
395 if ($pseudoconstant['table'] == 'civicrm_state_province') {
396 $I18nParams['context'] = 'province';
397 }
398 $i18n = CRM_Core_I18n::singleton();
399 $i18n->localizeArray($output, $I18nParams);
400 // Maintain sort by label
401 if ($order == "ORDER BY %2") {
402 CRM_Utils_Array::asort($output);
403 }
404 }
405 CRM_Utils_Hook::fieldOptions($entity, $fieldName, $output, $params);
406 self::$cache[$cacheKey] = $output;
407 }
408 return $flip ? array_flip($output) : $output;
409 }
410 }
411
412 // Return "Yes" and "No" for boolean fields
413 elseif (CRM_Utils_Array::value('type', $fieldSpec) === CRM_Utils_Type::T_BOOLEAN) {
414 $output = $context == 'validate' ? array(0, 1) : CRM_Core_SelectValues::boolean();
415 CRM_Utils_Hook::fieldOptions($entity, $fieldName, $output, $params);
416 return $flip ? array_flip($output) : $output;
417 }
418 // If we're still here, it's an error. Return FALSE.
419 return FALSE;
420 }
421
422 /**
423 * Fetch the translated label for a field given its key.
424 *
425 * @param string $baoName
426 * @param string $fieldName
427 * @param string|Int $key
428 *
429 * TODO: Accept multivalued input?
430 *
431 * @return bool|null|string
432 * FALSE if the given field has no associated option list
433 * NULL if the given key has no corresponding option
434 * String if label is found
435 */
436 public static function getLabel($baoName, $fieldName, $key) {
437 $values = $baoName::buildOptions($fieldName, 'get');
438 if ($values === FALSE) {
439 return FALSE;
440 }
441 return CRM_Utils_Array::value($key, $values);
442 }
443
444 /**
445 * Fetch the machine name for a field given its key.
446 *
447 * @param string $baoName
448 * @param string $fieldName
449 * @param string|Int $key
450 *
451 * @return bool|null|string
452 * FALSE if the given field has no associated option list
453 * NULL if the given key has no corresponding option
454 * String if label is found
455 */
456 public static function getName($baoName, $fieldName, $key) {
457 $values = $baoName::buildOptions($fieldName, 'validate');
458 if ($values === FALSE) {
459 return FALSE;
460 }
461 return CRM_Utils_Array::value($key, $values);
462 }
463
464 /**
465 * Fetch the key for a field option given its name.
466 *
467 * @param string $baoName
468 * @param string $fieldName
469 * @param string|Int $value
470 *
471 * @return bool|null|string|int
472 * FALSE if the given field has no associated option list
473 * NULL if the given key has no corresponding option
474 * String|Number if key is found
475 */
476 public static function getKey($baoName, $fieldName, $value) {
477 $values = $baoName::buildOptions($fieldName, 'validate');
478 if ($values === FALSE) {
479 return FALSE;
480 }
481 return CRM_Utils_Array::key($value, $values);
482 }
483
484 /**
485 * Lookup the admin page at which a field's option list can be edited
486 * @param $fieldSpec
487 * @return string|null
488 */
489 public static function getOptionEditUrl($fieldSpec) {
490 // If it's an option group, that's easy
491 if (!empty($fieldSpec['pseudoconstant']['optionGroupName'])) {
492 return 'civicrm/admin/options/' . $fieldSpec['pseudoconstant']['optionGroupName'];
493 }
494 // For everything else...
495 elseif (!empty($fieldSpec['pseudoconstant']['table'])) {
496 $daoName = CRM_Core_DAO_AllCoreTables::getClassForTable($fieldSpec['pseudoconstant']['table']);
497 if (!$daoName) {
498 return NULL;
499 }
500 // We don't have good mapping so have to do a bit of guesswork from the menu
501 list(, $parent, , $child) = explode('_', $daoName);
502 $sql = "SELECT path FROM civicrm_menu
503 WHERE page_callback LIKE '%CRM_Admin_Page_$child%' OR page_callback LIKE '%CRM_{$parent}_Page_$child%'
504 ORDER BY page_callback
505 LIMIT 1";
506 return CRM_Core_Dao::singleValueQuery($sql);
507 }
508 return NULL;
509 }
510
511 /**
512 * DEPRECATED generic populate method.
513 * All pseudoconstant functions that use this method are also @deprecated
514 *
515 * The static array $var is populated from the db
516 * using the <b>$name DAO</b>.
517 *
518 * Note: any database errors will be trapped by the DAO.
519 *
520 * @param array $var
521 * The associative array we will fill.
522 * @param string $name
523 * The name of the DAO.
524 * @param bool $all
525 * Get all objects. default is to get only active ones.
526 * @param string $retrieve
527 * The field that we are interested in (normally name, differs in some objects).
528 * @param string $filter
529 * The field that we want to filter the result set with.
530 * @param string $condition
531 * The condition that gets passed to the final query as the WHERE clause.
532 *
533 * @param bool $orderby
534 * @param string $key
535 * @param bool $force
536 *
537 * @return array
538 */
539 public static function populate(
540 &$var,
541 $name,
542 $all = FALSE,
543 $retrieve = 'name',
544 $filter = 'is_active',
545 $condition = NULL,
546 $orderby = NULL,
547 $key = 'id',
548 $force = NULL
549 ) {
550 $cacheKey = "CRM_PC_{$name}_{$all}_{$key}_{$retrieve}_{$filter}_{$condition}_{$orderby}";
551 $cache = CRM_Utils_Cache::singleton();
552 $var = $cache->get($cacheKey);
553 if ($var && empty($force)) {
554 return $var;
555 }
556
557 $object = new $name();
558
559 $object->selectAdd();
560 $object->selectAdd("$key, $retrieve");
561 if ($condition) {
562 $object->whereAdd($condition);
563 }
564
565 if (!$orderby) {
566 $object->orderBy($retrieve);
567 }
568 else {
569 $object->orderBy($orderby);
570 }
571
572 if (!$all) {
573 $object->$filter = 1;
574 }
575
576 $object->find();
577 $var = array();
578 while ($object->fetch()) {
579 $var[$object->$key] = $object->$retrieve;
580 }
581
582 $cache->set($cacheKey, $var);
583 }
584
585 /**
586 * Flush given pseudoconstant so it can be reread from db.
587 * nex time it's requested.
588 *
589 *
590 * @param bool|string $name pseudoconstant to be flushed
591 */
592 public static function flush($name = 'cache') {
593 if (isset(self::$$name)) {
594 self::$$name = NULL;
595 }
596 if ($name == 'cache') {
597 CRM_Core_OptionGroup::flushAll();
598 }
599 }
600
601 /**
602 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
603 *
604 * Get all Activty types.
605 *
606 * The static array activityType is returned
607 *
608 *
609 * @return array
610 * array reference of all activity types.
611 */
612 public static function &activityType() {
613 $args = func_get_args();
614 $all = CRM_Utils_Array::value(0, $args, TRUE);
615 $includeCaseActivities = CRM_Utils_Array::value(1, $args, FALSE);
616 $reset = CRM_Utils_Array::value(2, $args, FALSE);
617 $returnColumn = CRM_Utils_Array::value(3, $args, 'label');
618 $includeCampaignActivities = CRM_Utils_Array::value(4, $args, FALSE);
619 $onlyComponentActivities = CRM_Utils_Array::value(5, $args, FALSE);
620 $index = (int) $all . '_' . $returnColumn . '_' . (int) $includeCaseActivities;
621 $index .= '_' . (int) $includeCampaignActivities;
622 $index .= '_' . (int) $onlyComponentActivities;
623
624 if (NULL === self::$activityType) {
625 self::$activityType = array();
626 }
627
628 if (!isset(self::$activityType[$index]) || $reset) {
629 $condition = NULL;
630 if (!$all) {
631 $condition = 'AND filter = 0';
632 }
633 $componentClause = " v.component_id IS NULL";
634 if ($onlyComponentActivities) {
635 $componentClause = " v.component_id IS NOT NULL";
636 }
637
638 $componentIds = array();
639 $compInfo = CRM_Core_Component::getEnabledComponents();
640
641 // build filter for listing activity types only if their
642 // respective components are enabled
643 foreach ($compInfo as $compName => $compObj) {
644 if ($compName == 'CiviCase') {
645 if ($includeCaseActivities) {
646 $componentIds[] = $compObj->componentID;
647 }
648 }
649 elseif ($compName == 'CiviCampaign') {
650 if ($includeCampaignActivities) {
651 $componentIds[] = $compObj->componentID;
652 }
653 }
654 else {
655 $componentIds[] = $compObj->componentID;
656 }
657 }
658
659 if (count($componentIds)) {
660 $componentIds = implode(',', $componentIds);
661 $componentClause = " ($componentClause OR v.component_id IN ($componentIds))";
662 if ($onlyComponentActivities) {
663 $componentClause = " ( v.component_id IN ($componentIds ) )";
664 }
665 }
666 $condition = $condition . ' AND ' . $componentClause;
667
668 self::$activityType[$index] = CRM_Core_OptionGroup::values('activity_type', FALSE, FALSE, FALSE, $condition, $returnColumn);
669 }
670 return self::$activityType[$index];
671 }
672
673 /**
674 * Get all the State/Province from database.
675 *
676 * The static array stateProvince is returned, and if it's
677 * called the first time, the <b>State Province DAO</b> is used
678 * to get all the States.
679 *
680 * Note: any database errors will be trapped by the DAO.
681 *
682 *
683 * @param bool|int $id - Optional id to return
684 *
685 * @param bool $limit
686 *
687 * @return array
688 * array reference of all State/Provinces.
689 */
690 public static function &stateProvince($id = FALSE, $limit = TRUE) {
691 if (($id && !CRM_Utils_Array::value($id, self::$stateProvince)) || !self::$stateProvince || !$id) {
692 $whereClause = FALSE;
693 if ($limit) {
694 $countryIsoCodes = self::countryIsoCode();
695 $limitCodes = CRM_Core_BAO_Country::provinceLimit();
696 $limitIds = array();
697 foreach ($limitCodes as $code) {
698 $limitIds = array_merge($limitIds, array_keys($countryIsoCodes, $code));
699 }
700 if (!empty($limitIds)) {
701 $whereClause = 'country_id IN (' . implode(', ', $limitIds) . ')';
702 }
703 else {
704 $whereClause = FALSE;
705 }
706 }
707 self::populate(self::$stateProvince, 'CRM_Core_DAO_StateProvince', TRUE, 'name', 'is_active', $whereClause);
708
709 // localise the province names if in an non-en_US locale
710 global $tsLocale;
711 if ($tsLocale != '' and $tsLocale != 'en_US') {
712 $i18n = CRM_Core_I18n::singleton();
713 $i18n->localizeArray(self::$stateProvince, array(
714 'context' => 'province',
715 ));
716 self::$stateProvince = CRM_Utils_Array::asort(self::$stateProvince);
717 }
718 }
719 if ($id) {
720 if (array_key_exists($id, self::$stateProvince)) {
721 return self::$stateProvince[$id];
722 }
723 else {
724 $result = NULL;
725 return $result;
726 }
727 }
728 return self::$stateProvince;
729 }
730
731 /**
732 * Get all the State/Province abbreviations from the database.
733 *
734 * Same as above, except gets the abbreviations instead of the names.
735 *
736 *
737 * @param bool|int $id - Optional id to return
738 *
739 * @param bool $limit
740 *
741 * @return array
742 * array reference of all State/Province abbreviations.
743 */
744 public static function stateProvinceAbbreviation($id = FALSE, $limit = TRUE) {
745 if ($id && is_numeric($id)) {
746 if (!array_key_exists($id, (array) self::$stateProvinceAbbreviation)) {
747 $query = "SELECT abbreviation
748 FROM civicrm_state_province
749 WHERE id = %1";
750 $params = array(
751 1 => array(
752 $id,
753 'Integer',
754 ),
755 );
756 self::$stateProvinceAbbreviation[$id] = CRM_Core_DAO::singleValueQuery($query, $params);
757 }
758 return self::$stateProvinceAbbreviation[$id];
759 }
760 else {
761 $whereClause = FALSE;
762
763 if ($limit) {
764 $countryIsoCodes = self::countryIsoCode();
765 $limitCodes = CRM_Core_BAO_Country::provinceLimit();
766 $limitIds = array();
767 foreach ($limitCodes as $code) {
768 $tmpArray = array_keys($countryIsoCodes, $code);
769
770 if (!empty($tmpArray)) {
771 $limitIds[] = array_shift($tmpArray);
772 }
773 }
774 if (!empty($limitIds)) {
775 $whereClause = 'country_id IN (' . implode(', ', $limitIds) . ')';
776 }
777 }
778 self::populate(self::$stateProvinceAbbreviation, 'CRM_Core_DAO_StateProvince', TRUE, 'abbreviation', 'is_active', $whereClause);
779 }
780
781 return self::$stateProvinceAbbreviation;
782 }
783
784 /**
785 * Get all the countries from database.
786 *
787 * The static array country is returned, and if it's
788 * called the first time, the <b>Country DAO</b> is used
789 * to get all the countries.
790 *
791 * Note: any database errors will be trapped by the DAO.
792 *
793 *
794 * @param bool|int $id - Optional id to return
795 *
796 * @param bool $applyLimit
797 *
798 * @return array
799 * array reference of all countries.
800 */
801 public static function country($id = FALSE, $applyLimit = TRUE) {
802 if (($id && !CRM_Utils_Array::value($id, self::$country)) || !self::$country || !$id) {
803
804 $config = CRM_Core_Config::singleton();
805 $limitCodes = array();
806
807 if ($applyLimit) {
808 // limit the country list to the countries specified in CIVICRM_COUNTRY_LIMIT
809 // (ensuring it's a subset of the legal values)
810 // K/P: We need to fix this, i dont think it works with new setting files
811 $limitCodes = CRM_Core_BAO_Country::countryLimit();
812 if (!is_array($limitCodes)) {
813 $limitCodes = array(
814 $config->countryLimit => 1,
815 );
816 }
817
818 $limitCodes = array_intersect(self::countryIsoCode(), $limitCodes);
819 }
820
821 if (count($limitCodes)) {
822 $whereClause = "iso_code IN ('" . implode("', '", $limitCodes) . "')";
823 }
824 else {
825 $whereClause = NULL;
826 }
827
828 self::populate(self::$country, 'CRM_Core_DAO_Country', TRUE, 'name', 'is_active', $whereClause);
829
830 // if default country is set, percolate it to the top
831 if ($config->defaultContactCountry()) {
832 $countryIsoCodes = self::countryIsoCode();
833 $defaultID = array_search($config->defaultContactCountry(), $countryIsoCodes);
834 if ($defaultID !== FALSE) {
835 $default[$defaultID] = CRM_Utils_Array::value($defaultID, self::$country);
836 self::$country = $default + self::$country;
837 }
838 }
839
840 // localise the country names if in an non-en_US locale
841 global $tsLocale;
842 if ($tsLocale != '' and $tsLocale != 'en_US') {
843 $i18n = CRM_Core_I18n::singleton();
844 $i18n->localizeArray(self::$country, array(
845 'context' => 'country',
846 ));
847 self::$country = CRM_Utils_Array::asort(self::$country);
848 }
849 }
850 if ($id) {
851 if (array_key_exists($id, self::$country)) {
852 return self::$country[$id];
853 }
854 else {
855 return CRM_Core_DAO::$_nullObject;
856 }
857 }
858 return self::$country;
859 }
860
861 /**
862 * Get all the country ISO Code abbreviations from the database.
863 *
864 * The static array countryIsoCode is returned, and if it's
865 * called the first time, the <b>Country DAO</b> is used
866 * to get all the countries' ISO codes.
867 *
868 * Note: any database errors will be trapped by the DAO.
869 *
870 *
871 * @param bool $id
872 *
873 * @return array
874 * array reference of all country ISO codes.
875 */
876 public static function &countryIsoCode($id = FALSE) {
877 if (!self::$countryIsoCode) {
878 self::populate(self::$countryIsoCode, 'CRM_Core_DAO_Country', TRUE, 'iso_code');
879 }
880 if ($id) {
881 if (array_key_exists($id, self::$countryIsoCode)) {
882 return self::$countryIsoCode[$id];
883 }
884 else {
885 return CRM_Core_DAO::$_nullObject;
886 }
887 }
888 return self::$countryIsoCode;
889 }
890
891 /**
892 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
893 *
894 * Get all groups from database
895 *
896 * The static array group is returned, and if it's
897 * called the first time, the <b>Group DAO</b> is used
898 * to get all the groups.
899 *
900 * Note: any database errors will be trapped by the DAO.
901 *
902 * @param string $groupType
903 * Type of group(Access/Mailing).
904 * @param bool $excludeHidden
905 * Exclude hidden groups.
906 *
907 *
908 * @return array
909 * array reference of all groups.
910 */
911 public static function allGroup($groupType = NULL, $excludeHidden = TRUE) {
912 $condition = CRM_Contact_BAO_Group::groupTypeCondition($groupType, $excludeHidden);
913
914 if (!self::$group) {
915 self::$group = array();
916 }
917
918 $groupKey = ($groupType ? $groupType : 'null') . !empty($excludeHidden);
919
920 if (!isset(self::$group[$groupKey])) {
921 self::$group[$groupKey] = NULL;
922 self::populate(self::$group[$groupKey], 'CRM_Contact_DAO_Group', FALSE, 'title', 'is_active', $condition);
923 }
924 return self::$group[$groupKey];
925 }
926
927 /**
928 * Create or get groups iterator (iterates over nested groups in a
929 * logical fashion)
930 *
931 * The GroupNesting instance is returned; it's created if this is being
932 * called for the first time
933 *
934 *
935 *
936 * @param bool $styledLabels
937 *
938 * @return CRM_Contact_BAO_GroupNesting
939 */
940 public static function &groupIterator($styledLabels = FALSE) {
941 if (!self::$groupIterator) {
942 // When used as an object, GroupNesting implements Iterator
943 // and iterates nested groups in a logical manner for us
944 self::$groupIterator = new CRM_Contact_BAO_GroupNesting($styledLabels);
945 }
946 return self::$groupIterator;
947 }
948
949 /**
950 * Get all permissioned groups from database.
951 *
952 * The static array group is returned, and if it's
953 * called the first time, the <b>Group DAO</b> is used
954 * to get all the groups.
955 *
956 * Note: any database errors will be trapped by the DAO.
957 *
958 * @param string $groupType
959 * Type of group(Access/Mailing).
960 * @param bool $excludeHidden
961 * Exclude hidden groups.
962 *
963 *
964 * @return array
965 * array reference of all groups.
966 */
967 public static function group($groupType = NULL, $excludeHidden = TRUE) {
968 return CRM_Core_Permission::group($groupType, $excludeHidden);
969 }
970
971 /**
972 * Fetch groups in a nested format suitable for use in select form element.
973 * @param bool $checkPermissions
974 * @param string|null $groupType
975 * @param bool $excludeHidden
976 * @return array
977 */
978 public static function nestedGroup($checkPermissions = TRUE, $groupType = NULL, $excludeHidden = TRUE) {
979 $groups = $checkPermissions ? self::group($groupType, $excludeHidden) : self::allGroup($groupType, $excludeHidden);
980 return CRM_Contact_BAO_Group::getGroupsHierarchy($groups, NULL, '&nbsp;&nbsp;', TRUE);
981 }
982
983 /**
984 * Get all permissioned groups from database.
985 *
986 * The static array group is returned, and if it's
987 * called the first time, the <b>Group DAO</b> is used
988 * to get all the groups.
989 *
990 * Note: any database errors will be trapped by the DAO.
991 *
992 *
993 * @param bool $onlyPublic
994 * @param null $groupType
995 * @param bool $excludeHidden
996 *
997 * @return array
998 * array reference of all groups.
999 */
1000 public static function &staticGroup($onlyPublic = FALSE, $groupType = NULL, $excludeHidden = TRUE) {
1001 if (!self::$staticGroup) {
1002 $condition = 'saved_search_id = 0 OR saved_search_id IS NULL';
1003 if ($onlyPublic) {
1004 $condition .= " AND visibility != 'User and User Admin Only'";
1005 }
1006
1007 if ($groupType) {
1008 $condition .= ' AND ' . CRM_Contact_BAO_Group::groupTypeCondition($groupType);
1009 }
1010
1011 if ($excludeHidden) {
1012 $condition .= ' AND is_hidden != 1 ';
1013 }
1014
1015 self::populate(self::$staticGroup, 'CRM_Contact_DAO_Group', FALSE, 'title', 'is_active', $condition, 'title');
1016 }
1017
1018 return self::$staticGroup;
1019 }
1020
1021 /**
1022 * Get all Relationship Types from database.
1023 *
1024 * The static array group is returned, and if it's
1025 * called the first time, the <b>RelationshipType DAO</b> is used
1026 * to get all the relationship types.
1027 *
1028 * Note: any database errors will be trapped by the DAO.
1029 *
1030 * @param string $valueColumnName
1031 * Db column name/label.
1032 * @param bool $reset
1033 * Reset relationship types if true.
1034 * @param bool|NULL $isActive
1035 * Filter by is_active. NULL to disable.
1036 *
1037 * @return array
1038 * array reference of all relationship types.
1039 */
1040 public static function &relationshipType($valueColumnName = 'label', $reset = FALSE, $isActive = 1) {
1041 $cacheKey = $valueColumnName . '::' . $isActive;
1042 if (!CRM_Utils_Array::value($cacheKey, self::$relationshipType) || $reset) {
1043 self::$relationshipType[$cacheKey] = array();
1044
1045 //now we have name/label columns CRM-3336
1046 $column_a_b = "{$valueColumnName}_a_b";
1047 $column_b_a = "{$valueColumnName}_b_a";
1048
1049 $relationshipTypeDAO = new CRM_Contact_DAO_RelationshipType();
1050 $relationshipTypeDAO->selectAdd();
1051 $relationshipTypeDAO->selectAdd("id, {$column_a_b}, {$column_b_a}, contact_type_a, contact_type_b, contact_sub_type_a, contact_sub_type_b");
1052 if ($isActive !== NULL) {
1053 $relationshipTypeDAO->is_active = $isActive;
1054 }
1055 $relationshipTypeDAO->find();
1056 while ($relationshipTypeDAO->fetch()) {
1057
1058 self::$relationshipType[$cacheKey][$relationshipTypeDAO->id] = array(
1059 'id' => $relationshipTypeDAO->id,
1060 $column_a_b => $relationshipTypeDAO->$column_a_b,
1061 $column_b_a => $relationshipTypeDAO->$column_b_a,
1062 'contact_type_a' => "$relationshipTypeDAO->contact_type_a",
1063 'contact_type_b' => "$relationshipTypeDAO->contact_type_b",
1064 'contact_sub_type_a' => "$relationshipTypeDAO->contact_sub_type_a",
1065 'contact_sub_type_b' => "$relationshipTypeDAO->contact_sub_type_b",
1066 );
1067 }
1068 }
1069
1070 return self::$relationshipType[$cacheKey];
1071 }
1072
1073 /**
1074 * Get all the ISO 4217 currency codes
1075 *
1076 * so far, we use this for validation only, so there's no point of putting this into the database
1077 *
1078 *
1079 * @return array
1080 * array reference of all currency codes
1081 */
1082 public static function &currencyCode() {
1083 if (!self::$currencyCode) {
1084 self::$currencyCode = array(
1085 'AFN',
1086 'ALL',
1087 'DZD',
1088 'USD',
1089 'EUR',
1090 'AOA',
1091 'XCD',
1092 'XCD',
1093 'ARS',
1094 'AMD',
1095 'AWG',
1096 'AUD',
1097 'EUR',
1098 'AZM',
1099 'BSD',
1100 'BHD',
1101 'BDT',
1102 'BBD',
1103 'BYR',
1104 'EUR',
1105 'BZD',
1106 'XOF',
1107 'BMD',
1108 'INR',
1109 'BTN',
1110 'BOB',
1111 'BOV',
1112 'BAM',
1113 'BWP',
1114 'NOK',
1115 'BRL',
1116 'USD',
1117 'BND',
1118 'BGN',
1119 'XOF',
1120 'BIF',
1121 'KHR',
1122 'XAF',
1123 'CAD',
1124 'CVE',
1125 'KYD',
1126 'XAF',
1127 'XAF',
1128 'CLP',
1129 'CLF',
1130 'CNY',
1131 'AUD',
1132 'AUD',
1133 'COP',
1134 'COU',
1135 'KMF',
1136 'XAF',
1137 'CDF',
1138 'NZD',
1139 'CRC',
1140 'XOF',
1141 'HRK',
1142 'CUP',
1143 'CYP',
1144 'CZK',
1145 'DKK',
1146 'DJF',
1147 'XCD',
1148 'DOP',
1149 'USD',
1150 'EGP',
1151 'SVC',
1152 'USD',
1153 'XAF',
1154 'ERN',
1155 'EEK',
1156 'ETB',
1157 'FKP',
1158 'DKK',
1159 'FJD',
1160 'EUR',
1161 'EUR',
1162 'EUR',
1163 'XPF',
1164 'EUR',
1165 'XAF',
1166 'GMD',
1167 'GEL',
1168 'EUR',
1169 'GHC',
1170 'GIP',
1171 'EUR',
1172 'DKK',
1173 'XCD',
1174 'EUR',
1175 'USD',
1176 'GTQ',
1177 'GNF',
1178 'GWP',
1179 'XOF',
1180 'GYD',
1181 'HTG',
1182 'USD',
1183 'AUD',
1184 'EUR',
1185 'HNL',
1186 'HKD',
1187 'HUF',
1188 'ISK',
1189 'INR',
1190 'IDR',
1191 'XDR',
1192 'IRR',
1193 'IQD',
1194 'EUR',
1195 'ILS',
1196 'EUR',
1197 'JMD',
1198 'JPY',
1199 'JOD',
1200 'KZT',
1201 'KES',
1202 'AUD',
1203 'KPW',
1204 'KRW',
1205 'KWD',
1206 'KGS',
1207 'LAK',
1208 'LVL',
1209 'LBP',
1210 'ZAR',
1211 'LSL',
1212 'LRD',
1213 'LYD',
1214 'CHF',
1215 'LTL',
1216 'EUR',
1217 'MOP',
1218 'MKD',
1219 'MGA',
1220 'MWK',
1221 'MYR',
1222 'MVR',
1223 'XOF',
1224 'MTL',
1225 'USD',
1226 'EUR',
1227 'MRO',
1228 'MUR',
1229 'EUR',
1230 'MXN',
1231 'MXV',
1232 'USD',
1233 'MDL',
1234 'EUR',
1235 'MNT',
1236 'XCD',
1237 'MAD',
1238 'MZM',
1239 'MMK',
1240 'ZAR',
1241 'NAD',
1242 'AUD',
1243 'NPR',
1244 'EUR',
1245 'ANG',
1246 'XPF',
1247 'NZD',
1248 'NIO',
1249 'XOF',
1250 'NGN',
1251 'NZD',
1252 'AUD',
1253 'USD',
1254 'NOK',
1255 'OMR',
1256 'PKR',
1257 'USD',
1258 'PAB',
1259 'USD',
1260 'PGK',
1261 'PYG',
1262 'PEN',
1263 'PHP',
1264 'NZD',
1265 'PLN',
1266 'EUR',
1267 'USD',
1268 'QAR',
1269 'EUR',
1270 'ROL',
1271 'RON',
1272 'RUB',
1273 'RWF',
1274 'SHP',
1275 'XCD',
1276 'XCD',
1277 'EUR',
1278 'XCD',
1279 'WST',
1280 'EUR',
1281 'STD',
1282 'SAR',
1283 'XOF',
1284 'CSD',
1285 'EUR',
1286 'SCR',
1287 'SLL',
1288 'SGD',
1289 'SKK',
1290 'SIT',
1291 'SBD',
1292 'SOS',
1293 'ZAR',
1294 'EUR',
1295 'LKR',
1296 'SDD',
1297 'SRD',
1298 'NOK',
1299 'SZL',
1300 'SEK',
1301 'CHF',
1302 'CHW',
1303 'CHE',
1304 'SYP',
1305 'TWD',
1306 'TJS',
1307 'TZS',
1308 'THB',
1309 'USD',
1310 'XOF',
1311 'NZD',
1312 'TOP',
1313 'TTD',
1314 'TND',
1315 'TRY',
1316 'TRL',
1317 'TMM',
1318 'USD',
1319 'AUD',
1320 'UGX',
1321 'UAH',
1322 'AED',
1323 'GBP',
1324 'USD',
1325 'USS',
1326 'USN',
1327 'USD',
1328 'UYU',
1329 'UZS',
1330 'VUV',
1331 'VEB',
1332 'VND',
1333 'USD',
1334 'USD',
1335 'XPF',
1336 'MAD',
1337 'YER',
1338 'ZMK',
1339 'ZWD',
1340 'XAU',
1341 'XBA',
1342 'XBB',
1343 'XBC',
1344 'XBD',
1345 'XPD',
1346 'XPT',
1347 'XAG',
1348 'XFU',
1349 'XFO',
1350 'XTS',
1351 'XXX',
1352 );
1353 }
1354 return self::$currencyCode;
1355 }
1356
1357 /**
1358 * Get all the County from database.
1359 *
1360 * The static array county is returned, and if it's
1361 * called the first time, the <b>County DAO</b> is used
1362 * to get all the Counties.
1363 *
1364 * Note: any database errors will be trapped by the DAO.
1365 *
1366 *
1367 * @param bool|int $id - Optional id to return
1368 *
1369 * @return array
1370 * array reference of all Counties
1371 */
1372 public static function &county($id = FALSE) {
1373 if (!self::$county) {
1374
1375 $config = CRM_Core_Config::singleton();
1376 // order by id so users who populate civicrm_county can have more control over sort by the order they load the counties
1377 self::populate(self::$county, 'CRM_Core_DAO_County', TRUE, 'name', NULL, NULL, 'id');
1378 }
1379 if ($id) {
1380 if (array_key_exists($id, self::$county)) {
1381 return self::$county[$id];
1382 }
1383 else {
1384 return CRM_Core_DAO::$_nullObject;
1385 }
1386 }
1387 return self::$county;
1388 }
1389
1390 /**
1391 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
1392 * Get all active payment processors
1393 *
1394 * The static array paymentProcessor is returned
1395 *
1396 *
1397 * @param bool $all
1398 * Get payment processors - default is to get only active ones.
1399 * @param bool $test
1400 * Get test payment processors.
1401 *
1402 * @param null $additionalCond
1403 *
1404 * @return array
1405 * array of all payment processors
1406 */
1407 public static function paymentProcessor($all = FALSE, $test = FALSE, $additionalCond = NULL) {
1408 $condition = "is_test = ";
1409 $condition .= ($test) ? '1' : '0';
1410
1411 if ($additionalCond) {
1412 $condition .= " AND ( $additionalCond ) ";
1413 }
1414
1415 // CRM-7178. Make sure we only include payment processors valid in this
1416 // domain
1417 $condition .= " AND domain_id = " . CRM_Core_Config::domainID();
1418
1419 $cacheKey = $condition . '_' . (int) $all;
1420 if (!isset(self::$paymentProcessor[$cacheKey])) {
1421 self::populate(self::$paymentProcessor[$cacheKey], 'CRM_Financial_DAO_PaymentProcessor', $all, 'name', 'is_active', $condition, 'is_default desc, name');
1422 }
1423
1424 return self::$paymentProcessor[$cacheKey];
1425 }
1426
1427 /**
1428 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
1429 *
1430 * The static array paymentProcessorType is returned
1431 *
1432 *
1433 * @param bool $all
1434 * Get payment processors - default is to get only active ones.
1435 *
1436 * @param int $id
1437 * @param string $return
1438 *
1439 * @return array
1440 * array of all payment processor types
1441 */
1442 public static function &paymentProcessorType($all = FALSE, $id = NULL, $return = 'title') {
1443 $cacheKey = $id . '_' . $return;
1444 if (empty(self::$paymentProcessorType[$cacheKey])) {
1445 self::populate(self::$paymentProcessorType[$cacheKey], 'CRM_Financial_DAO_PaymentProcessorType', $all, $return, 'is_active', NULL, "is_default, $return", 'id');
1446 }
1447 if ($id && CRM_Utils_Array::value($id, self::$paymentProcessorType[$cacheKey])) {
1448 return self::$paymentProcessorType[$cacheKey][$id];
1449 }
1450 return self::$paymentProcessorType[$cacheKey];
1451 }
1452
1453 /**
1454 * Get all the World Regions from Database.
1455 *
1456 *
1457 * @param bool $id
1458 *
1459 * @return array
1460 * array reference of all World Regions
1461 */
1462 public static function &worldRegion($id = FALSE) {
1463 if (!self::$worldRegions) {
1464 self::populate(self::$worldRegions, 'CRM_Core_DAO_Worldregion', TRUE, 'name', NULL, NULL, 'id');
1465 }
1466
1467 if ($id) {
1468 if (array_key_exists($id, self::$worldRegions)) {
1469 return self::$worldRegions[$id];
1470 }
1471 else {
1472 return CRM_Core_DAO::$_nullObject;
1473 }
1474 }
1475
1476 return self::$worldRegions;
1477 }
1478
1479 /**
1480 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
1481 *
1482 * Get all Activity Statuses.
1483 *
1484 * The static array activityStatus is returned
1485 *
1486 *
1487 * @param string $column
1488 *
1489 * @return array
1490 * array reference of all activity statuses
1491 */
1492 public static function &activityStatus($column = 'label') {
1493 if (NULL === self::$activityStatus) {
1494 self::$activityStatus = array();
1495 }
1496 if (!array_key_exists($column, self::$activityStatus)) {
1497 self::$activityStatus[$column] = array();
1498
1499 self::$activityStatus[$column] = CRM_Core_OptionGroup::values('activity_status', FALSE, FALSE, FALSE, NULL, $column);
1500 }
1501
1502 return self::$activityStatus[$column];
1503 }
1504
1505 /**
1506 * @deprecated Please use the buildOptions() method in the appropriate BAO object.
1507 *
1508 * Get all Visibility levels.
1509 *
1510 * The static array visibility is returned
1511 *
1512 *
1513 * @param string $column
1514 *
1515 * @return array
1516 * array reference of all Visibility levels.
1517 */
1518 public static function &visibility($column = 'label') {
1519 if (!isset(self::$visibility)) {
1520 self::$visibility = array();
1521 }
1522
1523 if (!isset(self::$visibility[$column])) {
1524 self::$visibility[$column] = CRM_Core_OptionGroup::values('visibility', FALSE, FALSE, FALSE, NULL, $column);
1525 }
1526
1527 return self::$visibility[$column];
1528 }
1529
1530 /**
1531 * @param int $countryID
1532 * @param string $field
1533 *
1534 * @return array
1535 */
1536 public static function &stateProvinceForCountry($countryID, $field = 'name') {
1537 static $_cache = NULL;
1538
1539 $cacheKey = "{$countryID}_{$field}";
1540 if (!$_cache) {
1541 $_cache = array();
1542 }
1543
1544 if (!empty($_cache[$cacheKey])) {
1545 return $_cache[$cacheKey];
1546 }
1547
1548 $query = "
1549 SELECT civicrm_state_province.{$field} name, civicrm_state_province.id id
1550 FROM civicrm_state_province
1551 WHERE country_id = %1
1552 ORDER BY name";
1553 $params = array(
1554 1 => array(
1555 $countryID,
1556 'Integer',
1557 ),
1558 );
1559
1560 $dao = CRM_Core_DAO::executeQuery($query, $params);
1561
1562 $result = array();
1563 while ($dao->fetch()) {
1564 $result[$dao->id] = $dao->name;
1565 }
1566
1567 // localise the stateProvince names if in an non-en_US locale
1568 $config = CRM_Core_Config::singleton();
1569 global $tsLocale;
1570 if ($tsLocale != '' and $tsLocale != 'en_US') {
1571 $i18n = CRM_Core_I18n::singleton();
1572 $i18n->localizeArray($result, array(
1573 'context' => 'province',
1574 ));
1575 $result = CRM_Utils_Array::asort($result);
1576 }
1577
1578 $_cache[$cacheKey] = $result;
1579
1580 CRM_Utils_Hook::buildStateProvinceForCountry($countryID, $result);
1581
1582 return $result;
1583 }
1584
1585 /**
1586 * @param int $stateID
1587 *
1588 * @return array
1589 */
1590 public static function &countyForState($stateID) {
1591 if (is_array($stateID)) {
1592 $states = implode(", ", $stateID);
1593 $query = "
1594 SELECT civicrm_county.name name, civicrm_county.id id, civicrm_state_province.abbreviation abbreviation
1595 FROM civicrm_county
1596 LEFT JOIN civicrm_state_province ON civicrm_county.state_province_id = civicrm_state_province.id
1597 WHERE civicrm_county.state_province_id in ( $states )
1598 ORDER BY civicrm_state_province.abbreviation, civicrm_county.name";
1599
1600 $dao = CRM_Core_DAO::executeQuery($query);
1601
1602 $result = array();
1603 while ($dao->fetch()) {
1604 $result[$dao->id] = $dao->abbreviation . ': ' . $dao->name;
1605 }
1606 }
1607 else {
1608
1609 static $_cache = NULL;
1610
1611 $cacheKey = "{$stateID}_name";
1612 if (!$_cache) {
1613 $_cache = array();
1614 }
1615
1616 if (!empty($_cache[$cacheKey])) {
1617 return $_cache[$cacheKey];
1618 }
1619
1620 $query = "
1621 SELECT civicrm_county.name name, civicrm_county.id id
1622 FROM civicrm_county
1623 WHERE state_province_id = %1
1624 ORDER BY name";
1625 $params = array(
1626 1 => array(
1627 $stateID,
1628 'Integer',
1629 ),
1630 );
1631
1632 $dao = CRM_Core_DAO::executeQuery($query, $params);
1633
1634 $result = array();
1635 while ($dao->fetch()) {
1636 $result[$dao->id] = $dao->name;
1637 }
1638 }
1639
1640 return $result;
1641 }
1642
1643 /**
1644 * Given a state ID return the country ID, this allows
1645 * us to populate forms and values for downstream code
1646 *
1647 * @param int $stateID
1648 *
1649 * @return int
1650 * the country id that the state belongs to
1651 */
1652 public static function countryIDForStateID($stateID) {
1653 if (empty($stateID)) {
1654 return CRM_Core_DAO::$_nullObject;
1655 }
1656
1657 $query = "
1658 SELECT country_id
1659 FROM civicrm_state_province
1660 WHERE id = %1
1661 ";
1662 $params = array(1 => array($stateID, 'Integer'));
1663
1664 return CRM_Core_DAO::singleValueQuery($query, $params);
1665 }
1666
1667 /**
1668 * Get all types of Greetings.
1669 *
1670 * The static array of greeting is returned
1671 *
1672 *
1673 * @param $filter
1674 * Get All Email Greetings - default is to get only active ones.
1675 *
1676 * @param string $columnName
1677 *
1678 * @return array
1679 * array reference of all greetings.
1680 */
1681 public static function greeting($filter, $columnName = 'label') {
1682 $index = $filter['greeting_type'] . '_' . $columnName;
1683
1684 // also add contactType to the array
1685 $contactType = CRM_Utils_Array::value('contact_type', $filter);
1686 if ($contactType) {
1687 $index .= '_' . $contactType;
1688 }
1689
1690 if (NULL === self::$greeting) {
1691 self::$greeting = array();
1692 }
1693
1694 if (!CRM_Utils_Array::value($index, self::$greeting)) {
1695 $filterCondition = NULL;
1696 if ($contactType) {
1697 $filterVal = 'v.filter =';
1698 switch ($contactType) {
1699 case 'Individual':
1700 $filterVal .= "1";
1701 break;
1702
1703 case 'Household':
1704 $filterVal .= "2";
1705 break;
1706
1707 case 'Organization':
1708 $filterVal .= "3";
1709 break;
1710 }
1711 $filterCondition .= "AND (v.filter = 0 OR {$filterVal}) ";
1712 }
1713
1714 self::$greeting[$index] = CRM_Core_OptionGroup::values($filter['greeting_type'], NULL, NULL, NULL, $filterCondition, $columnName);
1715 }
1716
1717 return self::$greeting[$index];
1718 }
1719
1720 /**
1721 * Construct array of default greeting values for contact type.
1722 *
1723 *
1724 * @return array
1725 * array reference of default greetings.
1726 */
1727 public static function &greetingDefaults() {
1728 if (!self::$greetingDefaults) {
1729 $defaultGreetings = array();
1730 $contactTypes = self::get('CRM_Contact_DAO_Contact', 'contact_type', array(
1731 'keyColumn' => 'id',
1732 'labelColumn' => 'name',
1733 ));
1734
1735 foreach ($contactTypes as $filter => $contactType) {
1736 $filterCondition = " AND (v.filter = 0 OR v.filter = $filter) AND v.is_default = 1 ";
1737
1738 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
1739 $tokenVal = CRM_Core_OptionGroup::values($greeting, NULL, NULL, NULL, $filterCondition, 'label');
1740 $defaultGreetings[$contactType][$greeting] = $tokenVal;
1741 }
1742 }
1743
1744 self::$greetingDefaults = $defaultGreetings;
1745 }
1746
1747 return self::$greetingDefaults;
1748 }
1749
1750 /**
1751 * Get all extensions.
1752 *
1753 * The static array extensions
1754 *
1755 * FIXME: This is called by civix but not by any core code. We
1756 * should provide an API call which civix can use instead.
1757 *
1758 *
1759 * @return array
1760 * array($fullyQualifiedName => $label) list of extensions
1761 */
1762 public static function &getExtensions() {
1763 if (!self::$extensions) {
1764 self::$extensions = array();
1765 $sql = '
1766 SELECT full_name, label
1767 FROM civicrm_extension
1768 WHERE is_active = 1
1769 ';
1770 $dao = CRM_Core_DAO::executeQuery($sql);
1771 while ($dao->fetch()) {
1772 self::$extensions[$dao->full_name] = $dao->label;
1773 }
1774 }
1775
1776 return self::$extensions;
1777 }
1778
1779 /**
1780 * Get all options values.
1781 *
1782 * The static array option values is returned
1783 *
1784 *
1785 * @param bool $optionGroupName
1786 * Get All Option Group values- default is to get only active ones.
1787 *
1788 * @param int $id
1789 * @param null $condition
1790 *
1791 * @return array
1792 * array reference of all Option Group Name
1793 */
1794 public static function accountOptionValues($optionGroupName, $id = NULL, $condition = NULL) {
1795 $cacheKey = $optionGroupName . '_' . $condition;
1796 if (empty(self::$accountOptionValues[$cacheKey])) {
1797 self::$accountOptionValues[$cacheKey] = CRM_Core_OptionGroup::values($optionGroupName, FALSE, FALSE, FALSE, $condition);
1798 }
1799 if ($id) {
1800 return CRM_Utils_Array::value($id, self::$accountOptionValues[$cacheKey]);
1801 }
1802
1803 return self::$accountOptionValues[$cacheKey];
1804 }
1805
1806 /**
1807 * Fetch the list of active extensions of type 'module'
1808 *
1809 * @param bool $fresh
1810 * Whether to forcibly reload extensions list from canonical store.
1811 *
1812 * @return array
1813 * array(array('prefix' => $, 'file' => $))
1814 */
1815 public static function getModuleExtensions($fresh = FALSE) {
1816 return CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles($fresh);
1817 }
1818
1819
1820 /**
1821 * Get all tax rates.
1822 *
1823 * The static array tax rates is returned
1824 *
1825 * @return array
1826 * array list of tax rates with the financial type
1827 */
1828 public static function getTaxRates() {
1829 if (!isset(Civi::$statics[__CLASS__]['taxRates'])) {
1830 Civi::$statics[__CLASS__]['taxRates'] = array();
1831 $sql = "
1832 SELECT fa.tax_rate, efa.entity_id
1833 FROM civicrm_entity_financial_account efa
1834 INNER JOIN civicrm_financial_account fa ON fa.id = efa.financial_account_id
1835 INNER JOIN civicrm_option_value cov ON cov.value = efa.account_relationship
1836 INNER JOIN civicrm_option_group cog ON cog.id = cov.option_group_id
1837 WHERE efa.entity_table = 'civicrm_financial_type'
1838 AND cov.name = 'Sales Tax Account is'
1839 AND cog.name = 'account_relationship'
1840 AND fa.is_active = 1";
1841 $dao = CRM_Core_DAO::executeQuery($sql);
1842 while ($dao->fetch()) {
1843 Civi::$statics[__CLASS__]['taxRates'][$dao->entity_id] = $dao->tax_rate;
1844 }
1845 }
1846
1847 return Civi::$statics[__CLASS__]['taxRates'];
1848 }
1849
1850 }