Fix CRM_Core_DAO_AllCoreTables::getBriefName to accept BAO name
[civicrm-core.git] / CRM / Core / DAO / AllCoreTables.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
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 +--------------------------------------------------------------------+
11 */
12
13 /**
14 *
15 * @package CRM
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 */
18 class CRM_Core_DAO_AllCoreTables {
19
20 private static $tables = NULL;
21 private static $daoToClass = NULL;
22 private static $entityTypes = NULL;
23
24 /**
25 * Initialise.
26 *
27 * @param bool $fresh
28 */
29 public static function init($fresh = FALSE) {
30 static $init = FALSE;
31 if ($init && !$fresh) {
32 return;
33 }
34 Civi::$statics[__CLASS__] = [];
35
36 $file = preg_replace('/\.php$/', '.data.php', __FILE__);
37 $entityTypes = require $file;
38 CRM_Utils_Hook::entityTypes($entityTypes);
39
40 self::$entityTypes = [];
41 self::$tables = [];
42 self::$daoToClass = [];
43 foreach ($entityTypes as $entityType) {
44 self::registerEntityType(
45 $entityType['name'],
46 $entityType['class'],
47 $entityType['table'],
48 $entityType['fields_callback'] ?? NULL,
49 $entityType['links_callback'] ?? NULL
50 );
51 }
52
53 $init = TRUE;
54 }
55
56 /**
57 * (Quasi-Private) Do not call externally (except for unit-testing)
58 *
59 * @param string $daoName
60 * @param string $className
61 * @param string $tableName
62 * @param string $fields_callback
63 * @param string $links_callback
64 */
65 public static function registerEntityType($daoName, $className, $tableName, $fields_callback = NULL, $links_callback = NULL) {
66 self::$daoToClass[$daoName] = $className;
67 self::$tables[$tableName] = $className;
68 self::$entityTypes[$className] = [
69 'name' => $daoName,
70 'class' => $className,
71 'table' => $tableName,
72 'fields_callback' => $fields_callback,
73 'links_callback' => $links_callback,
74 ];
75 }
76
77 /**
78 * @return array
79 * Ex: $result['CRM_Contact_DAO_Contact']['table'] == 'civicrm_contact';
80 */
81 public static function get() {
82 self::init();
83 return self::$entityTypes;
84 }
85
86 /**
87 * @return array
88 * List of SQL table names.
89 */
90 public static function tables() {
91 self::init();
92 return self::$tables;
93 }
94
95 /**
96 * @return array
97 * List of indices.
98 */
99 public static function indices($localize = TRUE) {
100 $indices = [];
101 self::init();
102 foreach (self::$daoToClass as $class) {
103 if (is_callable([$class, 'indices'])) {
104 $indices[$class::getTableName()] = $class::indices($localize);
105 }
106 }
107 return $indices;
108 }
109
110 /**
111 * Modify indices to account for localization options.
112 *
113 * @param string $class DAO class
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) {
120 $domain = new CRM_Core_DAO_Domain();
121 $domain->find(TRUE);
122 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
123 if (CRM_Utils_System::isNull($locales)) {
124 return $originalIndices;
125 }
126 $classFields = $class::fields();
127
128 $finalIndices = [];
129 foreach ($originalIndices as $index) {
130 if ($index['localizable']) {
131 foreach ($locales as $locale) {
132 $localIndex = $index;
133 $localIndex['name'] .= "_" . $locale;
134 $fields = [];
135 foreach ($localIndex['field'] as $field) {
136 $baseField = explode('(', $field);
137 if ($classFields[$baseField[0]]['localizable']) {
138 // field name may have eg (3) at end for prefix length
139 // last_name => last_name_fr_FR
140 // last_name(3) => last_name_fr_FR(3)
141 $fields[] = preg_replace('/^([^(]+)(\(\d+\)|)$/', '${1}_' . $locale . '${2}', $field);
142 }
143 else {
144 $fields[] = $field;
145 }
146 }
147 $localIndex['field'] = $fields;
148 $finalIndices[$localIndex['name']] = $localIndex;
149 }
150 }
151 else {
152 $finalIndices[$index['name']] = $index;
153 }
154 }
155 CRM_Core_BAO_SchemaHandler::addIndexSignature(self::getTableForClass($class), $finalIndices);
156 return $finalIndices;
157 }
158
159 /**
160 * @return array
161 * Mapping from brief-names to class-names.
162 * Ex: $result['Contact'] == 'CRM_Contact_DAO_Contact'.
163 */
164 public static function daoToClass() {
165 self::init();
166 return self::$daoToClass;
167 }
168
169 /**
170 * @return array
171 * Mapping from table-names to class-names.
172 * Ex: $result['civicrm_contact'] == 'CRM_Contact_DAO_Contact'.
173 */
174 public static function getCoreTables() {
175 return self::tables();
176 }
177
178 /**
179 * Determine whether $tableName is a core table.
180 *
181 * @param string $tableName
182 * @return bool
183 */
184 public static function isCoreTable($tableName) {
185 return array_key_exists($tableName, self::tables());
186 }
187
188 /**
189 * Get the DAO for a BAO class.
190 *
191 * @param string $baoName
192 *
193 * @return string|CRM_Core_DAO
194 */
195 public static function getCanonicalClassName($baoName) {
196 return str_replace('_BAO_', '_DAO_', $baoName);
197 }
198
199 /**
200 * Get the BAO for a DAO class.
201 *
202 * @param string $daoName
203 *
204 * @return string|CRM_Core_DAO
205 */
206 public static function getBAOClassName($daoName) {
207 $baoName = str_replace('_DAO_', '_BAO_', $daoName);
208 return class_exists($baoName) ? $baoName : $daoName;
209 }
210
211 /**
212 * Get a list of all DAO classes.
213 *
214 * @return array
215 * List of class names.
216 */
217 public static function getClasses() {
218 return array_values(self::daoToClass());
219 }
220
221 /**
222 * Get the classname for the table.
223 *
224 * @param string $tableName
225 * @return string
226 */
227 public static function getClassForTable($tableName) {
228 //CRM-19677: on multilingual setup, trim locale from $tableName to fetch class name
229 if (CRM_Core_I18n::isMultilingual()) {
230 global $dbLocale;
231 $tableName = str_replace($dbLocale, '', $tableName);
232 }
233 return CRM_Utils_Array::value($tableName, self::tables());
234 }
235
236 /**
237 * Given a brief-name, determine the full class-name.
238 *
239 * @param string $daoName
240 * Ex: 'Contact'.
241 * @return string|NULL
242 * Ex: 'CRM_Contact_DAO_Contact'.
243 */
244 public static function getFullName($daoName) {
245 return CRM_Utils_Array::value($daoName, self::daoToClass());
246 }
247
248 /**
249 * Given a full class-name, determine the brief-name.
250 *
251 * @param string $className
252 * Ex: 'CRM_Contact_DAO_Contact'.
253 * @return string|NULL
254 * Ex: 'Contact'.
255 */
256 public static function getBriefName($className) {
257 $className = self::getCanonicalClassName($className);
258 return array_search($className, self::daoToClass(), TRUE) ?: NULL;
259 }
260
261 /**
262 * @param string $className DAO or BAO name
263 * @return string|FALSE SQL table name
264 */
265 public static function getTableForClass($className) {
266 return array_search(self::getCanonicalClassName($className),
267 self::tables());
268 }
269
270 /**
271 * Convert the entity name into a table name.
272 *
273 * @param string $entityBriefName
274 *
275 * @return FALSE|string
276 */
277 public static function getTableForEntityName($entityBriefName) {
278 return self::getTableForClass(self::getFullName($entityBriefName));
279 }
280
281 /**
282 * Reinitialise cache.
283 *
284 * @param bool $fresh
285 */
286 public static function reinitializeCache($fresh = FALSE) {
287 self::init($fresh);
288 }
289
290 /**
291 * (Quasi-Private) Do not call externally. For use by DAOs.
292 *
293 * @param string $dao
294 * Ex: 'CRM_Core_DAO_Address'.
295 * @param string $labelName
296 * Ex: 'address'.
297 * @param bool $prefix
298 * @param array $foreignDAOs
299 * @return array
300 */
301 public static function getExports($dao, $labelName, $prefix, $foreignDAOs) {
302 // Bug-level compatibility -- or sane behavior?
303 $cacheKey = $dao . ':export';
304 // $cacheKey = $dao . ':' . ($prefix ? 'export-prefix' : 'export');
305
306 if (!isset(Civi::$statics[__CLASS__][$cacheKey])) {
307 $exports = [];
308 $fields = $dao::fields();
309
310 foreach ($fields as $name => $field) {
311 if (!empty($field['export'])) {
312 if ($prefix) {
313 $exports[$labelName] = & $fields[$name];
314 }
315 else {
316 $exports[$name] = & $fields[$name];
317 }
318 }
319 }
320
321 foreach ($foreignDAOs as $foreignDAO) {
322 $exports = array_merge($exports, $foreignDAO::export(TRUE));
323 }
324
325 Civi::$statics[__CLASS__][$cacheKey] = $exports;
326 }
327 return Civi::$statics[__CLASS__][$cacheKey];
328 }
329
330 /**
331 * (Quasi-Private) Do not call externally. For use by DAOs.
332 *
333 * @param string $dao
334 * Ex: 'CRM_Core_DAO_Address'.
335 * @param string $labelName
336 * Ex: 'address'.
337 * @param bool $prefix
338 * @param array $foreignDAOs
339 * @return array
340 */
341 public static function getImports($dao, $labelName, $prefix, $foreignDAOs) {
342 // Bug-level compatibility -- or sane behavior?
343 $cacheKey = $dao . ':import';
344 // $cacheKey = $dao . ':' . ($prefix ? 'import-prefix' : 'import');
345
346 if (!isset(Civi::$statics[__CLASS__][$cacheKey])) {
347 $imports = [];
348 $fields = $dao::fields();
349
350 foreach ($fields as $name => $field) {
351 if (!empty($field['import'])) {
352 if ($prefix) {
353 $imports[$labelName] = & $fields[$name];
354 }
355 else {
356 $imports[$name] = & $fields[$name];
357 }
358 }
359 }
360
361 foreach ($foreignDAOs as $foreignDAO) {
362 $imports = array_merge($imports, $foreignDAO::import(TRUE));
363 }
364
365 Civi::$statics[__CLASS__][$cacheKey] = $imports;
366 }
367 return Civi::$statics[__CLASS__][$cacheKey];
368 }
369
370 /**
371 * (Quasi-Private) Do not call externally. For use by DAOs.
372 *
373 * Apply any third-party alterations to the `fields()`.
374 *
375 * @param string $className
376 * @param string $event
377 * @param mixed $values
378 */
379 public static function invoke($className, $event, &$values) {
380 self::init();
381 if (isset(self::$entityTypes[$className][$event])) {
382 foreach (self::$entityTypes[$className][$event] as $filter) {
383 $args = [$className, &$values];
384 \Civi\Core\Resolver::singleton()->call($filter, $args);
385 }
386 }
387 }
388
389 }