2 ini_set('include_path', '.' . PATH_SEPARATOR
. '..' . DIRECTORY_SEPARATOR
. 'packages' . PATH_SEPARATOR
. '..');
3 ini_set('memory_limit', '512M');
4 date_default_timezone_set('UTC'); // avoid php warnings if timezone is not set - CRM-10844
6 define('CIVICRM_UF', 'Drupal');
8 require_once 'CRM/Core/ClassLoader.php';
9 CRM_Core_ClassLoader
::singleton()->register();
11 $genCode = new CRM_GenCode_Main('../CRM/Core/DAO/', '../sql/', '../', '../templates/');
15 empty($argv[1]) ?
'schema/Schema.xml' : $argv[1]
18 class CRM_GenCode_Util_File
{
19 static function createDir($dir, $perm = 0755) {
21 mkdir($dir, $perm, TRUE);
25 static function removeDir($dir) {
26 foreach (glob("$dir/*") as $tempFile) {
32 static function createTempDir($prefix) {
33 if (isset($_SERVER['TMPDIR'])) {
34 $tempDir = $_SERVER['TMPDIR'];
40 $newTempDir = $tempDir . '/' . $prefix . rand(1, 10000);
42 if (file_exists($newTempDir)) {
43 self
::removeDir($newTempDir);
45 self
::createDir($newTempDir);
51 class CRM_GenCode_Main
{
63 function __construct($CoreDAOCodePath, $sqlCodePath, $phpCodePath, $tplCodePath) {
64 $this->CoreDAOCodePath
= $CoreDAOCodePath;
65 $this->sqlCodePath
= $sqlCodePath;
66 $this->phpCodePath
= $phpCodePath;
67 $this->tplCodePath
= $tplCodePath;
69 require_once 'Smarty/Smarty.class.php';
70 $this->smarty
= new Smarty();
71 $this->smarty
->template_dir
= './templates';
72 $this->smarty
->plugins_dir
= array('../packages/Smarty/plugins', '../CRM/Core/Smarty/plugins');
73 $this->compileDir
= CRM_GenCode_Util_File
::createTempDir('templates_c_');
74 $this->smarty
->compile_dir
= $this->compileDir
;
75 $this->smarty
->clear_all_cache();
77 // CRM-5308 / CRM-3507 - we need {localize} to work in the templates
78 require_once 'CRM/Core/Smarty/plugins/block.localize.php';
79 $this->smarty
->register_block('localize', 'smarty_block_localize');
81 require_once 'PHP/Beautifier.php';
83 $this->beautifier
= new PHP_Beautifier();
84 $this->beautifier
->addFilter('ArrayNested');
85 // add one or more filters
86 $this->beautifier
->addFilter('Pear');
87 // add one or more filters
88 $this->beautifier
->addFilter('NewLines', array('after' => 'class, public, require, comment'));
89 $this->beautifier
->setIndentChar(' ');
90 $this->beautifier
->setIndentNumber(2);
91 $this->beautifier
->setNewLine("\n");
93 CRM_GenCode_Util_File
::createDir($this->sqlCodePath
);
96 function __destruct() {
97 CRM_GenCode_Util_File
::removeDir($this->compileDir
);
101 * Automatically generate a variety of files
103 * @param $argVersion string, optional
104 * @param $argCms string, optional; "drupal" or "joomla"
105 * @param $file, the path to the XML schema file
107 function main($argVersion, $argCms, $file) {
108 $versionFile = "version.xml";
109 $versionXML = &$this->parseInput($versionFile);
110 $db_version = $versionXML->version_no
;
111 $this->buildVersion
= preg_replace('/^(\d{1,2}\.\d{1,2})\.(\d{1,2}|\w{4,7})$/i', '$1', $db_version);
112 if (isset($argVersion)) {
113 // change the version to that explicitly passed, if any
114 $db_version = $argVersion;
116 echo "\ncivicrm_domain.version := $db_version\n\n";
117 if ($this->buildVersion
< 1.1) {
118 echo "The Database is not compatible for this version";
122 if (substr(phpversion(), 0, 1) != 5) {
123 echo phpversion() . ', ' . substr(phpversion(), 0, 1) . "\n";
125 CiviCRM requires a PHP Version >= 5
126 Please upgrade your php / webserver configuration
127 Alternatively you can get a version of CiviCRM that matches your PHP version
132 $this->generateTemplateVersion($argVersion);
134 $this->setupCms($argCms, $db_version);
136 echo "Parsing input file $file\n";
137 $dbXML = $this->parseInput($file);
138 // print_r( $dbXML );
140 echo "Extracting database information\n";
141 $database = &$this->getDatabase($dbXML);
142 // print_r( $database );
144 $this->classNames
= array();
146 echo "Extracting table information\n";
147 $tables = &$this->getTables($dbXML, $database);
149 $this->resolveForeignKeys($tables, $this->classNames
);
150 $tables = $this->orderTables($tables);
152 // add archive tables here
153 $archiveTables = array( );
154 foreach ($tables as $name => $table ) {
155 if ( $table['archive'] == 'true' ) {
156 $name = 'archive_' . $table['name'];
157 $table['name'] = $name;
158 $table['archive'] = 'false';
159 if ( isset($table['foreignKey']) ) {
160 foreach ($table['foreignKey'] as $fkName => $fkValue) {
161 if ($tables[$fkValue['table']]['archive'] == 'true') {
162 $table['foreignKey'][$fkName]['table'] = 'archive_' . $table['foreignKey'][$fkName]['table'];
163 $table['foreignKey'][$fkName]['uniqName'] =
164 str_replace( 'FK_', 'FK_archive_', $table['foreignKey'][$fkName]['uniqName'] );
167 $archiveTables[$name] = $table;
172 $this->generateListAll($tables);
173 $this->generateCiviTestTruncate($tables);
174 $this->generateCreateSql($database, $tables, 'civicrm.mysql');
175 $this->generateDropSql($tables, 'civicrm_drop.mysql');
177 // also create the archive tables
178 // $this->generateCreateSql($database, $archiveTables, 'civicrm_archive.mysql' );
179 // $this->generateDropSql($archiveTables, 'civicrm_archive_drop.mysql');
181 $this->generateNavigation();
182 $this->generateLocalDataSql($db_version, $this->findLocales());
183 $this->generateSample();
184 $this->generateInstallLangs();
185 $this->generateDAOs($tables);
186 $this->generateSchemaStructure($tables);
189 function generateListAll($tables) {
190 $allDAO = "<?php\n\$dao = array ();";
193 foreach ($tables as $table) {
194 $base = $table['base'] . $table['objectName'];
195 if (!array_key_exists($table['objectName'], $dao)) {
196 $dao[$table['objectName']] = str_replace('/', '_', $base);
197 $allDAO .= "\n\$dao['" . $table['objectName'] . "'] = '" . str_replace('/', '_', $base) . "';";
200 $allDAO .= "\n//NAMESPACE ERROR: " . $table['objectName'] . " already used . " . str_replace('/', '_', $base) . " ignored.";
204 // TODO deal with the BAO's too ?
205 file_put_contents($this->CoreDAOCodePath
. "listAll.php", $allDAO);
208 function generateCiviTestTruncate($tables) {
209 echo "Generating tests truncate file\n";
211 $truncate = '<?xml version="1.0" encoding="UTF-8" ?>
212 <!-- Truncate all tables that will be used in the tests -->
214 $tbls = array_keys($tables);
215 foreach ($tbls as $d => $t) {
216 $truncate = $truncate . "\n <$t />\n";
219 $truncate = $truncate . "</dataset>\n";
220 file_put_contents($this->sqlCodePath
. "../tests/phpunit/CiviTest/truncate.xml", $truncate);
224 function generateCreateSql($database, $tables, $fileName = 'civicrm.mysql') {
225 echo "Generating sql file\n";
226 $this->smarty
->clear_all_assign();
227 $this->smarty
->assign_by_ref('database', $database);
228 $this->smarty
->assign_by_ref('tables', $tables);
229 $dropOrder = array_reverse(array_keys($tables));
230 $this->smarty
->assign_by_ref('dropOrder', $dropOrder);
231 $this->smarty
->assign('mysql', 'modern');
232 file_put_contents($this->sqlCodePath
. $fileName, $this->smarty
->fetch('schema.tpl'));
235 function generateDropSql($tables, $fileName = 'civicrm_drop.mysql') {
236 echo "Generating sql drop tables file\n";
237 $dropOrder = array_reverse(array_keys($tables));
238 $this->smarty
->assign_by_ref('dropOrder', $dropOrder);
239 file_put_contents($this->sqlCodePath
. $fileName, $this->smarty
->fetch('drop.tpl'));
242 function generateNavigation() {
243 echo "Generating navigation file\n";
244 $this->smarty
->clear_all_assign();
245 file_put_contents($this->sqlCodePath
. "civicrm_navigation.mysql", $this->smarty
->fetch('civicrm_navigation.tpl'));
248 function generateLocalDataSql($db_version, $locales) {
249 $this->smarty
->clear_all_assign();
252 $oldTsLocale = $tsLocale;
253 foreach ($locales as $locale) {
254 echo "Generating data files for $locale\n";
256 $this->smarty
->assign('locale', $locale);
259 $data[] = $this->smarty
->fetch('civicrm_country.tpl');
260 $data[] = $this->smarty
->fetch('civicrm_state_province.tpl');
261 $data[] = $this->smarty
->fetch('civicrm_currency.tpl');
262 $data[] = $this->smarty
->fetch('civicrm_data.tpl');
263 $data[] = $this->smarty
->fetch('civicrm_navigation.tpl');
265 $data[] = " UPDATE civicrm_domain SET version = '$db_version';";
267 $data = implode("\n", $data);
269 $ext = ($locale != 'en_US' ?
".$locale" : '');
270 // write the initialize base-data sql script
271 file_put_contents($this->sqlCodePath
. "civicrm_data$ext.mysql", $data);
273 // write the acl sql script
274 file_put_contents($this->sqlCodePath
. "civicrm_acl$ext.mysql", $this->smarty
->fetch('civicrm_acl.tpl'));
276 $tsLocale = $oldTsLocale;
279 function generateSample() {
280 $this->smarty
->clear_all_assign();
281 $sample = $this->smarty
->fetch('civicrm_sample.tpl');
282 $sample .= $this->smarty
->fetch('civicrm_acl.tpl');
283 file_put_contents($this->sqlCodePath
. 'civicrm_sample.mysql', $sample);
286 function generateInstallLangs() {
287 // CRM-7161: generate install/langs.php from the languages template
288 // grep it for enabled languages and create a 'xx_YY' => 'Language name' $langs mapping
290 preg_match_all('/, 1, \'([a-z][a-z]_[A-Z][A-Z])\', \'..\', \{localize\}\'\{ts escape="sql"\}(.+)\{\/ts\}\'\{\/localize\}, /', file_get_contents('templates/languages.tpl'), $matches);
292 for ($i = 0; $i < count($matches[0]); $i++
) {
293 $langs[$matches[1][$i]] = $matches[2][$i];
295 file_put_contents('../install/langs.php', "<?php \$langs = unserialize('" . serialize($langs) . "');");
298 function generateDAOs($tables) {
299 $this->smarty
->clear_all_assign();
300 foreach (array_keys($tables) as $name) {
301 $this->smarty
->clear_all_cache();
302 echo "Generating $name as " . $tables[$name]['fileName'] . "\n";
303 $this->smarty
->clear_all_assign();
305 $this->smarty
->assign_by_ref('table', $tables[$name]);
306 $php = $this->smarty
->fetch('dao.tpl');
308 $this->beautifier
->setInputString($php);
310 if (empty($tables[$name]['base'])) {
311 echo "No base defined for $name, skipping output generation\n";
315 $directory = $this->phpCodePath
. $tables[$name]['base'];
316 CRM_GenCode_Util_File
::createDir($directory);
317 $this->beautifier
->setOutputFile($directory . $tables[$name]['fileName']);
319 $this->beautifier
->process();
321 $this->beautifier
->save();
325 function generateSchemaStructure($tables) {
326 echo "Generating CRM_Core_I18n_SchemaStructure...\n";
329 foreach ($tables as $table) {
330 if ($table['localizable']) {
331 $columns[$table['name']] = array();
336 foreach ($table['fields'] as $field) {
337 if ($field['localizable']) {
338 $columns[$table['name']][$field['name']] = $field['sqlType'];
341 if (isset($table['index'])) {
342 foreach ($table['index'] as $index) {
343 if ($index['localizable']) {
344 $indices[$table['name']][$index['name']] = $index;
350 $this->smarty
->clear_all_cache();
351 $this->smarty
->clear_all_assign();
352 $this->smarty
->assign_by_ref('columns', $columns);
353 $this->smarty
->assign_by_ref('indices', $indices);
355 $this->beautifier
->setInputString($this->smarty
->fetch('schema_structure.tpl'));
356 $this->beautifier
->setOutputFile($this->phpCodePath
. "/CRM/Core/I18n/SchemaStructure.php");
357 $this->beautifier
->process();
358 $this->beautifier
->save();
361 function generateTemplateVersion($argVersion) {
362 // add the Subversion revision to templates
363 // use svnversion if the version was not specified explicitely on the commandline
364 if (isset($argVersion) and $argVersion != '') {
365 $svnversion = $argVersion;
368 $svnversion = `svnversion
.`
;
370 file_put_contents($this->tplCodePath
. "/CRM/common/version.tpl", $svnversion);
373 function findLocales() {
374 require_once 'CRM/Core/Config.php';
375 $config = CRM_Core_Config
::singleton(FALSE);
377 if (substr($config->gettextResourceDir
, 0, 1) === '/') {
378 $localeDir = $config->gettextResourceDir
;
381 $localeDir = '../' . $config->gettextResourceDir
;
383 if (file_exists($localeDir)) {
384 $config->gettextResourceDir
= $localeDir;
385 $locales = preg_grep('/^[a-z][a-z]_[A-Z][A-Z]$/', scandir($localeDir));
388 $localesMask = getenv('CIVICRM_LOCALES');
389 if (!empty($localesMask)) {
390 $mask = explode(',', $localesMask);
391 $locales = array_intersect($locales, $mask);
394 if (!in_array('en_US', $locales)) {
395 array_unshift($locales, 'en_US');
401 function setupCms($argCms, $db_version) {
402 // default cms is 'drupal', if not specified
403 $cms = isset($argCms) ?
strtolower($argCms) : 'drupal';
404 if (!in_array($cms, array(
405 'drupal', 'joomla'))) {
406 echo "Config file for '{$cms}' not known.";
409 elseif ($cms !== 'joomla') {
410 echo "Generating civicrm.config.php\n";
411 copy("../{$cms}/civicrm.config.php.{$cms}", '../civicrm.config.php');
414 echo "Generating civicrm-version file\n";
415 $this->smarty
->assign('db_version', $db_version);
416 $this->smarty
->assign('cms', ucwords($cms));
417 file_put_contents($this->phpCodePath
. "civicrm-version.php", $this->smarty
->fetch('civicrm_version.tpl'));
420 // -----------------------------
421 // ---- Schema manipulation ----
422 // -----------------------------
423 function &parseInput($file) {
424 $dom = new DomDocument();
427 $dbXML = simplexml_import_dom($dom);
431 function &getDatabase(&$dbXML) {
432 $database = array('name' => trim((string ) $dbXML->name
));
435 $this->checkAndAppend($attributes, $dbXML, 'character_set', 'DEFAULT CHARACTER SET ', '');
436 $this->checkAndAppend($attributes, $dbXML, 'collate', 'COLLATE ', '');
437 $database['attributes'] = $attributes;
439 $tableAttributes_modern = $tableAttributes_simple = '';
440 $this->checkAndAppend($tableAttributes_modern, $dbXML, 'table_type', 'ENGINE=', '');
441 $this->checkAndAppend($tableAttributes_simple, $dbXML, 'table_type', 'TYPE=', '');
442 $database['tableAttributes_modern'] = trim($tableAttributes_modern . ' ' . $attributes);
443 $database['tableAttributes_simple'] = trim($tableAttributes_simple);
445 $database['comment'] = $this->value('comment', $dbXML, '');
450 function &getTables(&$dbXML, &$database) {
452 foreach ($dbXML->tables
as $tablesXML) {
453 foreach ($tablesXML->table
as $tableXML) {
454 if ($this->value('drop', $tableXML, 0) > 0 and $this->value('drop', $tableXML, 0) <= $this->buildVersion
) {
458 if ($this->value('add', $tableXML, 0) <= $this->buildVersion
) {
459 $this->getTable($tableXML, $database, $tables);
467 function resolveForeignKeys(&$tables, &$classNames) {
468 foreach (array_keys($tables) as $name) {
469 $this->resolveForeignKey($tables, $classNames, $name);
473 function resolveForeignKey(&$tables, &$classNames, $name) {
474 if (!array_key_exists('foreignKey', $tables[$name])) {
478 foreach (array_keys($tables[$name]['foreignKey']) as $fkey) {
479 $ftable = $tables[$name]['foreignKey'][$fkey]['table'];
480 if (!array_key_exists($ftable, $classNames)) {
481 echo "$ftable is not a valid foreign key table in $name\n";
484 $tables[$name]['foreignKey'][$fkey]['className'] = $classNames[$ftable];
485 $tables[$name]['foreignKey'][$fkey]['fileName'] = str_replace('_', '/', $classNames[$ftable]) . '.php';
486 $tables[$name]['fields'][$fkey]['FKClassName'] = $classNames[$ftable];
490 function orderTables(&$tables) {
493 while (!empty($tables)) {
494 foreach (array_keys($tables) as $name) {
495 if ($this->validTable($tables, $ordered, $name)) {
496 $ordered[$name] = $tables[$name];
497 unset($tables[$name]);
504 function validTable(&$tables, &$valid, $name) {
505 if (!array_key_exists('foreignKey', $tables[$name])) {
509 foreach (array_keys($tables[$name]['foreignKey']) as $fkey) {
510 $ftable = $tables[$name]['foreignKey'][$fkey]['table'];
511 if (!array_key_exists($ftable, $valid) && $ftable !== $name) {
518 function getTable($tableXML, &$database, &$tables) {
519 $name = trim((string ) $tableXML->name
);
520 $klass = trim((string ) $tableXML->class);
521 $base = $this->value('base', $tableXML) . '/DAO/';
522 $pre = str_replace('/', '_', $base);
523 $this->classNames
[$name] = $pre . $klass;
525 $localizable = FALSE;
526 foreach ($tableXML->field
as $fieldXML) {
527 if ($fieldXML->localizable
) {
536 'fileName' => $klass . '.php',
537 'objectName' => $klass,
538 'labelName' => substr($name, 8),
539 'className' => $this->classNames
[$name],
540 'attributes_simple' => trim($database['tableAttributes_simple']),
541 'attributes_modern' => trim($database['tableAttributes_modern']),
542 'comment' => $this->value('comment', $tableXML),
543 'localizable' => $localizable,
544 'log' => $this->value('log', $tableXML, 'false'),
545 'archive' => $this->value('archive', $tableXML, 'false'),
549 foreach ($tableXML->field
as $fieldXML) {
550 if ($this->value('drop', $fieldXML, 0) > 0 and $this->value('drop', $fieldXML, 0) <= $this->buildVersion
) {
554 if ($this->value('add', $fieldXML, 0) <= $this->buildVersion
) {
555 $this->getField($fieldXML, $fields);
559 $table['fields'] = &$fields;
560 $table['hasEnum'] = FALSE;
561 foreach ($table['fields'] as $field) {
562 if ($field['crmType'] == 'CRM_Utils_Type::T_ENUM') {
563 $table['hasEnum'] = TRUE;
568 if ($this->value('primaryKey', $tableXML)) {
569 $this->getPrimaryKey($tableXML->primaryKey
, $fields, $table);
572 // some kind of refresh?
573 CRM_Core_Config
::singleton(FALSE);
574 if ($this->value('index', $tableXML)) {
576 foreach ($tableXML->index
as $indexXML) {
577 if ($this->value('drop', $indexXML, 0) > 0 and $this->value('drop', $indexXML, 0) <= $this->buildVersion
) {
581 $this->getIndex($indexXML, $fields, $index);
583 $table['index'] = &$index;
586 if ($this->value('foreignKey', $tableXML)) {
588 foreach ($tableXML->foreignKey
as $foreignXML) {
589 // print_r($foreignXML);
591 if ($this->value('drop', $foreignXML, 0) > 0 and $this->value('drop', $foreignXML, 0) <= $this->buildVersion
) {
594 if ($this->value('add', $foreignXML, 0) <= $this->buildVersion
) {
595 $this->getForeignKey($foreignXML, $fields, $foreign, $name);
598 $table['foreignKey'] = &$foreign;
601 $tables[$name] = &$table;
605 function getField(&$fieldXML, &$fields) {
606 $name = trim((string ) $fieldXML->name
);
607 $field = array('name' => $name, 'localizable' => $fieldXML->localizable
);
608 $type = (string ) $fieldXML->type
;
612 $field['length'] = (int) $fieldXML->length
;
613 $field['sqlType'] = "$type({$field['length']})";
614 $field['phpType'] = 'string';
615 $field['crmType'] = 'CRM_Utils_Type::T_STRING';
616 $field['size'] = $this->getSize($fieldXML);
620 $value = (string ) $fieldXML->values
;
621 $field['sqlType'] = 'enum(';
622 $field['values'] = array();
623 $field['enumValues'] = $value;
624 $values = explode(',', $value);
626 foreach ($values as $v) {
628 $field['values'][] = $v;
631 $field['sqlType'] .= ', ';
634 $field['sqlType'] .= "'$v'";
636 $field['sqlType'] .= ')';
637 $field['phpType'] = $field['sqlType'];
638 $field['crmType'] = 'CRM_Utils_Type::T_ENUM';
642 $field['sqlType'] = $field['phpType'] = $type;
643 $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type);
644 $field['rows'] = $this->value('rows', $fieldXML);
645 $field['cols'] = $this->value('cols', $fieldXML);
649 $field['sqlType'] = $field['phpType'] = $type;
650 $field['crmType'] = 'CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME';
654 // need this case since some versions of mysql do not have boolean as a valid column type and hence it
655 // is changed to tinyint. hopefully after 2 yrs this case can be removed.
656 $field['sqlType'] = 'tinyint';
657 $field['phpType'] = $type;
658 $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type);
662 $length = $fieldXML->length ?
$fieldXML->length
: '20,2';
663 $field['sqlType'] = 'decimal(' . $length . ')';
664 $field['phpType'] = 'float';
665 $field['crmType'] = 'CRM_Utils_Type::T_MONEY';
669 $field['sqlType'] = 'double';
670 $field['phpType'] = 'float';
671 $field['crmType'] = 'CRM_Utils_Type::T_FLOAT';
675 $field['sqlType'] = $field['phpType'] = $type;
676 if ($type == 'int unsigned') {
677 $field['crmType'] = 'CRM_Utils_Type::T_INT';
680 $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type);
685 $field['required'] = $this->value('required', $fieldXML);
686 $field['comment'] = $this->value('comment', $fieldXML);
687 $field['default'] = $this->value('default', $fieldXML);
688 $field['import'] = $this->value('import', $fieldXML);
689 if ($this->value('export', $fieldXML)) {
690 $field['export'] = $this->value('export', $fieldXML);
693 $field['export'] = $this->value('import', $fieldXML);
695 $field['rule'] = $this->value('rule', $fieldXML);
696 $field['title'] = $this->value('title', $fieldXML);
697 if (!$field['title']) {
698 $field['title'] = $this->composeTitle($name);
700 $field['headerPattern'] = $this->value('headerPattern', $fieldXML);
701 $field['dataPattern'] = $this->value('dataPattern', $fieldXML);
702 $field['uniqueName'] = $this->value('uniqueName', $fieldXML);
703 $field['pseudoconstant'] = $this->value('pseudoconstant', $fieldXML);
704 if(!empty($fieldXML->pseudoconstant
)){
705 //ok this is a bit long-winded but it gets there & is consistent with above approach
706 $field['pseudoconstant'] = array();
707 $validOptions = array('name', 'optionGroupName', 'table', 'keyColumn', 'labelColumn','class');
708 foreach ($validOptions as $pseudoOption){
709 if(!empty($fieldXML->pseudoconstant
->$pseudoOption)){
710 $field['pseudoconstant'][$pseudoOption] = $this->value($pseudoOption, $fieldXML->pseudoconstant
);
714 $fields[$name] = &$field;
717 function composeTitle($name) {
718 $names = explode('_', strtolower($name));
720 for ($i = 0; $i < count($names); $i++
) {
721 if ($names[$i] === 'id' ||
$names[$i] === 'is') {
722 // id's do not get titles
726 if ($names[$i] === 'im') {
730 $names[$i] = ucfirst(trim($names[$i]));
733 $title = $title . ' ' . $names[$i];
738 function getPrimaryKey(&$primaryXML, &$fields, &$table) {
739 $name = trim((string ) $primaryXML->name
);
741 /** need to make sure there is a field of type name */
742 if (!array_key_exists($name, $fields)) {
743 echo "primary key $name in $table->name does not have a field definition, ignoring\n";
747 // set the autoincrement property of the field
748 $auto = $this->value('autoincrement', $primaryXML);
749 $fields[$name]['autoincrement'] = $auto;
752 'autoincrement' => $auto,
754 $table['primaryKey'] = &$primaryKey;
757 function getIndex(&$indexXML, &$fields, &$indices) {
758 //echo "\n\n*******************************************************\n";
759 //echo "entering getIndex\n";
762 // empty index name is fine
763 $indexName = trim((string)$indexXML->name
);
764 $index['name'] = $indexName;
765 $index['field'] = array();
768 foreach ($indexXML->fieldName
as $v) {
769 $fieldName = (string)($v);
770 $length = (string)($v['length']);
771 if (strlen($length) > 0) {
772 $fieldName = "$fieldName($length)";
774 $index['field'][] = $fieldName;
777 $index['localizable'] = FALSE;
778 foreach ($index['field'] as $fieldName) {
779 if (isset($fields[$fieldName]) and $fields[$fieldName]['localizable']) {
780 $index['localizable'] = TRUE;
785 // check for unique index
786 if ($this->value('unique', $indexXML)) {
787 $index['unique'] = TRUE;
790 //echo "\$index = \n";
793 // field array cannot be empty
794 if (empty($index['field'])) {
795 echo "No fields defined for index $indexName\n";
799 // all fieldnames have to be defined and should exist in schema.
800 foreach ($index['field'] as $fieldName) {
802 echo "Invalid field defination for index $indexName\n";
805 $parenOffset = strpos($fieldName, '(');
806 if ($parenOffset > 0) {
807 $fieldName = substr($fieldName, 0, $parenOffset);
809 if (!array_key_exists($fieldName, $fields)) {
810 echo "Table does not contain $fieldName\n";
812 CRM_GenCode_Util_File
::removeDir($this->compileDir
);
816 $indices[$indexName] = &$index;
819 function getForeignKey(&$foreignXML, &$fields, &$foreignKeys, &$currentTableName) {
820 $name = trim((string ) $foreignXML->name
);
822 /** need to make sure there is a field of type name */
823 if (!array_key_exists($name, $fields)) {
824 echo "foreign $name in $currentTableName does not have a field definition, ignoring\n";
828 /** need to check for existence of table and key **/
829 $table = trim($this->value('table', $foreignXML));
833 'uniqName' => "FK_{$currentTableName}_{$name}",
834 'key' => trim($this->value('key', $foreignXML)),
835 'import' => $this->value('import', $foreignXML, FALSE),
836 'export' => $this->value('import', $foreignXML, FALSE),
837 // we do this matching in a seperate phase (resolveForeignKeys)
839 'onDelete' => $this->value('onDelete', $foreignXML, FALSE),
841 $foreignKeys[$name] = &$foreignKey;
844 protected function value($key, &$object, $default = NULL) {
845 if (isset($object->$key)) {
846 return (string ) $object->$key;
851 protected function checkAndAppend(&$attributes, &$object, $name, $pre = NULL, $post = NULL) {
852 if (!isset($object->$name)) {
856 $value = $pre . trim($object->$name) . $post;
857 $this->append($attributes, ' ', trim($value));
860 protected function append(&$str, $delim, $name) {
865 if (is_array($name)) {
866 foreach ($name as $n) {
883 $str .= $delim . $name;
889 * Sets the size property of a textfield
890 * See constants defined in CRM_Utils_Type for possible values
892 protected function getSize($fieldXML) {
893 // Extract from <size> tag if supplied
894 if ($this->value('size', $fieldXML)) {
895 $const = 'CRM_Utils_Type::' . strtoupper($fieldXML->size
);
896 if (defined($const)) {
900 // Infer from <length> tag if <size> was not explicitly set or was invalid
902 // This map is slightly different from CRM_Core_Form_Renderer::$_sizeMapper
903 // Because we usually want fields to render as smaller than their maxlength
913 foreach ($sizes as $length => $name) {
914 if ($fieldXML->length
<= $length) {
915 return "CRM_Utils_Type::$name";
918 return 'CRM_Utils_Type::HUGE';