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