Commit | Line | Data |
---|---|---|
4ef04170 TO |
1 | <?php |
2 | ||
3 | /* | |
4 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 5 | | Copyright CiviCRM LLC. All rights reserved. | |
4ef04170 | 6 | | | |
bc77d7c0 TO |
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 | | |
4ef04170 TO |
10 | +--------------------------------------------------------------------+ |
11 | */ | |
12 | ||
13 | /** | |
14 | * | |
15 | * @package CRM | |
ca5cec67 | 16 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
4ef04170 TO |
17 | */ |
18 | class CRM_Core_DAO_AllCoreTables { | |
19 | ||
95b9a42e TO |
20 | private static $tables = NULL; |
21 | private static $daoToClass = NULL; | |
22 | private static $entityTypes = NULL; | |
4ef04170 | 23 | |
8246bca4 | 24 | /** |
25 | * Initialise. | |
26 | * | |
27 | * @param bool $fresh | |
28 | */ | |
95b9a42e | 29 | public static function init($fresh = FALSE) { |
4ef04170 | 30 | static $init = FALSE; |
95b9a42e TO |
31 | if ($init && !$fresh) { |
32 | return; | |
4ef04170 | 33 | } |
be2fb01f | 34 | Civi::$statics[__CLASS__] = []; |
4ef04170 TO |
35 | |
36 | $file = preg_replace('/\.php$/', '.data.php', __FILE__); | |
37 | $entityTypes = require $file; | |
38 | CRM_Utils_Hook::entityTypes($entityTypes); | |
39 | ||
be2fb01f CW |
40 | self::$entityTypes = []; |
41 | self::$tables = []; | |
42 | self::$daoToClass = []; | |
4ef04170 | 43 | foreach ($entityTypes as $entityType) { |
740dd877 TO |
44 | self::registerEntityType( |
45 | $entityType['name'], | |
46 | $entityType['class'], | |
47 | $entityType['table'], | |
2e1f50d6 CW |
48 | $entityType['fields_callback'] ?? NULL, |
49 | $entityType['links_callback'] ?? NULL | |
740dd877 | 50 | ); |
4ef04170 TO |
51 | } |
52 | ||
53 | $init = TRUE; | |
54 | } | |
55 | ||
56 | /** | |
57 | * (Quasi-Private) Do not call externally (except for unit-testing) | |
8246bca4 | 58 | * |
59 | * @param string $daoName | |
60 | * @param string $className | |
61 | * @param string $tableName | |
62 | * @param string $fields_callback | |
63 | * @param string $links_callback | |
4ef04170 | 64 | */ |
740dd877 | 65 | public static function registerEntityType($daoName, $className, $tableName, $fields_callback = NULL, $links_callback = NULL) { |
4ef04170 TO |
66 | self::$daoToClass[$daoName] = $className; |
67 | self::$tables[$tableName] = $className; | |
be2fb01f | 68 | self::$entityTypes[$className] = [ |
4ef04170 TO |
69 | 'name' => $daoName, |
70 | 'class' => $className, | |
71 | 'table' => $tableName, | |
740dd877 TO |
72 | 'fields_callback' => $fields_callback, |
73 | 'links_callback' => $links_callback, | |
be2fb01f | 74 | ]; |
4ef04170 TO |
75 | } |
76 | ||
95b9a42e TO |
77 | /** |
78 | * @return array | |
79 | * Ex: $result['CRM_Contact_DAO_Contact']['table'] == 'civicrm_contact'; | |
80 | */ | |
81 | public static function get() { | |
4ef04170 TO |
82 | self::init(); |
83 | return self::$entityTypes; | |
84 | } | |
85 | ||
95b9a42e TO |
86 | /** |
87 | * @return array | |
88 | * List of SQL table names. | |
89 | */ | |
90 | public static function tables() { | |
4ef04170 TO |
91 | self::init(); |
92 | return self::$tables; | |
93 | } | |
94 | ||
6b86d84f AS |
95 | /** |
96 | * @return array | |
97 | * List of indices. | |
98 | */ | |
99 | public static function indices($localize = TRUE) { | |
be2fb01f | 100 | $indices = []; |
6b86d84f AS |
101 | self::init(); |
102 | foreach (self::$daoToClass as $class) { | |
be2fb01f | 103 | if (is_callable([$class, 'indices'])) { |
6b86d84f AS |
104 | $indices[$class::getTableName()] = $class::indices($localize); |
105 | } | |
106 | } | |
107 | return $indices; | |
108 | } | |
109 | ||
110 | /** | |
111 | * Modify indices to account for localization options. | |
112 | * | |
8a4fede3 | 113 | * @param string $class DAO class |
6b86d84f AS |
114 | * @param array $originalIndices index definitions before localization |
115 | * | |
116 | * @return array | |
117 | * index definitions after localization | |
118 | */ | |
119 | public static function multilingualize($class, $originalIndices) { | |
394d18d3 CW |
120 | $locales = CRM_Core_I18n::getMultilingual(); |
121 | if (!$locales) { | |
6b86d84f AS |
122 | return $originalIndices; |
123 | } | |
124 | $classFields = $class::fields(); | |
125 | ||
be2fb01f | 126 | $finalIndices = []; |
6b86d84f AS |
127 | foreach ($originalIndices as $index) { |
128 | if ($index['localizable']) { | |
129 | foreach ($locales as $locale) { | |
130 | $localIndex = $index; | |
131 | $localIndex['name'] .= "_" . $locale; | |
be2fb01f | 132 | $fields = []; |
6b86d84f AS |
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); | |
140 | } | |
141 | else { | |
142 | $fields[] = $field; | |
143 | } | |
144 | } | |
145 | $localIndex['field'] = $fields; | |
146 | $finalIndices[$localIndex['name']] = $localIndex; | |
147 | } | |
148 | } | |
149 | else { | |
150 | $finalIndices[$index['name']] = $index; | |
151 | } | |
152 | } | |
153 | CRM_Core_BAO_SchemaHandler::addIndexSignature(self::getTableForClass($class), $finalIndices); | |
154 | return $finalIndices; | |
155 | } | |
156 | ||
95b9a42e TO |
157 | /** |
158 | * @return array | |
159 | * Mapping from brief-names to class-names. | |
160 | * Ex: $result['Contact'] == 'CRM_Contact_DAO_Contact'. | |
161 | */ | |
162 | public static function daoToClass() { | |
4ef04170 TO |
163 | self::init(); |
164 | return self::$daoToClass; | |
165 | } | |
166 | ||
95b9a42e TO |
167 | /** |
168 | * @return array | |
169 | * Mapping from table-names to class-names. | |
170 | * Ex: $result['civicrm_contact'] == 'CRM_Contact_DAO_Contact'. | |
171 | */ | |
172 | public static function getCoreTables() { | |
4ef04170 TO |
173 | return self::tables(); |
174 | } | |
175 | ||
95b9a42e TO |
176 | /** |
177 | * Determine whether $tableName is a core table. | |
178 | * | |
179 | * @param string $tableName | |
180 | * @return bool | |
181 | */ | |
182 | public static function isCoreTable($tableName) { | |
4c1bd923 | 183 | return array_key_exists($tableName, self::tables()); |
4ef04170 TO |
184 | } |
185 | ||
8246bca4 | 186 | /** |
3ab49d54 | 187 | * Get the DAO for a BAO class. |
8246bca4 | 188 | * |
3ab49d54 | 189 | * @param string $baoName |
8246bca4 | 190 | * |
3ab49d54 CW |
191 | * @return string|CRM_Core_DAO |
192 | */ | |
193 | public static function getCanonicalClassName($baoName) { | |
194 | return str_replace('_BAO_', '_DAO_', $baoName); | |
195 | } | |
196 | ||
197 | /** | |
198 | * Get the BAO for a DAO class. | |
199 | * | |
200 | * @param string $daoName | |
201 | * | |
202 | * @return string|CRM_Core_DAO | |
8246bca4 | 203 | */ |
3ab49d54 CW |
204 | public static function getBAOClassName($daoName) { |
205 | $baoName = str_replace('_DAO_', '_BAO_', $daoName); | |
206 | return class_exists($baoName) ? $baoName : $daoName; | |
4ef04170 TO |
207 | } |
208 | ||
74c303ca | 209 | /** |
210 | * Convert possibly underscore separated words to camel case with special handling for 'UF' | |
211 | * e.g membership_payment returns MembershipPayment | |
212 | * | |
213 | * @param string $name | |
214 | * @param bool $legacyV3 | |
215 | * @return string | |
216 | */ | |
217 | public static function convertEntityNameToCamel(string $name, $legacyV3 = FALSE): string { | |
218 | // This map only applies to APIv3 | |
219 | $map = [ | |
220 | 'acl' => 'Acl', | |
221 | 'ACL' => 'Acl', | |
222 | 'im' => 'Im', | |
223 | 'IM' => 'Im', | |
224 | ]; | |
225 | if ($legacyV3 && isset($map[$name])) { | |
226 | return $map[$name]; | |
227 | } | |
228 | ||
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)); | |
235 | } | |
236 | } | |
237 | // Special case: UFGroup, UFJoin, UFMatch, UFField (if passed in underscore-separated) | |
238 | if ($fragments[0] === 'Uf') { | |
239 | $fragments[0] = 'UF'; | |
240 | } | |
241 | return implode('', $fragments); | |
242 | } | |
243 | ||
244 | /** | |
245 | * Convert CamelCase to snake_case, with special handling for some entity names. | |
246 | * | |
247 | * Eg. Activity returns activity | |
248 | * UFGroup returns uf_group | |
249 | * OptionValue returns option_value | |
250 | * | |
251 | * @param string $name | |
252 | * | |
253 | * @return string | |
254 | */ | |
255 | public static function convertEntityNameToLower(string $name): string { | |
256 | if ($name === strtolower($name)) { | |
257 | return $name; | |
258 | } | |
259 | if ($name === 'PCP' || $name === 'IM' || $name === 'ACL') { | |
260 | return strtolower($name); | |
261 | } | |
262 | return strtolower(ltrim(str_replace('U_F', | |
263 | 'uf', | |
264 | // That's CamelCase, beside an odd UFCamel that is expected as uf_camel | |
265 | preg_replace('/(?=[A-Z])/', '_$0', $name) | |
266 | ), '_')); | |
267 | } | |
268 | ||
95b9a42e | 269 | /** |
8246bca4 | 270 | * Get a list of all DAO classes. |
271 | * | |
95b9a42e TO |
272 | * @return array |
273 | * List of class names. | |
274 | */ | |
275 | public static function getClasses() { | |
4ef04170 TO |
276 | return array_values(self::daoToClass()); |
277 | } | |
278 | ||
8246bca4 | 279 | /** |
280 | * Get the classname for the table. | |
281 | * | |
282 | * @param string $tableName | |
721c9da1 | 283 | * @return string|CRM_Core_DAO|NULL |
8246bca4 | 284 | */ |
95b9a42e | 285 | public static function getClassForTable($tableName) { |
3a575348 | 286 | //CRM-19677: on multilingual setup, trim locale from $tableName to fetch class name |
287 | if (CRM_Core_I18n::isMultilingual()) { | |
288 | global $dbLocale; | |
289 | $tableName = str_replace($dbLocale, '', $tableName); | |
290 | } | |
4ef04170 TO |
291 | return CRM_Utils_Array::value($tableName, self::tables()); |
292 | } | |
293 | ||
95b9a42e TO |
294 | /** |
295 | * Given a brief-name, determine the full class-name. | |
296 | * | |
297 | * @param string $daoName | |
298 | * Ex: 'Contact'. | |
721c9da1 | 299 | * @return string|CRM_Core_DAO|NULL |
95b9a42e TO |
300 | * Ex: 'CRM_Contact_DAO_Contact'. |
301 | */ | |
302 | public static function getFullName($daoName) { | |
4ef04170 TO |
303 | return CRM_Utils_Array::value($daoName, self::daoToClass()); |
304 | } | |
305 | ||
95b9a42e TO |
306 | /** |
307 | * Given a full class-name, determine the brief-name. | |
308 | * | |
309 | * @param string $className | |
310 | * Ex: 'CRM_Contact_DAO_Contact'. | |
311 | * @return string|NULL | |
312 | * Ex: 'Contact'. | |
313 | */ | |
314 | public static function getBriefName($className) { | |
3d182a04 CW |
315 | $className = self::getCanonicalClassName($className); |
316 | return array_search($className, self::daoToClass(), TRUE) ?: NULL; | |
4ef04170 TO |
317 | } |
318 | ||
319 | /** | |
320 | * @param string $className DAO or BAO name | |
321 | * @return string|FALSE SQL table name | |
322 | */ | |
95b9a42e TO |
323 | public static function getTableForClass($className) { |
324 | return array_search(self::getCanonicalClassName($className), | |
325 | self::tables()); | |
4ef04170 TO |
326 | } |
327 | ||
9d4c4ffd | 328 | /** |
329 | * Convert the entity name into a table name. | |
330 | * | |
331 | * @param string $entityBriefName | |
332 | * | |
333 | * @return FALSE|string | |
334 | */ | |
335 | public static function getTableForEntityName($entityBriefName) { | |
336 | return self::getTableForClass(self::getFullName($entityBriefName)); | |
337 | } | |
338 | ||
17019d49 CW |
339 | /** |
340 | * Convert table name to brief entity name. | |
341 | * | |
342 | * @param string $tableName | |
343 | * | |
344 | * @return FALSE|string | |
345 | */ | |
346 | public static function getEntityNameForTable(string $tableName) { | |
347 | return self::getBriefName(self::getClassForTable($tableName)); | |
348 | } | |
349 | ||
8246bca4 | 350 | /** |
351 | * Reinitialise cache. | |
352 | * | |
353 | * @param bool $fresh | |
354 | */ | |
95b9a42e | 355 | public static function reinitializeCache($fresh = FALSE) { |
4ef04170 TO |
356 | self::init($fresh); |
357 | } | |
358 | ||
84a0493c TO |
359 | /** |
360 | * (Quasi-Private) Do not call externally. For use by DAOs. | |
361 | * | |
362 | * @param string $dao | |
363 | * Ex: 'CRM_Core_DAO_Address'. | |
364 | * @param string $labelName | |
365 | * Ex: 'address'. | |
366 | * @param bool $prefix | |
367 | * @param array $foreignDAOs | |
368 | * @return array | |
369 | */ | |
370 | public static function getExports($dao, $labelName, $prefix, $foreignDAOs) { | |
371 | // Bug-level compatibility -- or sane behavior? | |
372 | $cacheKey = $dao . ':export'; | |
373 | // $cacheKey = $dao . ':' . ($prefix ? 'export-prefix' : 'export'); | |
374 | ||
375 | if (!isset(Civi::$statics[__CLASS__][$cacheKey])) { | |
be2fb01f | 376 | $exports = []; |
84a0493c TO |
377 | $fields = $dao::fields(); |
378 | ||
8246bca4 | 379 | foreach ($fields as $name => $field) { |
de6c59ca | 380 | if (!empty($field['export'])) { |
84a0493c TO |
381 | if ($prefix) { |
382 | $exports[$labelName] = & $fields[$name]; | |
8246bca4 | 383 | } |
384 | else { | |
84a0493c TO |
385 | $exports[$name] = & $fields[$name]; |
386 | } | |
387 | } | |
388 | } | |
389 | ||
390 | foreach ($foreignDAOs as $foreignDAO) { | |
391 | $exports = array_merge($exports, $foreignDAO::export(TRUE)); | |
392 | } | |
393 | ||
394 | Civi::$statics[__CLASS__][$cacheKey] = $exports; | |
395 | } | |
396 | return Civi::$statics[__CLASS__][$cacheKey]; | |
397 | } | |
398 | ||
399 | /** | |
400 | * (Quasi-Private) Do not call externally. For use by DAOs. | |
401 | * | |
402 | * @param string $dao | |
403 | * Ex: 'CRM_Core_DAO_Address'. | |
404 | * @param string $labelName | |
405 | * Ex: 'address'. | |
406 | * @param bool $prefix | |
407 | * @param array $foreignDAOs | |
408 | * @return array | |
409 | */ | |
410 | public static function getImports($dao, $labelName, $prefix, $foreignDAOs) { | |
411 | // Bug-level compatibility -- or sane behavior? | |
412 | $cacheKey = $dao . ':import'; | |
413 | // $cacheKey = $dao . ':' . ($prefix ? 'import-prefix' : 'import'); | |
414 | ||
415 | if (!isset(Civi::$statics[__CLASS__][$cacheKey])) { | |
be2fb01f | 416 | $imports = []; |
84a0493c TO |
417 | $fields = $dao::fields(); |
418 | ||
8246bca4 | 419 | foreach ($fields as $name => $field) { |
de6c59ca | 420 | if (!empty($field['import'])) { |
84a0493c TO |
421 | if ($prefix) { |
422 | $imports[$labelName] = & $fields[$name]; | |
8246bca4 | 423 | } |
424 | else { | |
84a0493c TO |
425 | $imports[$name] = & $fields[$name]; |
426 | } | |
427 | } | |
428 | } | |
429 | ||
430 | foreach ($foreignDAOs as $foreignDAO) { | |
431 | $imports = array_merge($imports, $foreignDAO::import(TRUE)); | |
432 | } | |
433 | ||
434 | Civi::$statics[__CLASS__][$cacheKey] = $imports; | |
435 | } | |
436 | return Civi::$statics[__CLASS__][$cacheKey]; | |
437 | } | |
438 | ||
740dd877 TO |
439 | /** |
440 | * (Quasi-Private) Do not call externally. For use by DAOs. | |
441 | * | |
442 | * Apply any third-party alterations to the `fields()`. | |
443 | * | |
444 | * @param string $className | |
445 | * @param string $event | |
446 | * @param mixed $values | |
447 | */ | |
448 | public static function invoke($className, $event, &$values) { | |
449 | self::init(); | |
450 | if (isset(self::$entityTypes[$className][$event])) { | |
451 | foreach (self::$entityTypes[$className][$event] as $filter) { | |
be2fb01f | 452 | $args = [$className, &$values]; |
740dd877 TO |
453 | \Civi\Core\Resolver::singleton()->call($filter, $args); |
454 | } | |
455 | } | |
456 | } | |
457 | ||
4ef04170 | 458 | } |