1: <?php
2: require(__QCUBED_CORE__ . '/codegen/QSqlColumn.class.php');
3: require(__QCUBED_CORE__ . '/codegen/QIndex.class.php');
4: require(__QCUBED_CORE__ . '/codegen/QManyToManyReference.class.php');
5: require(__QCUBED_CORE__ . '/codegen/QReference.class.php');
6: require(__QCUBED_CORE__ . '/codegen/QReverseReference.class.php');
7: require(__QCUBED_CORE__ . '/codegen/QSqlTable.class.php');
8: require(__QCUBED_CORE__ . '/codegen/QTypeTable.class.php');
9: require(__QCUBED_CORE__ . '/codegen/QModelConnectorOptions.class.php');
10:
11: 12: 13:
14: class QDatabaseCodeGen extends QCodeGen {
15: public $objSettingsXml;
16:
17:
18:
19: protected $objTableArray;
20: protected $strExcludedTableArray;
21: protected $objTypeTableArray;
22: protected $strAssociationTableNameArray;
23:
24: protected $objDb;
25:
26: protected $intDatabaseIndex;
27:
28: protected $strCommentConnectorLabelDelimiter;
29:
30:
31: protected $strTypeTableSuffixArray;
32: protected $intTypeTableSuffixLengthArray;
33: protected $strAssociationTableSuffix;
34: protected $intAssociationTableSuffixLength;
35:
36:
37: protected $strStripTablePrefix;
38: protected $intStripTablePrefixLength;
39:
40:
41: protected $strExcludePattern;
42: protected $strExcludeListArray;
43:
44:
45: protected $strIncludePattern;
46: protected $strIncludeListArray;
47:
48:
49: protected $strAssociatedObjectPrefix;
50: protected $strAssociatedObjectSuffix;
51:
52:
53: protected $blnManualQuerySupport = false;
54:
55:
56: protected $strRelationships;
57: protected $blnRelationshipsIgnoreCase;
58:
59: protected $strRelationshipsScriptPath;
60: protected $strRelationshipsScriptFormat;
61: protected $blnRelationshipsScriptIgnoreCase;
62:
63: protected $strRelationshipLinesQcubed = array();
64: protected $strRelationshipLinesSql = array();
65:
66:
67: protected $strPatternTableName = '[[:alpha:]_][[:alnum:]_]*';
68: protected $strPatternColumnName = '[[:alpha:]_][[:alnum:]_]*';
69: protected $strPatternKeyName = '[[:alpha:]_][[:alnum:]_]*';
70:
71: protected $blnGenerateControlId;
72: protected $objModelConnectorOptions;
73: protected $blnAutoInitialize;
74:
75: 76: 77: 78: 79:
80: public function GetTable($strTableName) {
81: $strTableName = strtolower($strTableName);
82: if (array_key_exists($strTableName, $this->objTableArray))
83: return $this->objTableArray[$strTableName];
84: if (array_key_exists($strTableName, $this->objTypeTableArray))
85: return $this->objTypeTableArray[$strTableName];;
86: throw new QCallerException(sprintf('Table does not exist or does not have a defined Primary Key: %s', $strTableName));
87: }
88:
89: public function GetColumn($strTableName, $strColumnName) {
90: try {
91: $objTable = $this->GetTable($strTableName);
92: } catch (QCallerException $objExc) {
93: $objExc->IncrementOffset();
94: throw $objExc;
95: }
96: $strColumnName = strtolower($strColumnName);
97: if (array_key_exists($strColumnName, $objTable->ColumnArray))
98: return $objTable->ColumnArray[$strColumnName];
99: throw new QCallerException(sprintf('Column does not exist in %s: %s', $strTableName, $strColumnName));
100: }
101:
102: 103: 104: 105: 106: 107: 108: 109:
110: public function ValidateTableColumn($strTableName, $strColumnName) {
111: $strTableName = trim(strtolower($strTableName));
112: $strColumnName = trim(strtolower($strColumnName));
113:
114: if (array_key_exists($strTableName, $this->objTableArray))
115: $strTableName = $this->objTableArray[$strTableName]->Name;
116: else if (array_key_exists($strTableName, $this->objTypeTableArray))
117: $strTableName = $this->objTypeTableArray[$strTableName]->Name;
118: else if (array_key_exists($strTableName, $this->strAssociationTableNameArray))
119: $strTableName = $this->strAssociationTableNameArray[$strTableName];
120: else
121: return false;
122:
123: $objFieldArray = $this->objDb->GetFieldsForTable($strTableName);
124:
125: foreach ($objFieldArray as $objField) {
126: if (trim(strtolower($objField->Name)) == $strColumnName)
127: return true;
128: }
129:
130: return false;
131: }
132:
133: public function GetTitle() {
134: if (!QApplication::$Database) {
135: return '';
136: }
137:
138: if (array_key_exists($this->intDatabaseIndex, QApplication::$Database)) {
139: $objDatabase = QApplication::$Database[$this->intDatabaseIndex];
140: return sprintf('Database Index #%s (%s / %s / %s)', $this->intDatabaseIndex, $objDatabase->Adapter, $objDatabase->Server, $objDatabase->Database);
141: } else
142: return sprintf('Database Index #%s (N/A)', $this->intDatabaseIndex);
143: }
144:
145: public function GetConfigXml() {
146: $strCrLf = "\r\n";
147: $strToReturn = sprintf(' <database index="%s">%s', $this->intDatabaseIndex, $strCrLf);
148: $strToReturn .= sprintf(' <className prefix="%s" suffix="%s"/>%s', $this->strClassPrefix, $this->strClassSuffix, $strCrLf);
149: $strToReturn .= sprintf(' <associatedObjectName prefix="%s" suffix="%s"/>%s', $this->strAssociatedObjectPrefix, $this->strAssociatedObjectSuffix, $strCrLf);
150: $strToReturn .= sprintf(' <typeTableIdentifier suffix="%s"/>%s', implode(',', $this->strTypeTableSuffixArray), $strCrLf);
151: $strToReturn .= sprintf(' <associationTableIdentifier suffix="%s"/>%s', $this->strAssociationTableSuffix, $strCrLf);
152: $strToReturn .= sprintf(' <stripFromTableName prefix="%s"/>%s', $this->strStripTablePrefix, $strCrLf);
153: $strToReturn .= sprintf(' <excludeTables pattern="%s" list="%s"/>%s', $this->strExcludePattern, implode(',', $this->strExcludeListArray), $strCrLf);
154: $strToReturn .= sprintf(' <includeTables pattern="%s" list="%s"/>%s', $this->strIncludePattern, implode(',', $this->strIncludeListArray), $strCrLf);
155: $strToReturn .= sprintf(' <manualQuery support="%s"/>%s', ($this->blnManualQuerySupport) ? 'true' : 'false', $strCrLf);
156: $strToReturn .= sprintf(' <relationships>%s', $strCrLf);
157: if ($this->strRelationships)
158: $strToReturn .= sprintf(' %s%s', $this->strRelationships, $strCrLf);
159: $strToReturn .= sprintf(' </relationships>%s', $strCrLf);
160: $strToReturn .= sprintf(' <relationshipsScript filepath="%s" format="%s"/>%s', $this->strRelationshipsScriptPath, $this->strRelationshipsScriptFormat, $strCrLf);
161: $strToReturn .= sprintf(' </database>%s', $strCrLf);
162: return $strToReturn;
163: }
164:
165: public function GetReportLabel() {
166:
167: $intTotalTableCount = count($this->objTableArray) + count($this->objTypeTableArray);
168: if ($intTotalTableCount == 0)
169: $strReportLabel = 'There were no tables available to attempt code generation.';
170: else if ($intTotalTableCount == 1)
171: $strReportLabel = 'There was 1 table available to attempt code generation:';
172: else
173: $strReportLabel = 'There were ' . $intTotalTableCount . ' tables available to attempt code generation:';
174:
175: return $strReportLabel;
176: }
177:
178: public function GenerateAll() {
179: $strReport = '';
180:
181:
182: if ($this->objTableArray) foreach ($this->objTableArray as $objTable) {
183: if ($this->GenerateTable($objTable)) {
184: $intCount = $objTable->ReferenceCount;
185: if ($intCount == 0)
186: $strCount = '(with no relationships)';
187: else if ($intCount == 1)
188: $strCount = '(with 1 relationship)';
189: else
190: $strCount = sprintf('(with %s relationships)', $intCount);
191: $strReport .= sprintf("Successfully generated DB ORM Class: %s %s\r\n", $objTable->ClassName, $strCount);
192: } else
193: $strReport .= sprintf("FAILED to generate DB ORM Class: %s\r\n", $objTable->ClassName);
194: }
195:
196:
197: if ($this->objTypeTableArray) foreach ($this->objTypeTableArray as $objTypeTable) {
198: if ($this->GenerateTypeTable($objTypeTable))
199: $strReport .= sprintf("Successfully generated DB Type Class: %s\n", $objTypeTable->ClassName);
200: else
201: $strReport .= sprintf("FAILED to generate DB Type class: %s\n", $objTypeTable->ClassName);
202: }
203:
204: return $strReport;
205: }
206:
207: public static function GenerateAggregateHelper($objCodeGenArray) {
208: $strToReturn = array();
209:
210: if (count($objCodeGenArray)) {
211:
212: $objTableArray = array();
213: foreach ($objCodeGenArray as $objCodeGen) {
214: $objCurrentTableArray = $objCodeGen->TableArray;
215: foreach ($objCurrentTableArray as $objTable)
216: $objTableArray[$objTable->ClassName] = $objTable;
217: }
218:
219: $mixArgumentArray = array('objTableArray' => $objTableArray);
220: if ($objCodeGenArray[0]->GenerateFiles('aggregate_db_orm', $mixArgumentArray))
221: $strToReturn[] = 'Successfully generated Aggregate DB ORM file(s)';
222: else
223: $strToReturn[] = 'FAILED to generate Aggregate DB ORM file(s)';
224:
225:
226: $objTableArray = array();
227: foreach ($objCodeGenArray as $objCodeGen) {
228: $objCurrentTableArray = $objCodeGen->TypeTableArray;
229: foreach ($objCurrentTableArray as $objTable)
230: $objTableArray[$objTable->ClassName] = $objTable;
231: }
232:
233: $mixArgumentArray = array('objTableArray' => $objTableArray);
234: if ($objCodeGenArray[0]->GenerateFiles('aggregate_db_type', $mixArgumentArray))
235: $strToReturn[] = 'Successfully generated Aggregate DB Type file(s)';
236: else
237: $strToReturn[] = 'FAILED to generate Aggregate DB Type file(s)';
238: }
239:
240: return $strToReturn;
241: }
242:
243: public function __construct($objSettingsXml) {
244: parent::__construct($objSettingsXml);
245:
246:
247:
248:
249: $this->strAssociationTableNameArray = array();
250: $this->objTableArray = array();
251: $this->objTypeTableArray = array();
252: $this->strExcludedTableArray = array();
253:
254:
255: $this->intDatabaseIndex = QCodeGen::LookupSetting($objSettingsXml, null, 'index', QType::Integer);
256:
257:
258: $this->strClassPrefix = QCodeGen::LookupSetting($objSettingsXml, 'className', 'prefix');
259: $this->strClassSuffix = QCodeGen::LookupSetting($objSettingsXml, 'className', 'suffix');
260: $this->strAssociatedObjectPrefix = QCodeGen::LookupSetting($objSettingsXml, 'associatedObjectName', 'prefix');
261: $this->strAssociatedObjectSuffix = QCodeGen::LookupSetting($objSettingsXml, 'associatedObjectName', 'suffix');
262:
263:
264: $strTypeTableSuffixList = QCodeGen::LookupSetting($objSettingsXml, 'typeTableIdentifier', 'suffix');
265: $strTypeTableSuffixArray = explode(',', $strTypeTableSuffixList);
266: foreach ($strTypeTableSuffixArray as $strTypeTableSuffix) {
267: $this->strTypeTableSuffixArray[] = trim($strTypeTableSuffix);
268: $this->intTypeTableSuffixLengthArray[] = strlen(trim($strTypeTableSuffix));
269: }
270: $this->strAssociationTableSuffix = QCodeGen::LookupSetting($objSettingsXml, 'associationTableIdentifier', 'suffix');
271: $this->intAssociationTableSuffixLength = strlen($this->strAssociationTableSuffix);
272:
273:
274: $this->strStripTablePrefix = QCodeGen::LookupSetting($objSettingsXml, 'stripFromTableName', 'prefix');
275: $this->intStripTablePrefixLength = strlen($this->strStripTablePrefix);
276:
277:
278: $this->strExcludePattern = QCodeGen::LookupSetting($objSettingsXml, 'excludeTables', 'pattern');
279: $strExcludeList = QCodeGen::LookupSetting($objSettingsXml, 'excludeTables', 'list');
280: $this->strExcludeListArray = explode(',',$strExcludeList);
281: array_walk($this->strExcludeListArray, 'array_trim');
282:
283:
284: $this->strIncludePattern = QCodeGen::LookupSetting($objSettingsXml, 'includeTables', 'pattern');
285: $strIncludeList = QCodeGen::LookupSetting($objSettingsXml, 'includeTables', 'list');
286: $this->strIncludeListArray = explode(',',$strIncludeList);
287: array_walk($this->strIncludeListArray, 'array_trim');
288:
289:
290: $this->blnManualQuerySupport = QCodeGen::LookupSetting($objSettingsXml, 'manualQuery', 'support', QType::Boolean);
291:
292:
293: $this->strRelationships = QCodeGen::LookupSetting($objSettingsXml, 'relationships');
294: $this->strRelationshipsScriptPath = QCodeGen::LookupSetting($objSettingsXml, 'relationshipsScript', 'filepath');
295: $this->strRelationshipsScriptFormat = QCodeGen::LookupSetting($objSettingsXml, 'relationshipsScript', 'format');
296:
297:
298: $this->strCommentConnectorLabelDelimiter = QCodeGen::LookupSetting($objSettingsXml, 'columnCommentForModelConnector', 'delimiter');
299:
300:
301: if (!$this->intDatabaseIndex)
302: $this->strErrors .= "CodeGen Settings XML Fatal Error: databaseIndex was invalid or not set\r\n";
303:
304:
305: if ($this->strRelationships) {
306: $strLines = explode("\n", strtolower($this->strRelationships));
307: if ($strLines) foreach ($strLines as $strLine) {
308: $strLine = trim($strLine);
309:
310: if (($strLine) &&
311: (strlen($strLine) > 2) &&
312: (substr($strLine, 0, 2) != '//') &&
313: (substr($strLine, 0, 2) != '--') &&
314: (substr($strLine, 0, 1) != '#')) {
315: $this->strRelationshipLinesQcubed[$strLine] = $strLine;
316: }
317: }
318: }
319:
320: if ($this->strRelationshipsScriptPath) {
321: if (!file_exists($this->strRelationshipsScriptPath))
322: $this->strErrors .= sprintf("CodeGen Settings XML Fatal Error: relationshipsScript filepath \"%s\" does not exist\r\n", $this->strRelationshipsScriptPath);
323: else {
324: $strScript = strtolower(trim(file_get_contents($this->strRelationshipsScriptPath)));
325: switch (strtolower($this->strRelationshipsScriptFormat)) {
326: case 'qcubed':
327: $strLines = explode("\n", $strScript);
328: if ($strLines) foreach ($strLines as $strLine) {
329: $strLine = trim($strLine);
330:
331: if (($strLine) &&
332: (strlen($strLine) > 2) &&
333: (substr($strLine, 0, 2) != '//') &&
334: (substr($strLine, 0, 2) != '--') &&
335: (substr($strLine, 0, 1) != '#')) {
336: $this->strRelationshipLinesQcubed[$strLine] = $strLine;
337: }
338: }
339: break;
340:
341: case 'sql':
342:
343: $strCommands = explode(';', $strScript);
344: if ($strCommands) foreach ($strCommands as $strCommand) {
345: $strCommand = trim($strCommand);
346:
347: if ($strCommand) {
348:
349: $strLines = explode("\n", $strCommand);
350: $strCommand = '';
351: foreach ($strLines as $strLine) {
352: $strLine = trim($strLine);
353: if (($strLine) &&
354: (substr($strLine, 0, 2) != '//') &&
355: (substr($strLine, 0, 2) != '--') &&
356: (substr($strLine, 0, 1) != '#')) {
357: $strLine = str_replace(' ', ' ', $strLine);
358: $strLine = str_replace(' ', ' ', $strLine);
359: $strLine = str_replace(' ', ' ', $strLine);
360: $strLine = str_replace(' ', ' ', $strLine);
361: $strLine = str_replace(' ', ' ', $strLine);
362: $strLine = str_replace(' ', ' ', $strLine);
363: $strLine = str_replace(' ', ' ', $strLine);
364: $strLine = str_replace(' ', ' ', $strLine);
365: $strLine = str_replace(' ', ' ', $strLine);
366: $strLine = str_replace(' ', ' ', $strLine);
367: $strLine = str_replace(' ', ' ', $strLine);
368: $strLine = str_replace(' ', ' ', $strLine);
369:
370: $strCommand .= $strLine . ' ';
371: }
372: }
373:
374: $strCommand = trim($strCommand);
375: if ((strpos($strCommand, 'alter table') === 0) &&
376: (strpos($strCommand, 'foreign key') !== false))
377: $this->strRelationshipLinesSql[$strCommand] = $strCommand;
378: }
379: }
380: break;
381:
382: default:
383: $this->strErrors .= sprintf("CodeGen Settings XML Fatal Error: relationshipsScript format \"%s\" is invalid (must be either \"qcubed\" or \"sql\")\r\n", $this->strRelationshipsScriptFormat);
384: break;
385: }
386: }
387: }
388:
389: $this->blnGenerateControlId = QCodeGen::LookupSetting($objSettingsXml, 'generateControlId', 'support', QType::Boolean);
390: $this->objModelConnectorOptions = new QModelConnectorOptions();
391:
392: $this->blnAutoInitialize = QCodeGen::LookupSetting($objSettingsXml, 'createOptions', 'autoInitialize', QType::Boolean);
393:
394: if ($this->strErrors)
395: return;
396:
397: $this->AnalyzeDatabase();
398: }
399:
400: protected function AnalyzeDatabase() {
401: if (!QApplication::$Database) {
402: $this->strErrors = 'FATAL ERROR: No databases are listed in the configuration file.';
403: return;
404: }
405:
406:
407: if (array_key_exists($this->intDatabaseIndex, QApplication::$Database))
408: $this->objDb = QApplication::$Database[$this->intDatabaseIndex];
409:
410:
411: if (!$this->objDb) {
412: $this->strErrors = 'FATAL ERROR: No database configured at index ' . $this->intDatabaseIndex . '. Check your configuration file.';
413: return;
414: }
415:
416:
417: if ($this->objDb->EnableProfiling) {
418: $this->strErrors = 'FATAL ERROR: Code generator cannot analyze the database at index ' . $this->intDatabaseIndex . ' while DB Profiling is enabled.';
419: return;
420: }
421:
422:
423: $strTableArray = $this->objDb->GetTables();
424:
425:
426:
427: if ($strTableArray) {
428: foreach ($strTableArray as $strTableName) {
429:
430:
431:
432: if (in_array($strTableName, $this->strExcludeListArray) ||
433: (strlen($this->strExcludePattern) > 0 && preg_match(":" . $this->strExcludePattern . ":i", $strTableName))
434: ) {
435:
436:
437:
438: if (in_array($strTableName, $this->strIncludeListArray) ||
439: (strlen($this->strIncludePattern) > 0 && preg_match(":" . $this->strIncludePattern . ":i", $strTableName))
440: ) {
441:
442:
443: } else {
444:
445: $this->strExcludedTableArray[strtolower($strTableName)] = true;
446:
447:
448: continue;
449: }
450: }
451:
452:
453: foreach (QCodeGen::$CodeGenArray as $objCodeGen) {
454: if ($objCodeGen instanceof QDatabaseCodeGen) {
455: foreach ($objCodeGen->objTableArray as $objPossibleDuplicate)
456: if (strtolower($objPossibleDuplicate->Name) == strtolower($strTableName)) {
457: $this->strErrors .= 'Duplicate Table Name Used: ' . $strTableName . "\r\n";
458: }
459: }
460: }
461:
462:
463:
464: $blnIsTypeTable = false;
465: foreach ($this->intTypeTableSuffixLengthArray as $intIndex => $intTypeTableSuffixLength) {
466: if (($intTypeTableSuffixLength) &&
467: (strlen($strTableName) > $intTypeTableSuffixLength) &&
468: (substr($strTableName, strlen($strTableName) - $intTypeTableSuffixLength) == $this->strTypeTableSuffixArray[$intIndex])
469: ) {
470:
471: $blnIsTypeTable = true;
472:
473: $objTypeTable = new QTypeTable($strTableName);
474: $this->objTypeTableArray[strtolower($strTableName)] = $objTypeTable;
475:
476: break;
477:
478: }
479: }
480: if (!$blnIsTypeTable) {
481:
482: if (($this->intAssociationTableSuffixLength) &&
483: (strlen($strTableName) > $this->intAssociationTableSuffixLength) &&
484: (substr($strTableName, strlen($strTableName) - $this->intAssociationTableSuffixLength) == $this->strAssociationTableSuffix)
485: ) {
486:
487: $this->strAssociationTableNameArray[strtolower($strTableName)] = $strTableName;
488:
489:
490: } else {
491:
492: $objTable = new QSqlTable($strTableName);
493: $this->objTableArray[strtolower($strTableName)] = $objTable;
494:
495: }
496: }
497: }
498: }
499:
500:
501:
502: if ($this->objTypeTableArray) foreach ($this->objTypeTableArray as $objTypeTable)
503: $this->AnalyzeTypeTable($objTypeTable);
504:
505:
506: if ($this->objTableArray) foreach ($this->objTableArray as $objTable)
507: $this->AnalyzeTable($objTable);
508:
509:
510: if ($this->strAssociationTableNameArray) foreach ($this->strAssociationTableNameArray as $strAssociationTableName)
511: $this->AnalyzeAssociationTable($strAssociationTableName);
512:
513:
514: if ($this->objTableArray) foreach ($this->objTableArray as $objTable)
515: if ($objTable->ColumnArray) foreach ($objTable->ColumnArray as $objColumn)
516: if ($objColumn->Reference && !$objColumn->Reference->IsType) {
517: $objReference = $objColumn->Reference;
518:
519: $objReferencedTable = $this->GetTable($objReference->Table);
520: $objReferencedColumn = $objReferencedTable->ColumnArray[strtolower($objReference->Column)];
521:
522:
523: if (!$objReferencedColumn->PrimaryKey) {
524: $this->strErrors .= sprintf("Warning: Invalid Relationship created in %s class (for foreign key \"%s\") -- column \"%s\" is not the single-column primary key for the referenced \"%s\" table\r\n",
525: $objReferencedTable->ClassName, $objReference->KeyName, $objReferencedColumn->Name, $objReferencedTable->Name);
526: } else if (count($objReferencedTable->PrimaryKeyColumnArray) != 1) {
527: $this->strErrors .= sprintf("Warning: Invalid Relationship created in %s class (for foreign key \"%s\") -- column \"%s\" is not the single-column primary key for the referenced \"%s\" table\r\n",
528: $objReferencedTable->ClassName, $objReference->KeyName, $objReferencedColumn->Name, $objReferencedTable->Name);
529: }
530: }
531: }
532:
533: protected function ListOfColumnsFromTable(QSqlTable $objTable) {
534: $strArray = array();
535: $objColumnArray = $objTable->ColumnArray;
536: if ($objColumnArray) foreach ($objColumnArray as $objColumn)
537: array_push($strArray, $objColumn->Name);
538: return implode(', ', $strArray);
539: }
540:
541: protected function GetColumnArray(QSqlTable $objTable, $strColumnNameArray) {
542: $objToReturn = array();
543:
544: if ($strColumnNameArray) foreach ($strColumnNameArray as $strColumnName) {
545: array_push($objToReturn, $objTable->ColumnArray[strtolower($strColumnName)]);
546: }
547:
548: return $objToReturn;
549: }
550:
551: public function GenerateTable(QSqlTable $objTable) {
552:
553: $mixArgumentArray = array('objTable' => $objTable);
554: return $this->GenerateFiles('db_orm', $mixArgumentArray);
555: }
556:
557: public function GenerateTypeTable(QTypeTable $objTypeTable) {
558:
559: $mixArgumentArray = array('objTypeTable' => $objTypeTable);
560: return $this->GenerateFiles('db_type', $mixArgumentArray);
561: }
562:
563: protected function AnalyzeAssociationTable($strTableName) {
564: $objFieldArray = $this->objDb->GetFieldsForTable($strTableName);
565:
566:
567: if (count($objFieldArray) != 2) {
568: $this->strErrors .= sprintf("AssociationTable %s does not have exactly 2 columns.\n",
569: $strTableName);
570: return;
571: }
572:
573: if ((!$objFieldArray[0]->NotNull) ||
574: (!$objFieldArray[1]->NotNull)) {
575: $this->strErrors .= sprintf("AssociationTable %s's two columns must both be not null",
576: $strTableName);
577: return;
578: }
579:
580: if (((!$objFieldArray[0]->PrimaryKey) &&
581: ($objFieldArray[1]->PrimaryKey)) ||
582: (($objFieldArray[0]->PrimaryKey) &&
583: (!$objFieldArray[1]->PrimaryKey))) {
584: $this->strErrors .= sprintf("AssociationTable %s only support two-column composite Primary Keys.\n",
585: $strTableName);
586: return;
587: }
588:
589: $objForeignKeyArray = $this->objDb->GetForeignKeysForTable($strTableName);
590:
591:
592: $objForeignKeyArray = $this->GetForeignKeysFromRelationshipsScript($strTableName, $objForeignKeyArray);
593:
594: if (count($objForeignKeyArray) != 2) {
595: $this->strErrors .= sprintf("AssociationTable %s does not have exactly 2 foreign keys. Code Gen analysis found %s.\n",
596: $strTableName, count($objForeignKeyArray));
597: return;
598: }
599:
600:
601: $objManyToManyReferenceArray[0] = new QManyToManyReference();
602: $objManyToManyReferenceArray[1] = new QManyToManyReference();
603:
604:
605: if (array_key_exists($objForeignKeyArray[0]->ReferenceTableName, $this->strExcludedTableArray) ||
606: array_key_exists($objForeignKeyArray[1]->ReferenceTableName, $this->strExcludedTableArray))
607: return;
608:
609:
610: if ($objForeignKeyArray[0]->ReferenceTableName == $objForeignKeyArray[1]->ReferenceTableName) {
611:
612: $strGraphPrefixArray = $this->CalculateGraphPrefixArray($objForeignKeyArray);
613: } else {
614: $strGraphPrefixArray = array('', '');
615: }
616:
617:
618: for ($intIndex = 0; $intIndex < 2; $intIndex++) {
619: $objManyToManyReference = $objManyToManyReferenceArray[$intIndex];
620:
621: $objForeignKey = $objForeignKeyArray[$intIndex];
622: $objOppositeForeignKey = $objForeignKeyArray[($intIndex == 0) ? 1 : 0];
623:
624:
625: if (count($objForeignKey->ColumnNameArray) != 1) {
626: $this->strErrors .= sprintf("AssoiationTable %s has multi-column foreign keys.\n",
627: $strTableName);
628: return;
629: }
630:
631: $objManyToManyReference->KeyName = $objForeignKey->KeyName;
632: $objManyToManyReference->Table = $strTableName;
633: $objManyToManyReference->Column = $objForeignKey->ColumnNameArray[0];
634: $objManyToManyReference->PropertyName = $this->ModelColumnPropertyName($objManyToManyReference->Column);
635: $objManyToManyReference->OppositeColumn = $objOppositeForeignKey->ColumnNameArray[0];
636: $objManyToManyReference->AssociatedTable = $objOppositeForeignKey->ReferenceTableName;
637:
638:
639:
640:
641:
642:
643: $objTable = $this->GetTable($objManyToManyReference->AssociatedTable);
644: $objOppositeColumn = clone($objTable->PrimaryKeyColumnArray[0]);
645: $objOppositeColumn->Name = $objManyToManyReference->OppositeColumn;
646: $objManyToManyReference->OppositeVariableName = $this->ModelColumnVariableName($objOppositeColumn);
647: $objManyToManyReference->OppositePropertyName = $this->ModelColumnPropertyName($objOppositeColumn->Name);
648: $objManyToManyReference->OppositeVariableType = $objOppositeColumn->VariableType;
649: $objManyToManyReference->OppositeDbType = $objOppositeColumn->DbType;
650:
651: $objManyToManyReference->VariableName = $this->ModelReverseReferenceVariableName($objOppositeForeignKey->ReferenceTableName);
652: $objManyToManyReference->VariableType = $this->ModelReverseReferenceVariableType($objOppositeForeignKey->ReferenceTableName);
653:
654: $objManyToManyReference->ObjectDescription = $strGraphPrefixArray[$intIndex] . $this->CalculateObjectDescriptionForAssociation($strTableName, $objForeignKey->ReferenceTableName, $objOppositeForeignKey->ReferenceTableName, false);
655: $objManyToManyReference->ObjectDescriptionPlural = $strGraphPrefixArray[$intIndex] . $this->CalculateObjectDescriptionForAssociation($strTableName, $objForeignKey->ReferenceTableName, $objOppositeForeignKey->ReferenceTableName, true);
656:
657: $objManyToManyReference->OppositeObjectDescription = $strGraphPrefixArray[($intIndex == 0) ? 1 : 0] . $this->CalculateObjectDescriptionForAssociation($strTableName, $objOppositeForeignKey->ReferenceTableName, $objForeignKey->ReferenceTableName, false);
658: $objManyToManyReference->IsTypeAssociation = ($objTable instanceof QTypeTable);
659: $objManyToManyReference->Options = $this->objModelConnectorOptions->GetOptions($this->ModelClassName($objForeignKey->ReferenceTableName), $objManyToManyReference->ObjectDescription);
660:
661: }
662:
663:
664:
665: $objColumnArray = array();
666: foreach ($objFieldArray as $objField) {
667: if (($objField->Name != $objManyToManyReferenceArray[0]->Column) &&
668: ($objField->Name != $objManyToManyReferenceArray[1]->Column)) {
669: $objColumn = $this->AnalyzeTableColumn($objField, null);
670: if ($objColumn) {
671: $objColumnArray[strtolower($objColumn->Name)] = $objColumn;
672: }
673: }
674: }
675: $objManyToManyReferenceArray[0]->ColumnArray = $objColumnArray;
676: $objManyToManyReferenceArray[1]->ColumnArray = $objColumnArray;
677:
678:
679: for ($intIndex = 0; $intIndex < 2; $intIndex++) {
680: $objManyToManyReference = $objManyToManyReferenceArray[$intIndex];
681: $strTableWithReference = $objManyToManyReferenceArray[($intIndex == 0) ? 1 : 0]->AssociatedTable;
682:
683: $objTable = $this->GetTable($strTableWithReference);
684: $objArray = $objTable->ManyToManyReferenceArray;
685: array_push($objArray, $objManyToManyReference);
686: $objTable->ManyToManyReferenceArray = $objArray;
687: }
688:
689: }
690:
691: protected function AnalyzeTypeTable(QTypeTable $objTypeTable) {
692:
693: $strReservedWords = explode(',', QCodeGen::PhpReservedWords);
694: for ($intIndex = 0; $intIndex < count($strReservedWords); $intIndex++)
695: $strReservedWords[$intIndex] = strtolower(trim($strReservedWords[$intIndex]));
696:
697:
698: $strTableName = $objTypeTable->Name;
699: $objTypeTable->ClassName = $this->ModelClassName($strTableName);
700:
701:
702: $objFieldArray = $this->objDb->GetFieldsForTable($strTableName);
703:
704: if (($objFieldArray[0]->Type != QDatabaseFieldType::Integer) ||
705: (!$objFieldArray[0]->PrimaryKey)) {
706: $this->strErrors .= sprintf("TypeTable %s's first column is not a PK integer.\n",
707: $strTableName);
708: return;
709: }
710:
711: if (($objFieldArray[1]->Type != QDatabaseFieldType::VarChar) ||
712: (!$objFieldArray[1]->Unique)) {
713: $this->strErrors .= sprintf("TypeTable %s's second column is not a unique VARCHAR.\n",
714: $strTableName);
715: return;
716: }
717:
718:
719: $objResult = $this->objDb->Query(sprintf('SELECT * FROM %s', $strTableName));
720: $strNameArray = array();
721: $strTokenArray = array();
722: $strExtraPropertyArray = array();
723: $strExtraFields = array();
724: $intRowWidth = count($objFieldArray);
725: while ($objDbRow = $objResult->GetNextRow()) {
726: $strRowArray = $objDbRow->GetColumnNameArray();
727: $id = $strRowArray[0];
728: $name = $strRowArray[1];
729:
730: $strNameArray[$id] = str_replace("'", "\\'", str_replace('\\', '\\\\', $name));
731: $strTokenArray[$id] = $this->TypeTokenFromTypeName($name);
732: if ($intRowWidth > 2) {
733: $strExtraPropertyArray[$id] = array();
734: for ($i = 2; $i < $intRowWidth; $i++) {
735: $strFieldName = QCodeGen::TypeColumnPropertyName($objFieldArray[$i]->Name);
736: $strExtraFields[$i - 2] = $strFieldName;
737:
738:
739: $value = $objDbRow->GetColumn($objFieldArray[$i]->Name, $objFieldArray[$i]->Type);
740: $strExtraPropertyArray[$id][$strFieldName] = $value;
741: }
742: }
743:
744: foreach ($strReservedWords as $strReservedWord)
745: if (trim(strtolower($strTokenArray[$id])) == $strReservedWord) {
746: $this->strErrors .= sprintf("Warning: TypeTable %s contains a type name which is a reserved word: %s. Appended _ to the beginning of it.\r\n",
747: $strTableName, $strReservedWord);
748: $strTokenArray[$id] = '_' . $strTokenArray[$id];
749: }
750: if (strlen($strTokenArray[$id]) == 0) {
751: $this->strErrors .= sprintf("Warning: TypeTable %s contains an invalid type name: %s\r\n",
752: $strTableName, stripslashes($strNameArray[$id]));
753: return;
754: }
755: }
756:
757: ksort($strNameArray);
758: ksort($strTokenArray);
759:
760: $objTypeTable->NameArray = $strNameArray;
761: $objTypeTable->TokenArray = $strTokenArray;
762: $objTypeTable->ExtraFieldNamesArray = $strExtraFields;
763: $objTypeTable->ExtraPropertyArray = $strExtraPropertyArray;
764: $objTypeTable->KeyColumn = $this->AnalyzeTableColumn ($objFieldArray[0], $objTypeTable);
765: }
766:
767: protected function AnalyzeTable(QSqlTable $objTable) {
768:
769: $objTable->OwnerDbIndex = $this->intDatabaseIndex;
770: $strTableName = $objTable->Name;
771: $objTable->ClassName = $this->ModelClassName($strTableName);
772: $objTable->ClassNamePlural = $this->Pluralize($objTable->ClassName);
773:
774: $objTable->Options = $this->objModelConnectorOptions->GetOptions($objTable->ClassName, QModelConnectorOptions::TableOptionsFieldName);
775:
776:
777: $objFieldArray = $this->objDb->GetFieldsForTable($strTableName);
778:
779:
780: $objColumnArray = array();
781: if ($objFieldArray) foreach ($objFieldArray as $objField) {
782: $objColumn = $this->AnalyzeTableColumn($objField, $objTable);
783: if ($objColumn) {
784: $objColumnArray[strtolower($objColumn->Name)] = $objColumn;
785: }
786: }
787: $objTable->ColumnArray = $objColumnArray;
788:
789:
790:
791:
792:
793: $objTable->IndexArray = $this->objDb->GetIndexesForTable($objTable->Name);
794:
795:
796: $objIndexArray = array();
797:
798: $strPrimaryKeyArray = array();
799: foreach ($objColumnArray as $objColumn)
800: if ($objColumn->PrimaryKey) {
801: $objPkColumn = $objColumn;
802: array_push($strPrimaryKeyArray, $objColumn->Name);
803: }
804: if (count($strPrimaryKeyArray)) {
805: $objIndex = new QIndex();
806: $objIndex->KeyName = 'pk_' . $strTableName;
807: $objIndex->PrimaryKey = true;
808: $objIndex->Unique = true;
809: $objIndex->ColumnNameArray = $strPrimaryKeyArray;
810: array_push($objIndexArray, $objIndex);
811:
812: if (count($strPrimaryKeyArray) == 1) {
813: $objPkColumn->Unique = true;
814: $objPkColumn->Indexed = true;
815: }
816: }
817:
818:
819:
820: if ($objTable->IndexArray) foreach ($objArray = $objTable->IndexArray as $objDatabaseIndex) {
821:
822: if (count ($objDatabaseIndex->ColumnNameArray) == 0)
823: $this->strErrors .= sprintf("Index %s in table %s indexes on no columns.\n",
824: $objDatabaseIndex->KeyName, $strTableName);
825: else {
826:
827: $blnFailed = false;
828: foreach ($objArray = $objDatabaseIndex->ColumnNameArray as $strColumnName) {
829: if (array_key_exists(strtolower($strColumnName), $objTable->ColumnArray) &&
830: ($objTable->ColumnArray[strtolower($strColumnName)])) {
831:
832: } else {
833:
834: $this->strErrors .= sprintf("Index %s in table %s indexes on the column %s, which does not appear to exist.\n",
835: $objDatabaseIndex->KeyName, $strTableName, $strColumnName);
836: $blnFailed = true;
837: }
838: }
839:
840: if (!$blnFailed) {
841:
842: $blnAlreadyCreated = false;
843: foreach ($objIndexArray as $objIndex)
844: if (count($objIndex->ColumnNameArray) == count($objDatabaseIndex->ColumnNameArray))
845: if (implode(',', $objIndex->ColumnNameArray) == implode(',', $objDatabaseIndex->ColumnNameArray))
846: $blnAlreadyCreated = true;
847:
848: if (!$blnAlreadyCreated) {
849:
850: $objIndex = new QIndex();
851: $objIndex->KeyName = $objDatabaseIndex->KeyName;
852: $objIndex->PrimaryKey = $objDatabaseIndex->PrimaryKey;
853: $objIndex->Unique = $objDatabaseIndex->Unique;
854: if ($objDatabaseIndex->PrimaryKey)
855: $objIndex->Unique = true;
856: $objIndex->ColumnNameArray = $objDatabaseIndex->ColumnNameArray;
857:
858:
859: array_push($objIndexArray, $objIndex);
860:
861:
862: if (count($objDatabaseIndex->ColumnNameArray) == 1) {
863: $strColumnName = $objDatabaseIndex->ColumnNameArray[0];
864: $objColumn = $objTable->ColumnArray[strtolower($strColumnName)];
865: $objColumn->Indexed = true;
866:
867: if ($objIndex->Unique)
868: $objColumn->Unique = true;
869: }
870: }
871: }
872: }
873: }
874:
875:
876: $objTable->IndexArray = $objIndexArray;
877:
878:
879:
880:
881:
882: $objForeignKeys = $this->objDb->GetForeignKeysForTable($objTable->Name);
883:
884:
885: $objForeignKeys = $this->GetForeignKeysFromRelationshipsScript($strTableName, $objForeignKeys);
886:
887:
888: if ($objForeignKeys) foreach ($objForeignKeys as $objForeignKey) {
889:
890:
891: if (count($objForeignKey->ColumnNameArray) != 1)
892: $this->strErrors .= sprintf("Foreign Key %s in table %s keys on multiple columns. Multiple-columned FKs are not supported by the code generator.\n",
893: $objForeignKey->KeyName, $strTableName);
894: else {
895:
896: $strColumnName = $objForeignKey->ColumnNameArray[0];
897:
898: if (array_key_exists(strtolower($strColumnName), $objTable->ColumnArray) &&
899: ($objColumn = $objTable->ColumnArray[strtolower($strColumnName)])) {
900:
901:
902: $blnFound = false;
903: if ($objIndexArray = $objTable->IndexArray) foreach ($objIndexArray as $objIndex) {
904: if ((count($objIndex->ColumnNameArray) == 1) &&
905: (strtolower($objIndex->ColumnNameArray[0]) == strtolower($strColumnName)))
906: $blnFound = true;
907: }
908:
909: if (!$blnFound) {
910:
911: $objIndex = new QIndex();
912: $objIndex->KeyName = sprintf('virtualix_%s_%s', $objTable->Name, $objColumn->Name);
913: $objIndex->Unique = $objColumn->Unique;
914: $objIndex->ColumnNameArray = array($objColumn->Name);
915:
916: $objIndexArray = $objTable->IndexArray;
917: $objIndexArray[] = $objIndex;
918: $objTable->IndexArray = $objIndexArray;
919:
920: if ($objIndex->Unique)
921: $this->strWarnings .= sprintf("Notice: It is recommended that you add a single-column UNIQUE index on \"%s.%s\" for the Foreign Key %s\r\n",
922: $strTableName, $strColumnName, $objForeignKey->KeyName);
923: else
924: $this->strWarnings .= sprintf("Notice: It is recommended that you add a single-column index on \"%s.%s\" for the Foreign Key %s\r\n",
925: $strTableName, $strColumnName, $objForeignKey->KeyName);
926: }
927:
928:
929: if ((array_key_exists(strtolower($objForeignKey->ReferenceTableName), $this->objTableArray)) ||
930: (array_key_exists(strtolower($objForeignKey->ReferenceTableName), $this->objTypeTableArray))) {
931:
932:
933: $objReference = new QReference();
934:
935:
936: $objColumn = $objTable->ColumnArray[strtolower($strColumnName)];
937:
938:
939: $objReference->KeyName = $objForeignKey->KeyName;
940:
941: $strReferencedTableName = $objForeignKey->ReferenceTableName;
942:
943:
944: if (array_key_exists(strtolower($strReferencedTableName), $this->objTypeTableArray)) {
945: $objReference->IsType = true;
946: } else {
947: $objReference->IsType = false;
948: }
949:
950:
951: $objReference->Table = $strReferencedTableName;
952: $objReference->Column = $objForeignKey->ReferenceColumnNameArray[0];
953:
954:
955: $objReference->VariableType = $this->ModelClassName($strReferencedTableName);
956:
957:
958: $objReference->PropertyName = $this->ModelReferencePropertyName($objColumn->Name);
959: $objReference->VariableName = $this->ModelReferenceVariableName($objColumn->Name);
960:
961:
962: $objColumn->Reference = $objReference;
963:
964:
965: $objColumn->Options = $this->objModelConnectorOptions->GetOptions($objTable->ClassName, $objReference->PropertyName) + $objColumn->Options;
966:
967:
968:
969:
970: if (!$objReference->IsType) {
971:
972:
973: $objReferencedTable = $this->GetTable($objReference->Table);
974: $objReverseReference = new QReverseReference();
975: $objReverseReference->Reference = $objReference;
976: $objReverseReference->KeyName = $objReference->KeyName;
977: $objReverseReference->Table = $strTableName;
978: $objReverseReference->Column = $strColumnName;
979: $objReverseReference->NotNull = $objColumn->NotNull;
980: $objReverseReference->Unique = $objColumn->Unique;
981: $objReverseReference->PropertyName = $this->ModelColumnPropertyName($strColumnName);
982:
983: $objReverseReference->ObjectDescription = $this->CalculateObjectDescription($strTableName, $strColumnName, $strReferencedTableName, false);
984: $objReverseReference->ObjectDescriptionPlural = $this->CalculateObjectDescription($strTableName, $strColumnName, $strReferencedTableName, true);
985: $objReverseReference->VariableName = $this->ModelReverseReferenceVariableName($objTable->Name);
986: $objReverseReference->VariableType = $this->ModelReverseReferenceVariableType($objTable->Name);
987:
988:
989:
990:
991: if ((count($objTable->PrimaryKeyColumnArray) == 1) && ($objColumn->PrimaryKey)) {
992: $objReverseReference->ObjectMemberVariable = QConvertNotation::PrefixFromType(QType::Object) . $objReverseReference->VariableType;
993: $objReverseReference->ObjectPropertyName = $objReverseReference->VariableType;
994: $objReverseReference->ObjectDescription = $objReverseReference->VariableType;
995: $objReverseReference->ObjectDescriptionPlural = $this->Pluralize($objReverseReference->VariableType);
996:
997:
998: } else if ($objColumn->Unique) {
999: $objReverseReference->ObjectMemberVariable = $this->CalculateObjectMemberVariable($strTableName, $strColumnName, $strReferencedTableName);
1000: $objReverseReference->ObjectPropertyName = $this->CalculateObjectPropertyName($strTableName, $strColumnName, $strReferencedTableName);
1001:
1002: $objReverseReference->Options = $this->objModelConnectorOptions->GetOptions($objReference->VariableType, $objReverseReference->ObjectDescription);
1003: }
1004:
1005: $objReference->ReverseReference = $objReverseReference;
1006:
1007:
1008: $objArray = $objReferencedTable->ReverseReferenceArray;
1009: array_push($objArray, $objReverseReference);
1010: $objReferencedTable->ReverseReferenceArray = $objArray;
1011: }
1012: } else {
1013: $this->strErrors .= sprintf("Foreign Key %s in table %s references a table %s that does not appear to exist.\n",
1014: $objForeignKey->KeyName, $strTableName, $objForeignKey->ReferenceTableName);
1015: }
1016: } else {
1017: $this->strErrors .= sprintf("Foreign Key %s in table %s indexes on a column that does not appear to exist.\n",
1018: $objForeignKey->KeyName, $strTableName);
1019: }
1020: }
1021: }
1022:
1023:
1024:
1025: $strMatches = array();
1026: preg_match('/' . $this->strPatternTableName . '/', $strTableName, $strMatches);
1027: if (count($strMatches) && ($strMatches[0] == $strTableName) && ($strTableName != '_')) {
1028:
1029: $strReservedWords = explode(',', QCodeGen::PhpReservedWords);
1030: for ($intIndex = 0; $intIndex < count($strReservedWords); $intIndex++)
1031: $strReservedWords[$intIndex] = strtolower(trim($strReservedWords[$intIndex]));
1032:
1033: $strTableNameToTest = trim(strtolower($strTableName));
1034: foreach ($strReservedWords as $strReservedWord)
1035: if ($strTableNameToTest == $strReservedWord) {
1036: $this->strErrors .= sprintf("Table '%s' has a table name which is a PHP reserved word.\r\n", $strTableName);
1037: unset($this->objTableArray[strtolower($strTableName)]);
1038: return;
1039: }
1040: } else {
1041: $this->strErrors .= sprintf("Table '%s' can only contain characters that are alphanumeric or _, and must not begin with a number.\r\n", $strTableName);
1042: unset($this->objTableArray[strtolower($strTableName)]);
1043: return;
1044: }
1045:
1046:
1047: $objColumnArray = $objTable->ColumnArray;
1048: foreach ($objColumnArray as $objColumn) {
1049: $strColumnName = $objColumn->Name;
1050: $strMatches = array();
1051: preg_match('/' . $this->strPatternColumnName . '/', $strColumnName, $strMatches);
1052: if (count($strMatches) && ($strMatches[0] == $strColumnName) && ($strColumnName != '_')) {
1053: } else {
1054: $this->strErrors .= sprintf("Table '%s' has an invalid column name: '%s'\r\n", $strTableName, $strColumnName);
1055: unset($this->objTableArray[strtolower($strTableName)]);
1056: return;
1057: }
1058: }
1059:
1060:
1061: $blnFoundPk = false;
1062: $objColumnArray = $objTable->ColumnArray;
1063: foreach ($objColumnArray as $objColumn) {
1064: if ($objColumn->PrimaryKey)
1065: $blnFoundPk = true;
1066: }
1067: if (!$blnFoundPk) {
1068: $this->strErrors .= sprintf("Table %s does not have any defined primary keys.\n", $strTableName);
1069: unset($this->objTableArray[strtolower($strTableName)]);
1070: return;
1071: }
1072: }
1073:
1074: protected function AnalyzeTableColumn(QDatabaseFieldBase $objField, $objTable) {
1075: $objColumn = new QSqlColumn();
1076: $objColumn->Name = $objField->Name;
1077: $objColumn->OwnerTable = $objTable;
1078: if (substr_count($objField->Name, "-")) {
1079: $tableName = $objTable ? " in table " . $objTable->Name : "";
1080: $this->strErrors .= "Invalid column name" . $tableName . ": " . $objField->Name . ". Dashes are not allowed.";
1081: return null;
1082: }
1083:
1084: $objColumn->DbType = $objField->Type;
1085:
1086: $objColumn->VariableType = $this->VariableTypeFromDbType($objColumn->DbType);
1087: $objColumn->VariableTypeAsConstant = QType::Constant($objColumn->VariableType);
1088:
1089: $objColumn->Length = $objField->MaxLength;
1090: $objColumn->Default = $objField->Default;
1091:
1092: $objColumn->PrimaryKey = $objField->PrimaryKey;
1093: $objColumn->NotNull = $objField->NotNull;
1094: $objColumn->Identity = $objField->Identity;
1095: $objColumn->Unique = $objField->Unique;
1096: if (($objField->PrimaryKey) && $objTable && (count($objTable->PrimaryKeyColumnArray) == 1))
1097: $objColumn->Unique = true;
1098: $objColumn->Timestamp = $objField->Timestamp;
1099:
1100: $objColumn->VariableName = $this->ModelColumnVariableName($objColumn);
1101: $objColumn->PropertyName = $this->ModelColumnPropertyName($objColumn->Name);
1102:
1103:
1104:
1105:
1106: if (($strComment = $objField->Comment) &&
1107: ($pos1 = strpos ($strComment, '{')) !== false &&
1108: ($pos2 = strrpos ($strComment, '}', $pos1))) {
1109:
1110: $strJson = substr ($strComment, $pos1, $pos2 - $pos1 + 1);
1111: $a = json_decode($strJson, true);
1112:
1113: if ($a) {
1114: $objColumn->Options = $a;
1115: $objColumn->Comment = substr ($strComment, 0, $pos1) . substr ($strComment, $pos2 + 1);
1116: if (!empty ($a['Timestamp'])) {
1117: $objColumn->Timestamp = true;
1118: }
1119: if ($objColumn->Timestamp && !empty($a['AutoUpdate'])) {
1120: $objColumn->AutoUpdate = true;
1121: }
1122: } else {
1123: $objColumn->Comment = $strComment;
1124: }
1125: }
1126:
1127:
1128: $objColumn->Options = $this->objModelConnectorOptions->GetOptions($objTable->ClassName, $objColumn->PropertyName) + $objColumn->Options;
1129:
1130: return $objColumn;
1131: }
1132:
1133: protected function StripPrefixFromTable($strTableName) {
1134:
1135: if ($this->intStripTablePrefixLength &&
1136: (strlen($strTableName) > $this->intStripTablePrefixLength) &&
1137: (substr($strTableName, 0, $this->intStripTablePrefixLength - strlen($strTableName)) == $this->strStripTablePrefix))
1138: return substr($strTableName, $this->intStripTablePrefixLength);
1139:
1140: return $strTableName;
1141: }
1142:
1143: protected function GetForeignKeyForQcubedRelationshipDefinition($strTableName, $strLine) {
1144: $strTokens = explode('=>', $strLine);
1145: if (count($strTokens) != 2) {
1146: $this->strErrors .= sprintf("Could not parse Relationships Script reference: %s (Incorrect Format)\r\n", $strLine);
1147: $this->strRelationshipLinesQcubed[$strLine] = null;
1148: return null;
1149: }
1150:
1151: $strSourceTokens = explode('.', $strTokens[0]);
1152: $strDestinationTokens = explode('.', $strTokens[1]);
1153:
1154: if ((count($strSourceTokens) != 2) ||
1155: (count($strDestinationTokens) != 2)) {
1156: $this->strErrors .= sprintf("Could not parse Relationships Script reference: %s (Incorrect Table.Column Format)\r\n", $strLine);
1157: $this->strRelationshipLinesQcubed[$strLine] = null;
1158: return null;
1159: }
1160:
1161: $strColumnName = trim($strSourceTokens[1]);
1162: $strReferenceTableName = trim($strDestinationTokens[0]);
1163: $strReferenceColumnName = trim($strDestinationTokens[1]);
1164: $strFkName = sprintf('virtualfk_%s_%s', $strTableName, $strColumnName);
1165:
1166: if (strtolower($strTableName) == trim($strSourceTokens[0])) {
1167: $this->strRelationshipLinesQcubed[$strLine] = null;
1168: return $this->GetForeignKeyHelper($strLine, $strFkName, $strTableName, $strColumnName, $strReferenceTableName, $strReferenceColumnName);
1169: }
1170:
1171: return null;
1172: }
1173:
1174: protected function GetForeignKeyForSqlRelationshipDefinition($strTableName, $strLine) {
1175: $strMatches = array();
1176:
1177:
1178: $strPattern = '/alter[\s]+table[\s]+';
1179:
1180: $strPattern .= '[\[\`\'\"]?(' . $this->strPatternTableName . ')[\]\`\'\"]?[\s]+';
1181:
1182:
1183: $strPattern .= '(add[\s]+)?(constraint[\s]+';
1184: $strPattern .= '[\[\`\'\"]?(' . $this->strPatternKeyName . ')[\]\`\'\"]?[\s]+)?[\s]*';
1185:
1186: $strPattern .= 'foreign[\s]+key[\s]*(' . $this->strPatternKeyName . ')[\s]*\(';
1187: $strPattern .= '([^)]+)\)[\s]*';
1188:
1189: $strPattern .= 'references[\s]+';
1190: $strPattern .= '[\[\`\'\"]?(' . $this->strPatternTableName . ')[\]\`\'\"]?[\s]*\(';
1191: $strPattern .= '([^)]+)\)[\s]*';
1192:
1193: $strPattern .= '/';
1194:
1195:
1196: preg_match($strPattern, $strLine, $strMatches);
1197:
1198: if (count($strMatches) == 9) {
1199: $strColumnName = trim($strMatches[6]);
1200: $strReferenceTableName = trim($strMatches[7]);
1201: $strReferenceColumnName = trim($strMatches[8]);
1202: $strFkName = $strMatches[5];
1203: if (!$strFkName)
1204: $strFkName = sprintf('virtualfk_%s_%s', $strTableName, $strColumnName);
1205:
1206: if ((strpos($strColumnName, ',') !== false) ||
1207: (strpos($strReferenceColumnName, ',') !== false)) {
1208: $this->strErrors .= sprintf("Relationships Script has a foreign key definition with multiple columns: %s (Multiple-columned FKs are not supported by the code generator)\r\n", $strLine);
1209: $this->strRelationshipLinesSql[$strLine] = null;
1210: return null;
1211: }
1212:
1213:
1214: $strColumnName = str_replace("'", '', $strColumnName);
1215: $strColumnName = str_replace('"', '', $strColumnName);
1216: $strColumnName = str_replace('[', '', $strColumnName);
1217: $strColumnName = str_replace(']', '', $strColumnName);
1218: $strColumnName = str_replace('`', '', $strColumnName);
1219: $strColumnName = str_replace(' ', '', $strColumnName);
1220: $strColumnName = str_replace(' ', '', $strColumnName);
1221: $strColumnName = str_replace("\r", '', $strColumnName);
1222: $strColumnName = str_replace("\n", '', $strColumnName);
1223: $strReferenceColumnName = str_replace("'", '', $strReferenceColumnName);
1224: $strReferenceColumnName = str_replace('"', '', $strReferenceColumnName);
1225: $strReferenceColumnName = str_replace('[', '', $strReferenceColumnName);
1226: $strReferenceColumnName = str_replace(']', '', $strReferenceColumnName);
1227: $strReferenceColumnName = str_replace('`', '', $strReferenceColumnName);
1228: $strReferenceColumnName = str_replace(' ', '', $strReferenceColumnName);
1229: $strReferenceColumnName = str_replace(' ', '', $strReferenceColumnName);
1230: $strReferenceColumnName = str_replace("\r", '', $strReferenceColumnName);
1231: $strReferenceColumnName = str_replace("\n", '', $strReferenceColumnName);
1232:
1233: if (strtolower($strTableName) == trim($strMatches[1])) {
1234: $this->strRelationshipLinesSql[$strLine] = null;
1235: return $this->GetForeignKeyHelper($strLine, $strFkName, $strTableName, $strColumnName, $strReferenceTableName, $strReferenceColumnName);
1236: }
1237:
1238: return null;
1239: } else {
1240: $this->strErrors .= sprintf("Could not parse Relationships Script reference: %s (Not in ANSI SQL Format)\r\n", $strLine);
1241: $this->strRelationshipLinesSql[$strLine] = null;
1242: return null;
1243: }
1244: }
1245:
1246: protected function GetForeignKeyHelper($strLine, $strFkName, $strTableName, $strColumnName, $strReferencedTable, $strReferencedColumn) {
1247:
1248: if (!$this->ValidateTableColumn($strTableName, $strColumnName)) {
1249: $this->strErrors .= sprintf("Could not parse Relationships Script reference: \"%s\" (\"%s.%s\" does not exist)\r\n",
1250: $strLine, $strTableName, $strColumnName);
1251: return null;
1252: }
1253:
1254: if (!$this->ValidateTableColumn($strReferencedTable, $strReferencedColumn)) {
1255: $this->strErrors .= sprintf("Could not parse Relationships Script reference: \"%s\" (\"%s.%s\" does not exist)\r\n",
1256: $strLine, $strReferencedTable, $strReferencedColumn);
1257: return null;
1258: }
1259:
1260: return new QDatabaseForeignKey($strFkName, array($strColumnName), $strReferencedTable, array($strReferencedColumn));
1261: }
1262:
1263: 1264: 1265: 1266: 1267: 1268: 1269: 1270: 1271: 1272: 1273:
1274: protected function GetForeignKeysFromRelationshipsScript($strTableName, $objForeignKeyArray) {
1275: foreach ($this->strRelationshipLinesQcubed as $strLine) {
1276: if ($strLine) {
1277: $objForeignKey = $this->GetForeignKeyForQcubedRelationshipDefinition($strTableName, $strLine);
1278:
1279: if ($objForeignKey) {
1280: array_push($objForeignKeyArray, $objForeignKey);
1281: $this->strRelationshipLinesQcubed[$strLine] = null;
1282: }
1283: }
1284: }
1285:
1286: foreach ($this->strRelationshipLinesSql as $strLine) {
1287: if ($strLine) {
1288: $objForeignKey = $this->GetForeignKeyForSqlRelationshipDefinition($strTableName, $strLine);
1289:
1290: if ($objForeignKey) {
1291: array_push($objForeignKeyArray, $objForeignKey);
1292: $this->strRelationshipLinesSql[$strLine] = null;
1293: }
1294: }
1295: }
1296:
1297: return $objForeignKeyArray;
1298: }
1299:
1300: public function GenerateControlId($objTable, $objColumn) {
1301: $strControlId = null;
1302: if (isset($objColumn->Options['ControlId'])) {
1303: $strControlId = $objColumn->Options['ControlId'];
1304: } elseif ($this->blnGenerateControlId) {
1305: $strObjectName = $this->ModelVariableName($objTable->Name);
1306: $strClassName = $objTable->ClassName;
1307: $strControlVarName = $this->ModelConnectorVariableName($objColumn);
1308: $strLabelName = QCodeGen::ModelConnectorControlName($objColumn);
1309:
1310: $strControlId = $strControlVarName . $strClassName;
1311:
1312: }
1313: return $strControlId;
1314: }
1315:
1316:
1317:
1318:
1319: 1320: 1321: 1322: 1323: 1324: 1325:
1326: public function GetCastString (QSqlColumn $objColumn) {
1327: switch ($objColumn->DbType) {
1328: case QDatabaseFieldType::Bit:
1329: return ('$mixVal = (bool)$mixVal;');
1330:
1331: case QDatabaseFieldType::Blob:
1332: case QDatabaseFieldType::Char:
1333: case QDatabaseFieldType::VarChar:
1334: case QDatabaseFieldType::Json:
1335: return '';
1336:
1337: case QDatabaseFieldType::Date:
1338: return ('$mixVal = new QDateTime($mixVal, null, QDateTime::DateOnlyType);');
1339:
1340: case QDatabaseFieldType::DateTime:
1341: return ('$mixVal = new QDateTime($mixVal);');
1342:
1343: case QDatabaseFieldType::Time:
1344: return ('$mixVal = new QDateTime($mixVal, null, QDateTime::TimeOnlyType);');
1345:
1346: case QDatabaseFieldType::Float:
1347: case QDatabaseFieldType::Integer:
1348: return ('$mixVal = (' . $objColumn->VariableType . ')$mixVal;');
1349:
1350: default:
1351: throw new Exception ('Invalid database field type');
1352: exit;
1353: }
1354: }
1355:
1356:
1357:
1358:
1359:
1360:
1361:
1362: 1363: 1364: 1365: 1366: 1367: 1368:
1369: public function __get($strName) {
1370: switch ($strName) {
1371: case 'TableArray':
1372: return $this->objTableArray;
1373: case 'TypeTableArray':
1374: return $this->objTypeTableArray;
1375: case 'DatabaseIndex':
1376: return $this->intDatabaseIndex;
1377: case 'CommentConnectorLabelDelimiter':
1378: return $this->strCommentConnectorLabelDelimiter;
1379: case 'AutoInitialize':
1380: return $this->blnAutoInitialize;
1381: case 'objSettingsXml':
1382: throw new QCallerException('The field objSettingsXml is deprecated');
1383: default:
1384: try {
1385: return parent::__get($strName);
1386: } catch (QCallerException $objExc) {
1387: $objExc->IncrementOffset();
1388: throw $objExc;
1389: }
1390: }
1391: }
1392:
1393: public function __set($strName, $mixValue) {
1394: try {
1395: switch($strName) {
1396: default:
1397: return parent::__set($strName, $mixValue);
1398: }
1399: } catch (QCallerException $objExc) {
1400: $objExc->IncrementOffset();
1401: }
1402: }
1403: }
1404:
1405: function array_trim(&$strValue) {
1406: $strValue = trim($strValue);
1407: }