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