4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
18 class CRM_Core_DAO_AllCoreTables
{
20 private static $tables = NULL;
21 private static $daoToClass = NULL;
22 private static $entityTypes = NULL;
29 public static function init($fresh = FALSE) {
31 if ($init && !$fresh) {
34 Civi
::$statics[__CLASS__
] = [];
36 $file = preg_replace('/\.php$/', '.data.php', __FILE__
);
37 $entityTypes = require $file;
38 CRM_Utils_Hook
::entityTypes($entityTypes);
40 self
::$entityTypes = [];
42 self
::$daoToClass = [];
43 foreach ($entityTypes as $entityType) {
44 self
::registerEntityType(
48 $entityType['fields_callback'] ??
NULL,
49 $entityType['links_callback'] ??
NULL
57 * (Quasi-Private) Do not call externally (except for unit-testing)
59 * @param string $briefName
60 * @param string $className
61 * @param string $tableName
62 * @param string $fields_callback
63 * @param string $links_callback
65 public static function registerEntityType($briefName, $className, $tableName, $fields_callback = NULL, $links_callback = NULL) {
66 self
::$daoToClass[$briefName] = $className;
67 self
::$tables[$tableName] = $className;
68 self
::$entityTypes[$briefName] = [
70 'class' => $className,
71 'table' => $tableName,
72 'fields_callback' => $fields_callback,
73 'links_callback' => $links_callback,
79 * Ex: $result['Contact']['table'] == 'civicrm_contact';
81 public static function get() {
83 return self
::$entityTypes;
88 * List of SQL table names.
90 public static function tables() {
99 public static function indices($localize = TRUE) {
102 foreach (self
::$daoToClass as $class) {
103 if (is_callable([$class, 'indices'])) {
104 $indices[$class::getTableName()] = $class::indices($localize);
111 * Modify indices to account for localization options.
113 * @param string $class DAO class
114 * @param array $originalIndices index definitions before localization
117 * index definitions after localization
119 public static function multilingualize($class, $originalIndices) {
120 $locales = CRM_Core_I18n
::getMultilingual();
122 return $originalIndices;
124 $classFields = $class::fields();
127 foreach ($originalIndices as $index) {
128 if ($index['localizable']) {
129 foreach ($locales as $locale) {
130 $localIndex = $index;
131 $localIndex['name'] .= "_" . $locale;
133 foreach ($localIndex['field'] as $field) {
134 $baseField = explode('(', $field);
135 if ($classFields[$baseField[0]]['localizable']) {
136 // field name may have eg (3) at end for prefix length
137 // last_name => last_name_fr_FR
138 // last_name(3) => last_name_fr_FR(3)
139 $fields[] = preg_replace('/^([^(]+)(\(\d+\)|)$/', '${1}_' . $locale . '${2}', $field);
145 $localIndex['field'] = $fields;
146 $finalIndices[$localIndex['name']] = $localIndex;
150 $finalIndices[$index['name']] = $index;
153 CRM_Core_BAO_SchemaHandler
::addIndexSignature(self
::getTableForClass($class), $finalIndices);
154 return $finalIndices;
159 * Mapping from brief-names to class-names.
160 * Ex: $result['Contact'] == 'CRM_Contact_DAO_Contact'.
162 public static function daoToClass() {
164 return self
::$daoToClass;
169 * Mapping from table-names to class-names.
170 * Ex: $result['civicrm_contact'] == 'CRM_Contact_DAO_Contact'.
172 public static function getCoreTables() {
173 return self
::tables();
177 * Determine whether $tableName is a core table.
179 * @param string $tableName
182 public static function isCoreTable($tableName) {
183 return array_key_exists($tableName, self
::tables());
187 * Get the DAO for a BAO class.
189 * @param string $baoName
191 * @return string|CRM_Core_DAO
193 public static function getCanonicalClassName($baoName) {
194 return str_replace('_BAO_', '_DAO_', $baoName);
198 * Get the BAO for a DAO class.
200 * @param string $daoName
202 * @return string|CRM_Core_DAO
204 public static function getBAOClassName($daoName) {
205 $baoName = str_replace('_DAO_', '_BAO_', $daoName);
206 return $daoName === $baoName ||
class_exists($baoName) ?
$baoName : $daoName;
210 * Convert possibly underscore separated words to camel case with special handling for 'UF'
211 * e.g membership_payment returns MembershipPayment
213 * @param string $name
214 * @param bool $legacyV3
217 public static function convertEntityNameToCamel(string $name, $legacyV3 = FALSE): string {
218 // This map only applies to APIv3
225 if ($legacyV3 && isset($map[$name])) {
229 $fragments = explode('_', $name);
230 foreach ($fragments as & $fragment) {
231 $fragment = ucfirst($fragment);
232 // Special case: UFGroup, UFJoin, UFMatch, UFField (if passed in without underscores)
233 if (strpos($fragment, 'Uf') === 0 && strlen($name) > 2) {
234 $fragment = 'UF' . ucfirst(substr($fragment, 2));
237 // Special case: UFGroup, UFJoin, UFMatch, UFField (if passed in underscore-separated)
238 if ($fragments[0] === 'Uf') {
239 $fragments[0] = 'UF';
241 return implode('', $fragments);
245 * Convert CamelCase to snake_case, with special handling for some entity names.
247 * Eg. Activity returns activity
248 * UFGroup returns uf_group
249 * OptionValue returns option_value
251 * @param string $name
255 public static function convertEntityNameToLower(string $name): string {
256 if ($name === strtolower($name)) {
259 if ($name === 'PCP' ||
$name === 'IM' ||
$name === 'ACL') {
260 return strtolower($name);
262 return strtolower(ltrim(str_replace('U_F',
264 // That's CamelCase, beside an odd UFCamel that is expected as uf_camel
265 preg_replace('/(?=[A-Z])/', '_$0', $name)
270 * Get a list of all DAO classes.
273 * List of class names.
275 public static function getClasses() {
276 return array_values(self
::daoToClass());
280 * Get a list of all extant BAO classes.
283 * Ex: ['Contact' => 'CRM_Contact_BAO_Contact']
285 public static function getBaoClasses() {
287 foreach (\CRM_Core_DAO_AllCoreTables
::daoToClass() as $entity => $daoClass) {
288 $baoClass = str_replace('_DAO_', '_BAO_', $daoClass);
289 if (class_exists($baoClass)) {
290 $r[$entity] = $baoClass;
297 * Get the classname for the table.
299 * @param string $tableName
300 * @return string|CRM_Core_DAO|NULL
302 public static function getClassForTable($tableName) {
303 //CRM-19677: on multilingual setup, trim locale from $tableName to fetch class name
304 if (CRM_Core_I18n
::isMultilingual()) {
306 $tableName = str_replace($dbLocale, '', $tableName);
308 return CRM_Utils_Array
::value($tableName, self
::tables());
312 * Given a brief-name, determine the full class-name.
314 * @param string $briefName
316 * @return string|CRM_Core_DAO|NULL
317 * Ex: 'CRM_Contact_DAO_Contact'.
319 public static function getFullName($briefName) {
321 return self
::$entityTypes[$briefName]['class'] ??
NULL;
325 * Given a full class-name, determine the brief-name.
327 * @param string $className
328 * Ex: 'CRM_Contact_DAO_Contact'.
329 * @return string|NULL
332 public static function getBriefName($className) {
333 $className = self
::getCanonicalClassName($className);
334 return array_search($className, self
::daoToClass(), TRUE) ?
: NULL;
338 * @param string $className DAO or BAO name
339 * @return string|FALSE SQL table name
341 public static function getTableForClass($className) {
342 return array_search(self
::getCanonicalClassName($className),
347 * Convert the entity name into a table name.
349 * @param string $briefName
351 * @return FALSE|string
353 public static function getTableForEntityName($briefName) {
355 return self
::$entityTypes[$briefName]['table'];
359 * Convert table name to brief entity name.
361 * @param string $tableName
363 * @return FALSE|string
365 public static function getEntityNameForTable(string $tableName) {
367 // CRM-19677: on multilingual setup, trim locale from $tableName to fetch class name
368 if (CRM_Core_I18n
::isMultilingual()) {
370 $tableName = str_replace($dbLocale, '', $tableName);
372 $matches = CRM_Utils_Array
::findAll(self
::$entityTypes, ['table' => $tableName]);
373 return $matches ?
$matches[0]['name'] : NULL;
377 * Reinitialise cache.
379 public static function reinitializeCache() {
384 * (Quasi-Private) Do not call externally. For use by DAOs.
387 * Ex: 'CRM_Core_DAO_Address'.
388 * @param string $labelName
390 * @param bool $prefix
391 * @param array $foreignDAOs
394 public static function getExports($dao, $labelName, $prefix, $foreignDAOs) {
395 // Bug-level compatibility -- or sane behavior?
396 $cacheKey = $dao . ':export';
397 // $cacheKey = $dao . ':' . ($prefix ? 'export-prefix' : 'export');
399 if (!isset(Civi
::$statics[__CLASS__
][$cacheKey])) {
401 $fields = $dao::fields();
403 foreach ($fields as $name => $field) {
404 if (!empty($field['export'])) {
406 $exports[$labelName] = & $fields[$name];
409 $exports[$name] = & $fields[$name];
414 foreach ($foreignDAOs as $foreignDAO) {
415 $exports = array_merge($exports, $foreignDAO::export(TRUE));
418 Civi
::$statics[__CLASS__
][$cacheKey] = $exports;
420 return Civi
::$statics[__CLASS__
][$cacheKey];
424 * (Quasi-Private) Do not call externally. For use by DAOs.
427 * Ex: 'CRM_Core_DAO_Address'.
428 * @param string $labelName
430 * @param bool $prefix
431 * @param array $foreignDAOs
434 public static function getImports($dao, $labelName, $prefix, $foreignDAOs) {
435 // Bug-level compatibility -- or sane behavior?
436 $cacheKey = $dao . ':import';
437 // $cacheKey = $dao . ':' . ($prefix ? 'import-prefix' : 'import');
439 if (!isset(Civi
::$statics[__CLASS__
][$cacheKey])) {
441 $fields = $dao::fields();
443 foreach ($fields as $name => $field) {
444 if (!empty($field['import'])) {
446 $imports[$labelName] = & $fields[$name];
449 $imports[$name] = & $fields[$name];
454 foreach ($foreignDAOs as $foreignDAO) {
455 $imports = array_merge($imports, $foreignDAO::import(TRUE));
458 Civi
::$statics[__CLASS__
][$cacheKey] = $imports;
460 return Civi
::$statics[__CLASS__
][$cacheKey];
464 * (Quasi-Private) Do not call externally. For use by DAOs.
466 * Apply any third-party alterations to the `fields()`.
468 * TODO: This function should probably take briefName as the key instead of className
469 * because the latter is not always unique (e.g. virtual entities)
471 * @param string $className
472 * @param string $event
473 * @param mixed $values
475 public static function invoke($className, $event, &$values) {
477 $briefName = self
::getBriefName($className);
478 if (isset(self
::$entityTypes[$briefName][$event])) {
479 foreach (self
::$entityTypes[$briefName][$event] as $filter) {
480 $args = [$className, &$values];
481 \Civi\Core\Resolver
::singleton()->call($filter, $args);