Merge pull request #14667 from hoegrammer/master
[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 isset($entityType['fields_callback']) ? $entityType['fields_callback'] : NULL,
49 isset($entityType['links_callback']) ? $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 the class.
190 *
191 * @param string $className
192 *
193 * @return string
194 */
195 public static function getCanonicalClassName($className) {
196 return str_replace('_BAO_', '_DAO_', $className);
197 }
198
199 /**
200 * Get a list of all DAO classes.
201 *
202 * @return array
203 * List of class names.
204 */
205 public static function getClasses() {
206 return array_values(self::daoToClass());
207 }
208
209 /**
210 * Get the classname for the table.
211 *
212 * @param string $tableName
213 * @return string
214 */
215 public static function getClassForTable($tableName) {
216 //CRM-19677: on multilingual setup, trim locale from $tableName to fetch class name
217 if (CRM_Core_I18n::isMultilingual()) {
218 global $dbLocale;
219 $tableName = str_replace($dbLocale, '', $tableName);
220 }
221 return CRM_Utils_Array::value($tableName, self::tables());
222 }
223
224 /**
225 * Given a brief-name, determine the full class-name.
226 *
227 * @param string $daoName
228 * Ex: 'Contact'.
229 * @return string|NULL
230 * Ex: 'CRM_Contact_DAO_Contact'.
231 */
232 public static function getFullName($daoName) {
233 return CRM_Utils_Array::value($daoName, self::daoToClass());
234 }
235
236 /**
237 * Given a full class-name, determine the brief-name.
238 *
239 * @param string $className
240 * Ex: 'CRM_Contact_DAO_Contact'.
241 * @return string|NULL
242 * Ex: 'Contact'.
243 */
244 public static function getBriefName($className) {
245 return CRM_Utils_Array::value($className, array_flip(self::daoToClass()));
246 }
247
248 /**
249 * @param string $className DAO or BAO name
250 * @return string|FALSE SQL table name
251 */
252 public static function getTableForClass($className) {
253 return array_search(self::getCanonicalClassName($className),
254 self::tables());
255 }
256
257 /**
258 * Reinitialise cache.
259 *
260 * @param bool $fresh
261 */
262 public static function reinitializeCache($fresh = FALSE) {
263 self::init($fresh);
264 }
265
266 /**
267 * (Quasi-Private) Do not call externally. For use by DAOs.
268 *
269 * @param string $dao
270 * Ex: 'CRM_Core_DAO_Address'.
271 * @param string $labelName
272 * Ex: 'address'.
273 * @param bool $prefix
274 * @param array $foreignDAOs
275 * @return array
276 */
277 public static function getExports($dao, $labelName, $prefix, $foreignDAOs) {
278 // Bug-level compatibility -- or sane behavior?
279 $cacheKey = $dao . ':export';
280 // $cacheKey = $dao . ':' . ($prefix ? 'export-prefix' : 'export');
281
282 if (!isset(Civi::$statics[__CLASS__][$cacheKey])) {
283 $exports = [];
284 $fields = $dao::fields();
285
286 foreach ($fields as $name => $field) {
287 if (!empty($field['export'])) {
288 if ($prefix) {
289 $exports[$labelName] = & $fields[$name];
290 }
291 else {
292 $exports[$name] = & $fields[$name];
293 }
294 }
295 }
296
297 foreach ($foreignDAOs as $foreignDAO) {
298 $exports = array_merge($exports, $foreignDAO::export(TRUE));
299 }
300
301 Civi::$statics[__CLASS__][$cacheKey] = $exports;
302 }
303 return Civi::$statics[__CLASS__][$cacheKey];
304 }
305
306 /**
307 * (Quasi-Private) Do not call externally. For use by DAOs.
308 *
309 * @param string $dao
310 * Ex: 'CRM_Core_DAO_Address'.
311 * @param string $labelName
312 * Ex: 'address'.
313 * @param bool $prefix
314 * @param array $foreignDAOs
315 * @return array
316 */
317 public static function getImports($dao, $labelName, $prefix, $foreignDAOs) {
318 // Bug-level compatibility -- or sane behavior?
319 $cacheKey = $dao . ':import';
320 // $cacheKey = $dao . ':' . ($prefix ? 'import-prefix' : 'import');
321
322 if (!isset(Civi::$statics[__CLASS__][$cacheKey])) {
323 $imports = [];
324 $fields = $dao::fields();
325
326 foreach ($fields as $name => $field) {
327 if (!empty($field['import'])) {
328 if ($prefix) {
329 $imports[$labelName] = & $fields[$name];
330 }
331 else {
332 $imports[$name] = & $fields[$name];
333 }
334 }
335 }
336
337 foreach ($foreignDAOs as $foreignDAO) {
338 $imports = array_merge($imports, $foreignDAO::import(TRUE));
339 }
340
341 Civi::$statics[__CLASS__][$cacheKey] = $imports;
342 }
343 return Civi::$statics[__CLASS__][$cacheKey];
344 }
345
346 /**
347 * (Quasi-Private) Do not call externally. For use by DAOs.
348 *
349 * Apply any third-party alterations to the `fields()`.
350 *
351 * @param string $className
352 * @param string $event
353 * @param mixed $values
354 */
355 public static function invoke($className, $event, &$values) {
356 self::init();
357 if (isset(self::$entityTypes[$className][$event])) {
358 foreach (self::$entityTypes[$className][$event] as $filter) {
359 $args = [$className, &$values];
360 \Civi\Core\Resolver::singleton()->call($filter, $args);
361 }
362 }
363 }
364
365 }