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