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