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