Commit | Line | Data |
---|---|---|
5e434adf ARW |
1 | <?php |
2 | ||
3 | /** | |
4 | * Read the schema specification and parse into internal data structures | |
5 | */ | |
6 | class CRM_Core_CodeGen_Specification { | |
7 | public $tables; | |
8 | public $database; | |
9 | ||
10 | protected $classNames; | |
11 | ||
12 | /** | |
13 | * Read and parse. | |
14 | * | |
77b97be7 | 15 | * @param $schemaPath |
6a0b768e TO |
16 | * @param string $buildVersion |
17 | * Which version of the schema to build. | |
5e434adf | 18 | */ |
00be9182 | 19 | public function parse($schemaPath, $buildVersion) { |
5e434adf ARW |
20 | $this->buildVersion = $buildVersion; |
21 | ||
92fcb95f | 22 | echo "Parsing schema description " . $schemaPath . "\n"; |
5e434adf ARW |
23 | $dbXML = CRM_Core_CodeGen_Util_Xml::parse($schemaPath); |
24 | // print_r( $dbXML ); | |
25 | ||
26 | echo "Extracting database information\n"; | |
27 | $this->database = &$this->getDatabase($dbXML); | |
28 | // print_r( $this->database ); | |
29 | ||
30 | $this->classNames = array(); | |
31 | ||
32 | # TODO: peel DAO-specific stuff out of getTables, and spec reading into its own class | |
33 | echo "Extracting table information\n"; | |
34 | $this->tables = $this->getTables($dbXML, $this->database); | |
35 | ||
36 | $this->resolveForeignKeys($this->tables, $this->classNames); | |
37 | $this->tables = $this->orderTables($this->tables); | |
38 | ||
39 | // add archive tables here | |
2aa397bc | 40 | $archiveTables = array(); |
481a74f4 TO |
41 | foreach ($this->tables as $name => $table) { |
42 | if ($table['archive'] == 'true') { | |
5e434adf ARW |
43 | $name = 'archive_' . $table['name']; |
44 | $table['name'] = $name; | |
45 | $table['archive'] = 'false'; | |
481a74f4 | 46 | if (isset($table['foreignKey'])) { |
5e434adf ARW |
47 | foreach ($table['foreignKey'] as $fkName => $fkValue) { |
48 | if ($this->tables[$fkValue['table']]['archive'] == 'true') { | |
49 | $table['foreignKey'][$fkName]['table'] = 'archive_' . $table['foreignKey'][$fkName]['table']; | |
50 | $table['foreignKey'][$fkName]['uniqName'] = | |
481a74f4 | 51 | str_replace('FK_', 'FK_archive_', $table['foreignKey'][$fkName]['uniqName']); |
5e434adf ARW |
52 | } |
53 | } | |
54 | $archiveTables[$name] = $table; | |
55 | } | |
56 | } | |
57 | } | |
58 | } | |
59 | ||
2558c2b0 EM |
60 | /** |
61 | * @param $dbXML | |
62 | * | |
63 | * @return array | |
64 | */ | |
00be9182 | 65 | public function &getDatabase(&$dbXML) { |
5e434adf ARW |
66 | $database = array('name' => trim((string ) $dbXML->name)); |
67 | ||
68 | $attributes = ''; | |
69 | $this->checkAndAppend($attributes, $dbXML, 'character_set', 'DEFAULT CHARACTER SET ', ''); | |
70 | $this->checkAndAppend($attributes, $dbXML, 'collate', 'COLLATE ', ''); | |
71 | $database['attributes'] = $attributes; | |
72 | ||
73 | $tableAttributes_modern = $tableAttributes_simple = ''; | |
74 | $this->checkAndAppend($tableAttributes_modern, $dbXML, 'table_type', 'ENGINE=', ''); | |
75 | $this->checkAndAppend($tableAttributes_simple, $dbXML, 'table_type', 'TYPE=', ''); | |
76 | $database['tableAttributes_modern'] = trim($tableAttributes_modern . ' ' . $attributes); | |
77 | $database['tableAttributes_simple'] = trim($tableAttributes_simple); | |
78 | ||
79 | $database['comment'] = $this->value('comment', $dbXML, ''); | |
80 | ||
81 | return $database; | |
82 | } | |
83 | ||
2558c2b0 EM |
84 | /** |
85 | * @param $dbXML | |
86 | * @param $database | |
87 | * | |
88 | * @return array | |
89 | */ | |
00be9182 | 90 | public function getTables($dbXML, &$database) { |
5e434adf ARW |
91 | $tables = array(); |
92 | foreach ($dbXML->tables as $tablesXML) { | |
93 | foreach ($tablesXML->table as $tableXML) { | |
94 | if ($this->value('drop', $tableXML, 0) > 0 and $this->value('drop', $tableXML, 0) <= $this->buildVersion) { | |
95 | continue; | |
96 | } | |
97 | ||
98 | if ($this->value('add', $tableXML, 0) <= $this->buildVersion) { | |
99 | $this->getTable($tableXML, $database, $tables); | |
100 | } | |
101 | } | |
102 | } | |
103 | ||
104 | return $tables; | |
105 | } | |
106 | ||
2558c2b0 EM |
107 | /** |
108 | * @param $tables | |
100fef9d | 109 | * @param string $classNames |
2558c2b0 | 110 | */ |
00be9182 | 111 | public function resolveForeignKeys(&$tables, &$classNames) { |
5e434adf ARW |
112 | foreach (array_keys($tables) as $name) { |
113 | $this->resolveForeignKey($tables, $classNames, $name); | |
114 | } | |
115 | } | |
116 | ||
2558c2b0 EM |
117 | /** |
118 | * @param $tables | |
100fef9d CW |
119 | * @param string $classNames |
120 | * @param string $name | |
2558c2b0 | 121 | */ |
00be9182 | 122 | public function resolveForeignKey(&$tables, &$classNames, $name) { |
5e434adf ARW |
123 | if (!array_key_exists('foreignKey', $tables[$name])) { |
124 | return; | |
125 | } | |
126 | ||
127 | foreach (array_keys($tables[$name]['foreignKey']) as $fkey) { | |
128 | $ftable = $tables[$name]['foreignKey'][$fkey]['table']; | |
129 | if (!array_key_exists($ftable, $classNames)) { | |
130 | echo "$ftable is not a valid foreign key table in $name\n"; | |
131 | continue; | |
132 | } | |
133 | $tables[$name]['foreignKey'][$fkey]['className'] = $classNames[$ftable]; | |
134 | $tables[$name]['foreignKey'][$fkey]['fileName'] = str_replace('_', '/', $classNames[$ftable]) . '.php'; | |
135 | $tables[$name]['fields'][$fkey]['FKClassName'] = $classNames[$ftable]; | |
136 | } | |
137 | } | |
138 | ||
2558c2b0 EM |
139 | /** |
140 | * @param $tables | |
141 | * | |
142 | * @return array | |
143 | */ | |
00be9182 | 144 | public function orderTables(&$tables) { |
5e434adf ARW |
145 | $ordered = array(); |
146 | ||
147 | while (!empty($tables)) { | |
148 | foreach (array_keys($tables) as $name) { | |
149 | if ($this->validTable($tables, $ordered, $name)) { | |
150 | $ordered[$name] = $tables[$name]; | |
151 | unset($tables[$name]); | |
152 | } | |
153 | } | |
154 | } | |
155 | return $ordered; | |
156 | } | |
157 | ||
2558c2b0 EM |
158 | /** |
159 | * @param $tables | |
100fef9d CW |
160 | * @param int $valid |
161 | * @param string $name | |
2558c2b0 EM |
162 | * |
163 | * @return bool | |
164 | */ | |
00be9182 | 165 | public function validTable(&$tables, &$valid, $name) { |
5e434adf ARW |
166 | if (!array_key_exists('foreignKey', $tables[$name])) { |
167 | return TRUE; | |
168 | } | |
169 | ||
170 | foreach (array_keys($tables[$name]['foreignKey']) as $fkey) { | |
171 | $ftable = $tables[$name]['foreignKey'][$fkey]['table']; | |
172 | if (!array_key_exists($ftable, $valid) && $ftable !== $name) { | |
173 | return FALSE; | |
174 | } | |
175 | } | |
176 | return TRUE; | |
177 | } | |
178 | ||
2558c2b0 EM |
179 | /** |
180 | * @param $tableXML | |
181 | * @param $database | |
182 | * @param $tables | |
183 | */ | |
00be9182 | 184 | public function getTable($tableXML, &$database, &$tables) { |
5e434adf ARW |
185 | $name = trim((string ) $tableXML->name); |
186 | $klass = trim((string ) $tableXML->class); | |
187 | $base = $this->value('base', $tableXML); | |
188 | $sourceFile = "xml/schema/{$base}/{$klass}.xml"; | |
189 | $daoPath = "{$base}/DAO/"; | |
190 | $pre = str_replace('/', '_', $daoPath); | |
191 | $this->classNames[$name] = $pre . $klass; | |
192 | ||
193 | $localizable = FALSE; | |
194 | foreach ($tableXML->field as $fieldXML) { | |
195 | if ($fieldXML->localizable) { | |
196 | $localizable = TRUE; | |
197 | break; | |
198 | } | |
199 | } | |
200 | ||
201 | $table = array( | |
202 | 'name' => $name, | |
203 | 'base' => $daoPath, | |
204 | 'sourceFile' => $sourceFile, | |
205 | 'fileName' => $klass . '.php', | |
206 | 'objectName' => $klass, | |
207 | 'labelName' => substr($name, 8), | |
208 | 'className' => $this->classNames[$name], | |
209 | 'attributes_simple' => trim($database['tableAttributes_simple']), | |
210 | 'attributes_modern' => trim($database['tableAttributes_modern']), | |
211 | 'comment' => $this->value('comment', $tableXML), | |
212 | 'localizable' => $localizable, | |
213 | 'log' => $this->value('log', $tableXML, 'false'), | |
214 | 'archive' => $this->value('archive', $tableXML, 'false'), | |
215 | ); | |
216 | ||
217 | $fields = array(); | |
218 | foreach ($tableXML->field as $fieldXML) { | |
219 | if ($this->value('drop', $fieldXML, 0) > 0 and $this->value('drop', $fieldXML, 0) <= $this->buildVersion) { | |
220 | continue; | |
221 | } | |
222 | ||
223 | if ($this->value('add', $fieldXML, 0) <= $this->buildVersion) { | |
224 | $this->getField($fieldXML, $fields); | |
225 | } | |
226 | } | |
227 | ||
228 | $table['fields'] = &$fields; | |
5e434adf ARW |
229 | |
230 | if ($this->value('primaryKey', $tableXML)) { | |
231 | $this->getPrimaryKey($tableXML->primaryKey, $fields, $table); | |
232 | } | |
233 | ||
234 | // some kind of refresh? | |
235 | CRM_Core_Config::singleton(FALSE); | |
236 | if ($this->value('index', $tableXML)) { | |
237 | $index = array(); | |
238 | foreach ($tableXML->index as $indexXML) { | |
239 | if ($this->value('drop', $indexXML, 0) > 0 and $this->value('drop', $indexXML, 0) <= $this->buildVersion) { | |
240 | continue; | |
241 | } | |
242 | ||
243 | $this->getIndex($indexXML, $fields, $index); | |
244 | } | |
245 | $table['index'] = &$index; | |
246 | } | |
247 | ||
248 | if ($this->value('foreignKey', $tableXML)) { | |
249 | $foreign = array(); | |
250 | foreach ($tableXML->foreignKey as $foreignXML) { | |
251 | // print_r($foreignXML); | |
252 | ||
253 | if ($this->value('drop', $foreignXML, 0) > 0 and $this->value('drop', $foreignXML, 0) <= $this->buildVersion) { | |
254 | continue; | |
255 | } | |
256 | if ($this->value('add', $foreignXML, 0) <= $this->buildVersion) { | |
257 | $this->getForeignKey($foreignXML, $fields, $foreign, $name); | |
258 | } | |
259 | } | |
260 | $table['foreignKey'] = &$foreign; | |
261 | } | |
262 | ||
263 | if ($this->value('dynamicForeignKey', $tableXML)) { | |
264 | $dynamicForeign = array(); | |
265 | foreach ($tableXML->dynamicForeignKey as $foreignXML) { | |
266 | if ($this->value('drop', $foreignXML, 0) > 0 and $this->value('drop', $foreignXML, 0) <= $this->buildVersion) { | |
267 | continue; | |
268 | } | |
269 | if ($this->value('add', $foreignXML, 0) <= $this->buildVersion) { | |
270 | $this->getDynamicForeignKey($foreignXML, $dynamicForeign, $name); | |
271 | } | |
272 | } | |
273 | $table['dynamicForeignKey'] = $dynamicForeign; | |
274 | } | |
275 | ||
276 | $tables[$name] = &$table; | |
277 | return; | |
278 | } | |
279 | ||
2558c2b0 EM |
280 | /** |
281 | * @param $fieldXML | |
282 | * @param $fields | |
283 | */ | |
00be9182 | 284 | public function getField(&$fieldXML, &$fields) { |
5e434adf ARW |
285 | $name = trim((string ) $fieldXML->name); |
286 | $field = array('name' => $name, 'localizable' => $fieldXML->localizable); | |
287 | $type = (string ) $fieldXML->type; | |
288 | switch ($type) { | |
289 | case 'varchar': | |
290 | case 'char': | |
291 | $field['length'] = (int) $fieldXML->length; | |
292 | $field['sqlType'] = "$type({$field['length']})"; | |
293 | $field['phpType'] = 'string'; | |
294 | $field['crmType'] = 'CRM_Utils_Type::T_STRING'; | |
295 | $field['size'] = $this->getSize($fieldXML); | |
296 | break; | |
297 | ||
5e434adf ARW |
298 | case 'text': |
299 | $field['sqlType'] = $field['phpType'] = $type; | |
300 | $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type); | |
5e545f38 CW |
301 | // CRM-13497 see fixme below |
302 | $field['rows'] = isset($fieldXML->html) ? $this->value('rows', $fieldXML->html) : NULL; | |
303 | $field['cols'] = isset($fieldXML->html) ? $this->value('cols', $fieldXML->html) : NULL; | |
304 | break; | |
2aa397bc TO |
305 | |
306 | break; | |
5e434adf ARW |
307 | |
308 | case 'datetime': | |
309 | $field['sqlType'] = $field['phpType'] = $type; | |
310 | $field['crmType'] = 'CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME'; | |
311 | break; | |
312 | ||
313 | case 'boolean': | |
314 | // need this case since some versions of mysql do not have boolean as a valid column type and hence it | |
315 | // is changed to tinyint. hopefully after 2 yrs this case can be removed. | |
316 | $field['sqlType'] = 'tinyint'; | |
317 | $field['phpType'] = $type; | |
318 | $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type); | |
319 | break; | |
320 | ||
321 | case 'decimal': | |
322 | $length = $fieldXML->length ? $fieldXML->length : '20,2'; | |
323 | $field['sqlType'] = 'decimal(' . $length . ')'; | |
324 | $field['phpType'] = 'float'; | |
325 | $field['crmType'] = 'CRM_Utils_Type::T_MONEY'; | |
ac5f2ccd | 326 | $field['precision'] = $length; |
5e434adf ARW |
327 | break; |
328 | ||
329 | case 'float': | |
330 | $field['sqlType'] = 'double'; | |
331 | $field['phpType'] = 'float'; | |
332 | $field['crmType'] = 'CRM_Utils_Type::T_FLOAT'; | |
333 | break; | |
334 | ||
335 | default: | |
336 | $field['sqlType'] = $field['phpType'] = $type; | |
337 | if ($type == 'int unsigned') { | |
338 | $field['crmType'] = 'CRM_Utils_Type::T_INT'; | |
339 | } | |
340 | else { | |
341 | $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type); | |
342 | } | |
343 | break; | |
344 | } | |
345 | ||
346 | $field['required'] = $this->value('required', $fieldXML); | |
347 | $field['collate'] = $this->value('collate', $fieldXML); | |
348 | $field['comment'] = $this->value('comment', $fieldXML); | |
349 | $field['default'] = $this->value('default', $fieldXML); | |
350 | $field['import'] = $this->value('import', $fieldXML); | |
351 | if ($this->value('export', $fieldXML)) { | |
352 | $field['export'] = $this->value('export', $fieldXML); | |
353 | } | |
354 | else { | |
355 | $field['export'] = $this->value('import', $fieldXML); | |
356 | } | |
357 | $field['rule'] = $this->value('rule', $fieldXML); | |
358 | $field['title'] = $this->value('title', $fieldXML); | |
359 | if (!$field['title']) { | |
360 | $field['title'] = $this->composeTitle($name); | |
361 | } | |
362 | $field['headerPattern'] = $this->value('headerPattern', $fieldXML); | |
363 | $field['dataPattern'] = $this->value('dataPattern', $fieldXML); | |
364 | $field['uniqueName'] = $this->value('uniqueName', $fieldXML); | |
5e545f38 CW |
365 | $field['html'] = $this->value('html', $fieldXML); |
366 | if (!empty($field['html'])) { | |
367 | $validOptions = array( | |
368 | 'type', | |
369 | /* Fixme: prior to CRM-13497 these were in a flat structure | |
370 | // CRM-13497 moved them to be nested within 'html' but there's no point | |
371 | // making that change in the DAOs right now since we are in the process of | |
372 | // moving to docrtine anyway. | |
373 | // So translating from nested xml back to flat structure for now. | |
374 | 'rows', | |
375 | 'cols', | |
376 | 'size', */ | |
377 | ); | |
378 | $field['html'] = array(); | |
379 | foreach ($validOptions as $htmlOption) { | |
9b873358 | 380 | if (!empty($fieldXML->html->$htmlOption)) { |
5e545f38 CW |
381 | $field['html'][$htmlOption] = $this->value($htmlOption, $fieldXML->html); |
382 | } | |
383 | } | |
384 | } | |
5e434adf | 385 | $field['pseudoconstant'] = $this->value('pseudoconstant', $fieldXML); |
9b873358 | 386 | if (!empty($field['pseudoconstant'])) { |
5e434adf ARW |
387 | //ok this is a bit long-winded but it gets there & is consistent with above approach |
388 | $field['pseudoconstant'] = array(); | |
389 | $validOptions = array( | |
390 | // Fields can specify EITHER optionGroupName OR table, not both | |
391 | // (since declaring optionGroupName means we are using the civicrm_option_value table) | |
392 | 'optionGroupName', | |
393 | 'table', | |
394 | // If table is specified, keyColumn and labelColumn are also required | |
395 | 'keyColumn', | |
396 | 'labelColumn', | |
397 | // Non-translated machine name for programmatic lookup. Defaults to 'name' if that column exists | |
398 | 'nameColumn', | |
399 | // Where clause snippet (will be joined to the rest of the query with AND operator) | |
400 | 'condition', | |
cc6443c4 | 401 | // callback funtion incase of static arrays |
402 | 'callback', | |
5e434adf ARW |
403 | ); |
404 | foreach ($validOptions as $pseudoOption) { | |
9b873358 | 405 | if (!empty($fieldXML->pseudoconstant->$pseudoOption)) { |
5e434adf ARW |
406 | $field['pseudoconstant'][$pseudoOption] = $this->value($pseudoOption, $fieldXML->pseudoconstant); |
407 | } | |
408 | } | |
409 | // For now, fields that have option lists that are not in the db can simply | |
410 | // declare an empty pseudoconstant tag and we'll add this placeholder. | |
411 | // That field's BAO::buildOptions fn will need to be responsible for generating the option list | |
412 | if (empty($field['pseudoconstant'])) { | |
413 | $field['pseudoconstant'] = 'not in database'; | |
414 | } | |
415 | } | |
416 | $fields[$name] = &$field; | |
417 | } | |
418 | ||
2558c2b0 | 419 | /** |
100fef9d | 420 | * @param string $name |
2558c2b0 EM |
421 | * |
422 | * @return string | |
423 | */ | |
00be9182 | 424 | public function composeTitle($name) { |
5e434adf ARW |
425 | $names = explode('_', strtolower($name)); |
426 | $title = ''; | |
427 | for ($i = 0; $i < count($names); $i++) { | |
428 | if ($names[$i] === 'id' || $names[$i] === 'is') { | |
429 | // id's do not get titles | |
430 | return NULL; | |
431 | } | |
432 | ||
433 | if ($names[$i] === 'im') { | |
434 | $names[$i] = 'IM'; | |
435 | } | |
436 | else { | |
437 | $names[$i] = ucfirst(trim($names[$i])); | |
438 | } | |
439 | ||
440 | $title = $title . ' ' . $names[$i]; | |
441 | } | |
442 | return trim($title); | |
443 | } | |
444 | ||
2558c2b0 EM |
445 | /** |
446 | * @param $primaryXML | |
447 | * @param $fields | |
448 | * @param $table | |
449 | */ | |
00be9182 | 450 | public function getPrimaryKey(&$primaryXML, &$fields, &$table) { |
5e434adf ARW |
451 | $name = trim((string ) $primaryXML->name); |
452 | ||
453 | /** need to make sure there is a field of type name */ | |
454 | if (!array_key_exists($name, $fields)) { | |
2aa397bc | 455 | echo "primary key $name in $table->name does not have a field definition, ignoring\n"; |
5e434adf ARW |
456 | return; |
457 | } | |
458 | ||
459 | // set the autoincrement property of the field | |
460 | $auto = $this->value('autoincrement', $primaryXML); | |
461 | $fields[$name]['autoincrement'] = $auto; | |
462 | $primaryKey = array( | |
463 | 'name' => $name, | |
464 | 'autoincrement' => $auto, | |
465 | ); | |
466 | $table['primaryKey'] = &$primaryKey; | |
467 | } | |
468 | ||
2558c2b0 EM |
469 | /** |
470 | * @param $indexXML | |
471 | * @param $fields | |
472 | * @param $indices | |
473 | */ | |
00be9182 | 474 | public function getIndex(&$indexXML, &$fields, &$indices) { |
5e434adf ARW |
475 | //echo "\n\n*******************************************************\n"; |
476 | //echo "entering getIndex\n"; | |
477 | ||
478 | $index = array(); | |
479 | // empty index name is fine | |
2aa397bc | 480 | $indexName = trim((string) $indexXML->name); |
5e434adf ARW |
481 | $index['name'] = $indexName; |
482 | $index['field'] = array(); | |
483 | ||
484 | // populate fields | |
485 | foreach ($indexXML->fieldName as $v) { | |
2aa397bc TO |
486 | $fieldName = (string) ($v); |
487 | $length = (string) ($v['length']); | |
5e434adf ARW |
488 | if (strlen($length) > 0) { |
489 | $fieldName = "$fieldName($length)"; | |
490 | } | |
491 | $index['field'][] = $fieldName; | |
492 | } | |
493 | ||
494 | $index['localizable'] = FALSE; | |
495 | foreach ($index['field'] as $fieldName) { | |
496 | if (isset($fields[$fieldName]) and $fields[$fieldName]['localizable']) { | |
497 | $index['localizable'] = TRUE; | |
498 | break; | |
499 | } | |
500 | } | |
501 | ||
502 | // check for unique index | |
503 | if ($this->value('unique', $indexXML)) { | |
504 | $index['unique'] = TRUE; | |
505 | } | |
506 | ||
507 | //echo "\$index = \n"; | |
508 | //print_r($index); | |
509 | ||
510 | // field array cannot be empty | |
511 | if (empty($index['field'])) { | |
512 | echo "No fields defined for index $indexName\n"; | |
513 | return; | |
514 | } | |
515 | ||
516 | // all fieldnames have to be defined and should exist in schema. | |
517 | foreach ($index['field'] as $fieldName) { | |
518 | if (!$fieldName) { | |
519 | echo "Invalid field defination for index $indexName\n"; | |
520 | return; | |
521 | } | |
522 | $parenOffset = strpos($fieldName, '('); | |
523 | if ($parenOffset > 0) { | |
524 | $fieldName = substr($fieldName, 0, $parenOffset); | |
525 | } | |
526 | if (!array_key_exists($fieldName, $fields)) { | |
527 | echo "Table does not contain $fieldName\n"; | |
528 | print_r($fields); | |
529 | exit(); | |
530 | } | |
531 | } | |
532 | $indices[$indexName] = &$index; | |
533 | } | |
534 | ||
2558c2b0 EM |
535 | /** |
536 | * @param $foreignXML | |
537 | * @param $fields | |
538 | * @param $foreignKeys | |
100fef9d | 539 | * @param string $currentTableName |
2558c2b0 | 540 | */ |
00be9182 | 541 | public function getForeignKey(&$foreignXML, &$fields, &$foreignKeys, &$currentTableName) { |
5e434adf ARW |
542 | $name = trim((string ) $foreignXML->name); |
543 | ||
544 | /** need to make sure there is a field of type name */ | |
545 | if (!array_key_exists($name, $fields)) { | |
2aa397bc | 546 | echo "foreign $name in $currentTableName does not have a field definition, ignoring\n"; |
5e434adf ARW |
547 | return; |
548 | } | |
549 | ||
550 | /** need to check for existence of table and key **/ | |
551 | $table = trim($this->value('table', $foreignXML)); | |
552 | $foreignKey = array( | |
553 | 'name' => $name, | |
554 | 'table' => $table, | |
555 | 'uniqName' => "FK_{$currentTableName}_{$name}", | |
556 | 'key' => trim($this->value('key', $foreignXML)), | |
557 | 'import' => $this->value('import', $foreignXML, FALSE), | |
558 | 'export' => $this->value('import', $foreignXML, FALSE), | |
559 | // we do this matching in a seperate phase (resolveForeignKeys) | |
560 | 'className' => NULL, | |
561 | 'onDelete' => $this->value('onDelete', $foreignXML, FALSE), | |
562 | ); | |
563 | $foreignKeys[$name] = &$foreignKey; | |
564 | } | |
565 | ||
2558c2b0 EM |
566 | /** |
567 | * @param $foreignXML | |
568 | * @param $dynamicForeignKeys | |
569 | */ | |
00be9182 | 570 | public function getDynamicForeignKey(&$foreignXML, &$dynamicForeignKeys) { |
5e434adf ARW |
571 | $foreignKey = array( |
572 | 'idColumn' => trim($foreignXML->idColumn), | |
573 | 'typeColumn' => trim($foreignXML->typeColumn), | |
574 | 'key' => trim($this->value('key', $foreignXML)), | |
575 | ); | |
576 | $dynamicForeignKeys[] = $foreignKey; | |
577 | } | |
578 | ||
2558c2b0 EM |
579 | /** |
580 | * @param $key | |
581 | * @param $object | |
582 | * @param null $default | |
583 | * | |
584 | * @return null|string | |
585 | */ | |
5e434adf ARW |
586 | protected function value($key, &$object, $default = NULL) { |
587 | if (isset($object->$key)) { | |
588 | return (string ) $object->$key; | |
589 | } | |
590 | return $default; | |
591 | } | |
592 | ||
2558c2b0 EM |
593 | /** |
594 | * @param $attributes | |
595 | * @param $object | |
100fef9d | 596 | * @param string $name |
2558c2b0 EM |
597 | * @param null $pre |
598 | * @param null $post | |
599 | */ | |
5e434adf ARW |
600 | protected function checkAndAppend(&$attributes, &$object, $name, $pre = NULL, $post = NULL) { |
601 | if (!isset($object->$name)) { | |
602 | return; | |
603 | } | |
604 | ||
605 | $value = $pre . trim($object->$name) . $post; | |
606 | $this->append($attributes, ' ', trim($value)); | |
607 | } | |
608 | ||
2558c2b0 EM |
609 | /** |
610 | * @param $str | |
611 | * @param $delim | |
612 | * @param $name | |
613 | */ | |
5e434adf ARW |
614 | protected function append(&$str, $delim, $name) { |
615 | if (empty($name)) { | |
616 | return; | |
617 | } | |
618 | ||
619 | if (is_array($name)) { | |
620 | foreach ($name as $n) { | |
621 | if (empty($n)) { | |
622 | continue; | |
623 | } | |
624 | if (empty($str)) { | |
625 | $str = $n; | |
626 | } | |
627 | else { | |
628 | $str .= $delim . $n; | |
629 | } | |
630 | } | |
631 | } | |
632 | else { | |
633 | if (empty($str)) { | |
634 | $str = $name; | |
635 | } | |
636 | else { | |
637 | $str .= $delim . $name; | |
638 | } | |
639 | } | |
640 | } | |
641 | ||
642 | /** | |
643 | * Sets the size property of a textfield | |
644 | * See constants defined in CRM_Utils_Type for possible values | |
645 | */ | |
646 | protected function getSize($fieldXML) { | |
647 | // Extract from <size> tag if supplied | |
5e545f38 CW |
648 | if (!empty($fieldXML->html) && $this->value('size', $fieldXML->html)) { |
649 | $const = 'CRM_Utils_Type::' . strtoupper($fieldXML->html->size); | |
5e434adf ARW |
650 | if (defined($const)) { |
651 | return $const; | |
652 | } | |
653 | } | |
654 | // Infer from <length> tag if <size> was not explicitly set or was invalid | |
655 | ||
656 | // This map is slightly different from CRM_Core_Form_Renderer::$_sizeMapper | |
657 | // Because we usually want fields to render as smaller than their maxlength | |
658 | $sizes = array( | |
659 | 2 => 'TWO', | |
660 | 4 => 'FOUR', | |
661 | 6 => 'SIX', | |
662 | 8 => 'EIGHT', | |
663 | 16 => 'TWELVE', | |
664 | 32 => 'MEDIUM', | |
665 | 64 => 'BIG', | |
666 | ); | |
667 | foreach ($sizes as $length => $name) { | |
668 | if ($fieldXML->length <= $length) { | |
669 | return "CRM_Utils_Type::$name"; | |
670 | } | |
671 | } | |
672 | return 'CRM_Utils_Type::HUGE'; | |
673 | } | |
674 | } |