1: <?php
2:
3: function QcubedHandleCodeGenParseError($__exc_errno, $__exc_errstr, $__exc_errfile, $__exc_errline) {
4: $strErrorString = str_replace("SimpleXMLElement::__construct() [<a href='function.SimpleXMLElement---construct'>function.SimpleXMLElement---construct</a>]: ", '', $__exc_errstr);
5: QCodeGen::$RootErrors .= sprintf("%s\r\n", $strErrorString);
6: }
7:
8: function GO_BACK($intNumChars) {
9: $content_so_far = ob_get_contents();
10: ob_end_clean();
11: $content_so_far = substr($content_so_far, 0, strlen($content_so_far) - $intNumChars);
12: ob_start();
13: print $content_so_far;
14: }
15:
16:
17: function beginsWith( $str, $sub ) {
18: return ( substr( $str, 0, strlen( $sub ) ) == $sub );
19: }
20:
21:
22: function endsWith( $str, $sub ) {
23: return ( substr( $str, strlen( $str ) - strlen( $sub ) ) == $sub );
24: }
25:
26:
27:
28: function trimOffFront( $off, $str ) {
29: if( is_numeric( $off ) )
30: return substr( $str, $off );
31: else
32: return substr( $str, strlen( $off ) );
33: }
34:
35:
36:
37: function trimOffEnd( $off, $str ) {
38: if( is_numeric( $off ) )
39: return substr( $str, 0, strlen( $str ) - $off );
40: else
41: return substr( $str, 0, strlen( $str ) - strlen( $off ) );
42: }
43:
44: 45: 46: 47: 48: 49: 50: 51: 52:
53: abstract class QCodeGenBase extends QBaseClass {
54:
55:
56: protected $strClassPrefix;
57:
58: protected $strClassSuffix;
59:
60:
61: protected $strErrors;
62:
63:
64: protected $strWarnings;
65:
66: 67: 68: 69: 70: 71:
72: const PhpReservedWords = 'new, null, break, return, switch, self, case, const, clone, continue, declare, default, echo, else, elseif, empty, exit, eval, if, try, throw, catch, public, private, protected, function, extends, foreach, for, while, do, var, class, static, abstract, isset, unset, implements, interface, instanceof, include, include_once, require, require_once, abstract, and, or, xor, array, list, false, true, global, parent, print, exception, namespace, goto, final, endif, endswitch, enddeclare, endwhile, use, as, endfor, endforeach, this';
73:
74: 75: 76: 77:
78: public static $TemplatePaths;
79:
80: 81: 82: 83: 84: 85:
86: const DebugMode = false;
87:
88: 89: 90: 91: 92: 93:
94: public static $CodeGenArray;
95:
96: 97: 98: 99: 100: 101:
102: protected static $SettingsXmlArray;
103:
104: 105: 106: 107: 108:
109: protected static $SettingsXml;
110:
111: public static $SettingsFilePath;
112:
113: 114: 115: 116: 117:
118: public static $ApplicationName;
119:
120: 121: 122: 123: 124:
125: public static $PreferredRenderMethod;
126:
127: 128: 129: 130: 131:
132: public static $CreateMethod;
133:
134: 135: 136: 137: 138:
139: public static $DefaultButtonClass;
140:
141:
142: 143: 144: 145: 146:
147: protected static $TemplateEscapeBegin;
148: protected static $TemplateEscapeBeginLength;
149:
150: 151: 152: 153: 154:
155: protected static $TemplateEscapeEnd;
156: protected static $TemplateEscapeEndLength;
157:
158: public static $RootErrors = '';
159:
160: 161: 162: 163:
164: protected static $DirectoriesToExcludeArray = array('.','..','.svn','svn','cvs','.git');
165:
166: 167: 168: 169:
170: public static function GetSettingsXml() {
171: $strCrLf = "\r\n";
172:
173: $strToReturn = sprintf('<codegen>%s', $strCrLf);
174: $strToReturn .= sprintf(' <name application="%s"/>%s', QCodeGen::$ApplicationName, $strCrLf);
175: $strToReturn .= sprintf(' <templateEscape begin="%s" end="%s"/>%s', QCodeGen::$TemplateEscapeBegin, QCodeGen::$TemplateEscapeEnd, $strCrLf);
176: $strToReturn .= sprintf(' <render preferredRenderMethod="%s"/>%s', QCodeGen::$PreferredRenderMethod, $strCrLf);
177: $strToReturn .= sprintf(' <dataSources>%s', $strCrLf);
178: foreach (QCodeGen::$CodeGenArray as $objCodeGen)
179: $strToReturn .= $strCrLf . $objCodeGen->GetConfigXml();
180: $strToReturn .= sprintf('%s </dataSources>%s', $strCrLf, $strCrLf);
181: $strToReturn .= '</codegen>';
182:
183: return $strToReturn;
184: }
185:
186: 187: 188: 189: 190:
191: public static function Run($strSettingsXmlFilePath) {
192: define ('__CODE_GENERATING__', true);
193: QCodeGen::$CodeGenArray = array();
194: QCodeGen::$SettingsFilePath = $strSettingsXmlFilePath;
195:
196: if (!file_exists($strSettingsXmlFilePath)) {
197: QCodeGen::$RootErrors = 'FATAL ERROR: CodeGen Settings XML File (' . $strSettingsXmlFilePath . ') was not found.';
198: return;
199: }
200:
201: if (!is_file($strSettingsXmlFilePath)) {
202: QCodeGen::$RootErrors = 'FATAL ERROR: CodeGen Settings XML File (' . $strSettingsXmlFilePath . ') was not found.';
203: return;
204: }
205:
206:
207: try {
208: QApplication::SetErrorHandler('QcubedHandleCodeGenParseError', E_ALL);
209: QCodeGen::$SettingsXml = new SimpleXMLElement(file_get_contents($strSettingsXmlFilePath));
210: QApplication::RestoreErrorHandler();
211: } catch (Exception $objExc) {
212: QCodeGen::$RootErrors .= 'FATAL ERROR: Unable to parse CodeGenSettings XML File: ' . $strSettingsXmlFilePath;
213: QCodeGen::$RootErrors .= "\r\n";
214: QCodeGen::$RootErrors .= $objExc->getMessage();
215: return;
216: }
217:
218:
219: QCodeGen::$TemplateEscapeBegin = QCodeGen::LookupSetting(QCodeGen::$SettingsXml, 'templateEscape', 'begin');
220: QCodeGen::$TemplateEscapeEnd = QCodeGen::LookupSetting(QCodeGen::$SettingsXml, 'templateEscape', 'end');
221: QCodeGen::$TemplateEscapeBeginLength = strlen(QCodeGen::$TemplateEscapeBegin);
222: QCodeGen::$TemplateEscapeEndLength = strlen(QCodeGen::$TemplateEscapeEnd);
223:
224: if ((!QCodeGen::$TemplateEscapeBeginLength) || (!QCodeGen::$TemplateEscapeEndLength)) {
225: QCodeGen::$RootErrors .= "CodeGen Settings XML Fatal Error: templateEscape begin and/or end was not defined\r\n";
226: return;
227: }
228:
229:
230: QCodeGen::$ApplicationName = QCodeGen::LookupSetting(QCodeGen::$SettingsXml, 'name', 'application');
231:
232:
233: QCodeGen::$PreferredRenderMethod = QCodeGen::LookupSetting(QCodeGen::$SettingsXml, 'formgen', 'preferredRenderMethod');
234: QCodeGen::$CreateMethod = QCodeGen::LookupSetting(QCodeGen::$SettingsXml, 'formgen', 'createMethod');
235: QCodeGen::$DefaultButtonClass = QCodeGen::LookupSetting(QCodeGen::$SettingsXml, 'formgen', 'buttonClass');
236:
237: if (!QCodeGen::$DefaultButtonClass) {
238: QCodeGen::$RootErrors .= "CodeGen Settings XML Fatal Error: buttonClass was not defined\r\n";
239: return;
240: }
241:
242:
243: if (QCodeGen::$SettingsXml->dataSources->asXML())
244: foreach (QCodeGen::$SettingsXml->dataSources->children() as $objChildNode) {
245: switch (dom_import_simplexml($objChildNode)->nodeName) {
246: case 'database':
247: QCodeGen::$CodeGenArray[] = new QDatabaseCodeGen($objChildNode);
248: break;
249: case 'restService':
250: QCodeGen::$CodeGenArray[] = new QRestServiceCodeGen($objChildNode);
251: break;
252: default:
253: QCodeGen::$RootErrors .= sprintf("Invalid Data Source Type in CodeGen Settings XML File (%s): %s\r\n",
254: $strSettingsXmlFilePath, dom_import_simplexml($objChildNode)->nodeName);
255: break;
256: }
257: }
258: }
259:
260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272:
273: static public function LookupSetting($objNode, $strTagName, $strAttributeName = null, $strType = QType::String) {
274: if ($strTagName)
275: $objNode = $objNode->$strTagName;
276:
277: if ($strAttributeName) {
278: switch ($strType) {
279: case QType::Integer:
280: try {
281: $intToReturn = QType::Cast($objNode[$strAttributeName], QType::Integer);
282: return $intToReturn;
283: } catch (Exception $objExc) {
284: return null;
285: }
286: case QType::Boolean:
287: try {
288: $blnToReturn = QType::Cast($objNode[$strAttributeName], QType::Boolean);
289: return $blnToReturn;
290: } catch (Exception $objExc) {
291: return null;
292: }
293: default:
294: $strToReturn = trim(QType::Cast($objNode[$strAttributeName], QType::String));
295: return $strToReturn;
296: }
297: } else {
298: $strToReturn = trim(QType::Cast($objNode, QType::String));
299: return $strToReturn;
300: }
301: }
302:
303: 304: 305: 306:
307: public static function GenerateAggregate() {
308: $objDbOrmCodeGen = array();
309: $objRestServiceCodeGen = array();
310:
311: foreach (QCodeGen::$CodeGenArray as $objCodeGen) {
312: if ($objCodeGen instanceof QDatabaseCodeGen)
313: array_push($objDbOrmCodeGen, $objCodeGen);
314: if ($objCodeGen instanceof QRestServiceCodeGen)
315: array_push($objRestServiceCodeGen, $objCodeGen);
316: }
317:
318: $strToReturn = array();
319: array_merge($strToReturn, QDatabaseCodeGen::GenerateAggregateHelper($objDbOrmCodeGen));
320:
321:
322: return $strToReturn;
323: }
324:
325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339:
340: public function GenerateFiles($strTemplatePrefix, $mixArgumentArray) {
341:
342: if (QCodeGen::DebugMode && ini_get ('short_open_tag')) _p("Warning: PHP directive short_open_tag is on. Using short tags will cause unexpected EOF on travis build.\n", false);
343:
344:
345: if (!static::$TemplatePaths) {
346: static::$TemplatePaths = array (
347: __QCUBED_CORE__ . '/codegen/templates/',
348: __QCUBED__ . '/codegen/templates/'
349: );
350: }
351:
352:
353: foreach (static::$TemplatePaths as $strPath) {
354: if (!is_dir($strPath)) {
355: throw new Exception(sprintf("Template path: %s does not appear to be a valid directory.", $strPath));
356: }
357: }
358:
359:
360:
361:
362:
363:
364: $strTemplateArray = array();
365:
366:
367: foreach (static::$TemplatePaths as $strPath) {
368: $this->buildTemplateArray($strPath . $strTemplatePrefix, $strTemplateArray);
369: }
370:
371:
372: $blnSuccess = true;
373: foreach ($strTemplateArray as $strModuleName => $strFileArray) {
374: foreach ($strFileArray as $strFilename => $strPath) {
375: if (!$this->GenerateFile($strTemplatePrefix . '/' . $strModuleName, $strPath, $mixArgumentArray)) {
376: $blnSuccess = false;
377: }
378: }
379: }
380:
381: return $blnSuccess;
382: }
383:
384: protected function buildTemplateArray ($strTemplateFilePath, &$strTemplateArray) {
385: if (!$strTemplateFilePath) return;
386: if (substr( $strTemplateFilePath, -1 ) != '/') {
387: $strTemplateFilePath .= '/';
388: }
389: if (is_dir($strTemplateFilePath)) {
390: $objDirectory = opendir($strTemplateFilePath);
391: while ($strModuleName = readdir($objDirectory)) {
392: if (!in_array(strtolower($strModuleName), QCodeGen::$DirectoriesToExcludeArray) &&
393: is_dir($strTemplateFilePath . $strModuleName)) {
394: $objModuleDirectory = opendir($strTemplateFilePath . $strModuleName);
395: while ($strFilename = readdir($objModuleDirectory)) {
396: if ((QString::FirstCharacter($strFilename) == '_') &&
397: (substr($strFilename, strlen($strFilename) - 8) == '.tpl.php')
398: ) {
399: $strTemplateArray[$strModuleName][$strFilename] = $strTemplateFilePath . $strModuleName . '/' . $strFilename;
400: }
401: }
402: }
403: }
404: }
405: }
406:
407: 408: 409: 410: 411: 412: 413: 414: 415: 416:
417: protected function getTemplateSettings($strTemplateFilePath, &$strTemplate = null) {
418: if ($strTemplate === null)
419: $strTemplate = file_get_contents($strTemplateFilePath);
420: $strError = 'Template\'s first line must be <template OverwriteFlag="boolean" DocrootFlag="boolean" TargetDirectory="string" DirectorySuffix="string" TargetFileName="string"/>: ' . $strTemplateFilePath;
421:
422: $intPosition = strpos($strTemplate, "\n");
423: if ($intPosition === false) {
424: throw new Exception($strError);
425: }
426:
427: $strFirstLine = trim(substr($strTemplate, 0, $intPosition));
428:
429: $objTemplateXml = null;
430:
431: try {
432: @$objTemplateXml = new SimpleXMLElement($strFirstLine);
433: } catch (Exception $objExc) {}
434:
435: if (is_null($objTemplateXml) || (!($objTemplateXml instanceof SimpleXMLElement)))
436: throw new Exception($strError);
437: $strTemplate = substr($strTemplate, $intPosition + 1);
438: return $objTemplateXml;
439: }
440:
441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452:
453: public function GenerateFile($strModuleSubPath, $strTemplateFilePath, $mixArgumentArray, $blnSave = true) {
454:
455: if (QCodeGen::DebugMode) _p("Evaluating $strTemplateFilePath<br/>", false);
456:
457:
458: if (!file_exists($strTemplateFilePath))
459: throw new QCallerException('Template File Not Found: ' . $strTemplateFilePath);
460:
461:
462:
463:
464: $a = array();
465: foreach (static::$TemplatePaths as $strTemplatePath) {
466: array_unshift($a, $strTemplatePath . $strModuleSubPath);
467: }
468: $strSearchPath = implode (PATH_SEPARATOR, $a) . PATH_SEPARATOR . get_include_path();
469: $strOldIncludePath = set_include_path ($strSearchPath);
470: if ($strSearchPath != get_include_path()) {
471: throw new QCallerException ('Can\'t override include path. Make sure your apache or server settings allow include paths to be overridden. ' );
472: }
473:
474: $strTemplate = $this->EvaluatePHP($strTemplateFilePath, $mixArgumentArray, $templateSettings);
475: set_include_path($strOldIncludePath);
476:
477: $blnOverwriteFlag = QType::Cast($templateSettings['OverwriteFlag'], QType::Boolean);
478: $blnDocrootFlag = QType::Cast($templateSettings['DocrootFlag'], QType::Boolean);
479: $strTargetDirectory = QType::Cast($templateSettings['TargetDirectory'], QType::String);
480: $strDirectorySuffix = QType::Cast($templateSettings['DirectorySuffix'], QType::String);
481: $strTargetFileName = QType::Cast($templateSettings['TargetFileName'], QType::String);
482:
483: if (is_null($blnOverwriteFlag) || is_null($strTargetFileName) || is_null($strTargetDirectory) || is_null($strDirectorySuffix) || is_null($blnDocrootFlag)) {
484: throw new Exception('the template settings cannot be null');
485: }
486:
487: if ($blnSave && $strTargetDirectory) {
488:
489: if ($blnDocrootFlag)
490: $strTargetDirectory = __DOCROOT__ . $strTargetDirectory . $strDirectorySuffix;
491: else
492: $strTargetDirectory = $strTargetDirectory . $strDirectorySuffix;
493:
494:
495: if (!is_dir($strTargetDirectory))
496: if (!QApplication::MakeDirectory($strTargetDirectory, 0777))
497: throw new Exception('Unable to mkdir ' . $strTargetDirectory);
498:
499:
500: $strFilePath = sprintf('%s/%s', $strTargetDirectory, $strTargetFileName);
501: if ($blnOverwriteFlag || (!file_exists($strFilePath))) {
502: $intBytesSaved = file_put_contents($strFilePath, $strTemplate);
503:
504: $this->setGeneratedFilePermissions($strFilePath);
505: return ($intBytesSaved == strlen($strTemplate));
506: } else
507:
508: return true;
509: }
510:
511:
512: if ($blnSave) {
513:
514:
515: return true;
516: }
517:
518: return $strTemplate;
519: }
520:
521: 522: 523: 524: 525: 526:
527: protected function setGeneratedFilePermissions($strFilePath) {
528:
529:
530: if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
531: QApplication::SetErrorHandler(null);
532: chmod($strFilePath, 0666);
533: QApplication::RestoreErrorHandler();
534: }
535: }
536:
537: 538: 539: 540: 541: 542: 543: 544:
545: protected function EvaluatePHP($strFilename, $mixArgumentArray, &$templateSettings = null) {
546:
547: if ($mixArgumentArray) foreach ($mixArgumentArray as $strName=>$mixValue) {
548: $$strName = $mixValue;
549: }
550: global $_TEMPLATE_SETTINGS;
551: unset($_TEMPLATE_SETTINGS);
552: $_TEMPLATE_SETTINGS = null;
553:
554:
555: $objCodeGen = $this;
556:
557:
558: $strEscapeIdentifierBegin = QApplication::$Database[$this->intDatabaseIndex]->EscapeIdentifierBegin;
559: $strEscapeIdentifierEnd = QApplication::$Database[$this->intDatabaseIndex]->EscapeIdentifierEnd;
560:
561:
562: $strAlreadyRendered = ob_get_contents();
563:
564: if (ob_get_level()) ob_clean();
565: ob_start();
566: include($strFilename);
567: $strTemplate = ob_get_contents();
568: ob_end_clean();
569:
570: $templateSettings = $_TEMPLATE_SETTINGS;
571: unset($_TEMPLATE_SETTINGS);
572:
573:
574: print($strAlreadyRendered);
575:
576:
577: $strTemplate = str_replace("\r", '', $strTemplate);
578: return $strTemplate;
579: }
580:
581:
582:
583:
584:
585: 586: 587: 588: 589: 590:
591: protected function ModelClassName($strTableName) {
592: $strTableName = $this->StripPrefixFromTable($strTableName);
593: return sprintf('%s%s%s',
594: $this->strClassPrefix,
595: QConvertNotation::CamelCaseFromUnderscore($strTableName),
596: $this->strClassSuffix);
597: }
598:
599: 600: 601: 602: 603:
604: public function ModelVariableName($strTableName) {
605: $strTableName = $this->StripPrefixFromTable($strTableName);
606: return QConvertNotation::PrefixFromType(QType::Object) .
607: QConvertNotation::CamelCaseFromUnderscore($strTableName);
608: }
609:
610: 611: 612: 613: 614: 615:
616: protected function ModelReverseReferenceVariableName($strTableName) {
617: $strTableName = $this->StripPrefixFromTable($strTableName);
618: return $this->ModelVariableName($strTableName);
619: }
620:
621: 622: 623: 624: 625: 626:
627: protected function ModelReverseReferenceVariableType($strTableName) {
628: $strTableName = $this->StripPrefixFromTable($strTableName);
629: return $this->ModelClassName($strTableName);
630: }
631:
632:
633: 634: 635: 636: 637: 638: 639:
640: protected function ModelColumnVariableName(QSqlColumn $objColumn) {
641: return QConvertNotation::PrefixFromType($objColumn->VariableType) .
642: QConvertNotation::CamelCaseFromUnderscore($objColumn->Name);
643: }
644:
645: 646: 647: 648: 649: 650:
651: protected function ModelColumnPropertyName($strColumnName) {
652: return QConvertNotation::CamelCaseFromUnderscore($strColumnName);
653: }
654:
655: 656: 657: 658: 659: 660:
661: protected function TypeColumnPropertyName($strColumnName) {
662: return QConvertNotation::CamelCaseFromUnderscore($strColumnName);
663: }
664:
665: 666: 667: 668: 669: 670: 671: 672: 673:
674: protected function ModelReferenceColumnName($strColumnName) {
675: $intNameLength = strlen($strColumnName);
676:
677:
678: if (($intNameLength > 3) && (substr($strColumnName, $intNameLength - 3) == "_id")) {
679:
680:
681: $strColumnName = substr($strColumnName, 0, $intNameLength - 3);
682: } else {
683:
684:
685:
686:
687:
688:
689: $strColumnName = sprintf("%s_object", $strColumnName);
690: }
691:
692: return $strColumnName;
693: }
694:
695: 696: 697: 698: 699: 700: 701:
702: protected function ModelReferenceVariableName($strColumnName) {
703: $strColumnName = $this->ModelReferenceColumnName($strColumnName);
704: return QConvertNotation::PrefixFromType(QType::Object) .
705: QConvertNotation::CamelCaseFromUnderscore($strColumnName);
706: }
707:
708: 709: 710: 711: 712: 713: 714:
715: protected function ModelReferencePropertyName($strColumnName) {
716: $strColumnName = $this->ModelReferenceColumnName($strColumnName);
717: return QConvertNotation::CamelCaseFromUnderscore($strColumnName);
718: }
719:
720: protected function ParameterCleanupFromColumn(QSqlColumn $objColumn, $blnIncludeEquality = false) {
721: if ($blnIncludeEquality)
722: return sprintf('$%s = $objDatabase->SqlVariable($%s, true);',
723: $objColumn->VariableName, $objColumn->VariableName);
724: else
725: return sprintf('$%s = $objDatabase->SqlVariable($%s);',
726: $objColumn->VariableName, $objColumn->VariableName);
727: }
728:
729:
730: protected function ParameterListFromColumnArray($objColumnArray) {
731: return $this->ImplodeObjectArray(', ', '$', '', 'VariableName', $objColumnArray);
732: }
733:
734: protected function ImplodeObjectArray($strGlue, $strPrefix, $strSuffix, $strProperty, $objArrayToImplode) {
735: $strArrayToReturn = array();
736: if ($objArrayToImplode) foreach ($objArrayToImplode as $objObject) {
737: array_push($strArrayToReturn, sprintf('%s%s%s', $strPrefix, $objObject->__get($strProperty), $strSuffix));
738: }
739:
740: return implode($strGlue, $strArrayToReturn);
741: }
742:
743: protected function TypeTokenFromTypeName($strName) {
744: $strToReturn = '';
745: for($intIndex = 0; $intIndex < strlen($strName); $intIndex++)
746: if (((ord($strName[$intIndex]) >= ord('a')) &&
747: (ord($strName[$intIndex]) <= ord('z'))) ||
748: ((ord($strName[$intIndex]) >= ord('A')) &&
749: (ord($strName[$intIndex]) <= ord('Z'))) ||
750: ((ord($strName[$intIndex]) >= ord('0')) &&
751: (ord($strName[$intIndex]) <= ord('9'))) ||
752: ($strName[$intIndex] == '_'))
753: $strToReturn .= $strName[$intIndex];
754:
755: if (is_numeric(QString::FirstCharacter($strToReturn)))
756: $strToReturn = '_' . $strToReturn;
757: return $strToReturn;
758: }
759:
760: 761: 762: 763: 764: 765: 766:
767: public static function ModelConnectorControlName ($objColumn) {
768: if (($o = $objColumn->Options) && isset ($o['Name'])) {
769: return $o['Name'];
770: }
771: return QConvertNotation::WordsFromCamelCase(QCodeGen::ModelConnectorPropertyName($objColumn));
772: }
773:
774: 775: 776: 777: 778: 779: 780: 781:
782: public static function ModelConnectorPropertyName ($objColumn) {
783: if ($objColumn instanceof QSqlColumn) {
784: if ($objColumn->Reference) {
785: return $objColumn->Reference->PropertyName;
786: } else {
787: return $objColumn->PropertyName;
788: }
789: }
790: elseif ($objColumn instanceof QReverseReference) {
791: if ($objColumn->Unique) {
792: return ($objColumn->ObjectDescription);
793: }
794: else {
795: return ($objColumn->ObjectDescriptionPlural);
796: }
797: }
798: elseif ($objColumn instanceof QManyToManyReference) {
799: return $objColumn->ObjectDescriptionPlural;
800: }
801: else {
802: throw new Exception ('Unknown column type.');
803: }
804: }
805:
806: 807: 808: 809: 810: 811:
812: public function ModelConnectorVariableName($objColumn) {
813: $strPropName = static::ModelConnectorPropertyName($objColumn);
814: $objControlHelper = $this->GetControlCodeGenerator($objColumn);
815: return $objControlHelper->VarName ($strPropName);
816: }
817:
818: 819: 820: 821: 822: 823:
824: public function ModelConnectorLabelVariableName($objColumn) {
825: $strPropName = static::ModelConnectorPropertyName($objColumn);
826: return QLabel_CodeGenerator::Instance()->VarName($strPropName);
827: }
828:
829: 830: 831: 832: 833: 834: 835: 836: 837:
838: protected function ModelConnectorControlClass($objColumn) {
839:
840:
841: if ($o = $objColumn->Options) {
842: if (isset ($o['FormGen']) && $o['FormGen'] == QFormGen::LabelOnly) {
843: return 'QLabel';
844: }
845: if (isset($o['ControlClass'])) {
846: return $o['ControlClass'];
847: }
848: }
849:
850:
851: if ($objColumn instanceof QSqlColumn) {
852: if ($objColumn->Identity)
853: return 'QLabel';
854:
855: if ($objColumn->Timestamp)
856: return 'QLabel';
857:
858: if ($objColumn->Reference)
859: return 'QListBox';
860:
861: switch ($objColumn->VariableType) {
862: case QType::Boolean:
863: return 'QCheckBox';
864: case QType::DateTime:
865: return 'QDateTimePicker';
866: case QType::Integer:
867: return 'QIntegerTextBox';
868: case QType::Float:
869: return 'QFloatTextBox';
870: default:
871: return 'QTextBox';
872: }
873: }
874: elseif ($objColumn instanceof QReverseReference) {
875: if ($objColumn->Unique) {
876: return 'QListBox';
877: } else {
878: return 'QCheckBoxList';
879: }
880: }
881: elseif ($objColumn instanceof QManyToManyReference) {
882: return 'QCheckBoxList';
883: }
884: throw new Exception('Unknown column type.');
885: }
886:
887:
888: public function DataListControlClass (QSqlTable $objTable) {
889:
890: if ($o = $objTable->Options) {
891: if (isset($o['ControlClass'])) {
892: return $o['ControlClass'];
893: }
894: }
895:
896:
897: return 'QDataGrid';
898: }
899:
900: 901: 902: 903: 904: 905: 906:
907: public static function DataListControlName (QSqlTable $objTable) {
908: if (($o = $objTable->Options) && isset ($o['Name'])) {
909: return $o['Name'];
910: }
911: return QConvertNotation::WordsFromCamelCase($objTable->ClassNamePlural);
912: }
913:
914: 915: 916: 917: 918: 919: 920:
921: public static function DataListItemName (QSqlTable $objTable) {
922: if (($o = $objTable->Options) && isset ($o['ItemName'])) {
923: return $o['ItemName'];
924: }
925: return QConvertNotation::WordsFromCamelCase($objTable->ClassName);
926: }
927:
928: public function DataListVarName (QSqlTable $objTable) {
929: $strPropName = self::DataListPropertyNamePlural($objTable);
930: $objControlHelper = $this->GetDataListCodeGenerator($objTable);
931: return $objControlHelper->VarName($strPropName);
932: }
933:
934: public static function DataListPropertyName (QSqlTable $objTable) {
935: return $objTable->ClassName;
936: }
937:
938: public static function DataListPropertyNamePlural (QSqlTable $objTable) {
939: return $objTable->ClassNamePlural;
940: }
941:
942:
943: 944: 945: 946: 947: 948: 949: 950: 951:
952: public function GetControlCodeGenerator($objColumn) {
953: $strControlClass = $this->ModelConnectorControlClass($objColumn);
954:
955: if (method_exists($strControlClass, 'GetCodeGenerator')) {
956: return call_user_func($strControlClass.'::GetCodeGenerator');
957: }
958:
959: switch ($strControlClass) {
960: case 'QLabel': return QLabel_CodeGenerator::Instance();
961: case 'QListBox': return new QListBox_CodeGenerator();
962: case 'QCheckBox': return new QCheckBox_CodeGenerator();
963: case 'QDateTimePicker': return new QDateTimePicker_CodeGenerator();
964: case 'QTextBox': return new QTextBox_CodeGenerator();
965: case 'QIntegerTextBox': return new QIntegerTextBox_CodeGenerator();
966: case 'QFloatTextBox': return new QFloatTextBox_CodeGenerator();
967: case 'QCheckBoxList': return new QCheckBoxList_CodeGenerator();
968: default: break;
969: }
970:
971: $strOrigControlClass = $strControlClass;
972: $strControlCodeGeneratorClass = $strControlClass .'_CodeGenerator';
973: while (!class_exists($strControlCodeGeneratorClass)) {
974: $strControlClass = get_parent_class($strControlClass);
975: if ($strControlClass === 'QControl') {
976: throw new QCallerException("Cannot find an appropriate subclass of AbstractControl_CodeGenerator for ".$strOrigControlClass);
977: }
978: $strControlCodeGeneratorClass = $strControlClass .'_CodeGenerator';
979: }
980: return new $strControlCodeGeneratorClass($strOrigControlClass);
981: }
982:
983: public function GetDataListCodeGenerator($objTable) {
984: $strControlClass = $this->DataListControlClass($objTable);
985:
986: if (method_exists($strControlClass, 'GetCodeGenerator')) {
987: return call_user_func($strControlClass.'::GetCodeGenerator');
988: }
989:
990: return new QDataGrid_CodeGenerator();
991: }
992:
993:
994: protected function CalculateObjectMemberVariable($strTableName, $strColumnName, $strReferencedTableName) {
995: return sprintf('%s%s%s%s',
996: QConvertNotation::PrefixFromType(QType::Object),
997: $this->strAssociatedObjectPrefix,
998: $this->CalculateObjectDescription($strTableName, $strColumnName, $strReferencedTableName, false),
999: $this->strAssociatedObjectSuffix);
1000: }
1001:
1002: protected function CalculateObjectPropertyName($strTableName, $strColumnName, $strReferencedTableName) {
1003: return sprintf('%s%s%s',
1004: $this->strAssociatedObjectPrefix,
1005: $this->CalculateObjectDescription($strTableName, $strColumnName, $strReferencedTableName, false),
1006: $this->strAssociatedObjectSuffix);
1007: }
1008:
1009:
1010: protected function CalculateObjectDescription($strTableName, $strColumnName, $strReferencedTableName, $blnPluralize) {
1011:
1012: $strTableName = $this->StripPrefixFromTable($strTableName);
1013: $strReferencedTableName = $this->StripPrefixFromTable($strReferencedTableName);
1014:
1015:
1016: $strToReturn = QConvertNotation::CamelCaseFromUnderscore($strTableName);
1017:
1018: if ($blnPluralize)
1019: $strToReturn = $this->Pluralize($strToReturn);
1020:
1021: if ($strTableName == $strReferencedTableName) {
1022:
1023:
1024:
1025:
1026: if (($strColumnName == $strReferencedTableName) ||
1027: ($strColumnName == $strReferencedTableName . '_id'))
1028: return sprintf('Child%s', $strToReturn);
1029:
1030:
1031: $intLength = strlen($strColumnName);
1032: if (($intLength > 3) && (substr($strColumnName, $intLength - 3) == "_id"))
1033: $strColumnName = substr($strColumnName, 0, $intLength - 3);
1034:
1035:
1036: $strColumnName = str_replace($strReferencedTableName, "", $strColumnName);
1037:
1038:
1039: $strColumnName = str_replace("__", "_", $strColumnName);
1040: $strColumnName = str_replace("__", "_", $strColumnName);
1041:
1042: $strColumnName = QConvertNotation::CamelCaseFromUnderscore($strColumnName);
1043:
1044:
1045: if ($strColumnName == 'Parent')
1046: return sprintf('Child%s', $strToReturn);
1047:
1048: return sprintf("%sAs%s",
1049: $strToReturn, $strColumnName);
1050:
1051: } else {
1052:
1053:
1054: if (($strColumnName == $strReferencedTableName) ||
1055: ($strColumnName == $strReferencedTableName . '_id'))
1056: return $strToReturn;
1057:
1058:
1059: $intLength = strlen($strColumnName);
1060: if (($intLength > 3) && (substr($strColumnName, $intLength - 3) == "_id"))
1061: $strColumnName = substr($strColumnName, 0, $intLength - 3);
1062:
1063:
1064: $strColumnName = str_replace($strReferencedTableName, "", $strColumnName);
1065:
1066:
1067: $strColumnName = str_replace("__", "_", $strColumnName);
1068: $strColumnName = str_replace("__", "_", $strColumnName);
1069:
1070: return sprintf("%sAs%s",
1071: $strToReturn,
1072: QConvertNotation::CamelCaseFromUnderscore($strColumnName));
1073: }
1074: }
1075:
1076:
1077: protected function CalculateObjectDescriptionForAssociation($strAssociationTableName, $strTableName, $strReferencedTableName, $blnPluralize) {
1078:
1079: $strTableName = $this->StripPrefixFromTable($strTableName);
1080: $strAssociationTableName = $this->StripPrefixFromTable($strAssociationTableName);
1081: $strReferencedTableName = $this->StripPrefixFromTable($strReferencedTableName);
1082:
1083:
1084: $strToReturn = QConvertNotation::CamelCaseFromUnderscore($strReferencedTableName);
1085:
1086: if ($blnPluralize)
1087: $strToReturn = $this->Pluralize($strToReturn);
1088:
1089:
1090:
1091:
1092: $strAssociationTableName = str_replace($this->strAssociationTableSuffix, '', $strAssociationTableName);
1093:
1094:
1095: $strTableName2 = str_replace('_', '', $strTableName);
1096: $strReferencedTableName2 = str_replace('_', '', $strReferencedTableName);
1097:
1098: if (beginsWith ($strAssociationTableName, $strTableName . '_')) {
1099: $strAssociationTableName = trimOffFront ($strTableName . '_', $strAssociationTableName);
1100: } elseif (beginsWith ($strAssociationTableName, $strTableName2 . '_')) {
1101: $strAssociationTableName = trimOffFront ($strTableName2 . '_', $strAssociationTableName);
1102: } elseif (beginsWith ($strAssociationTableName, $strReferencedTableName . '_')) {
1103: $strAssociationTableName = trimOffFront ($strReferencedTableName . '_', $strAssociationTableName);
1104: } elseif (beginsWith ($strAssociationTableName, $strReferencedTableName2 . '_')) {
1105: $strAssociationTableName = trimOffFront ($strReferencedTableName2 . '_', $strAssociationTableName);
1106: } elseif ($strAssociationTableName == $strTableName ||
1107: $strAssociationTableName == $strTableName2 ||
1108: $strAssociationTableName == $strReferencedTableName ||
1109: $strAssociationTableName == $strReferencedTableName2) {
1110: $strAssociationTableName = "";
1111: }
1112:
1113: if (endsWith ($strAssociationTableName, '_' . $strTableName)) {
1114: $strAssociationTableName = trimOffEnd ('_' . $strTableName, $strAssociationTableName);
1115: } elseif (endsWith ($strAssociationTableName, '_' . $strTableName2)) {
1116: $strAssociationTableName = trimOffEnd ('_' . $strTableName2, $strAssociationTableName);
1117: } elseif (endsWith ($strAssociationTableName, '_' . $strReferencedTableName)) {
1118: $strAssociationTableName = trimOffEnd ('_' . $strReferencedTableName, $strAssociationTableName);
1119: } elseif (endsWith ($strAssociationTableName, '_' . $strReferencedTableName2)) {
1120: $strAssociationTableName = trimOffEnd ('_' . $strReferencedTableName2, $strAssociationTableName);
1121: } elseif ($strAssociationTableName == $strTableName ||
1122: $strAssociationTableName == $strTableName2 ||
1123: $strAssociationTableName == $strReferencedTableName ||
1124: $strAssociationTableName == $strReferencedTableName2) {
1125: $strAssociationTableName = "";
1126: }
1127:
1128:
1129: $strAssociationTableName = str_replace("__", "_", $strAssociationTableName);
1130: $strAssociationTableName = str_replace("__", "_", $strAssociationTableName);
1131: $strAssociationTableName = str_replace("__", "_", $strAssociationTableName);
1132:
1133:
1134: if (($strAssociationTableName == "_") || ($strAssociationTableName == ""))
1135: return sprintf("%s%s%s",
1136: $this->strAssociatedObjectPrefix,
1137: $strToReturn,
1138: $this->strAssociatedObjectSuffix);
1139:
1140:
1141: return sprintf("%s%sAs%s%s",
1142: $this->strAssociatedObjectPrefix,
1143: $strToReturn,
1144: QConvertNotation::CamelCaseFromUnderscore($strAssociationTableName),
1145: $this->strAssociatedObjectSuffix);
1146: }
1147:
1148:
1149: protected function CalculateGraphPrefixArray($objForeignKeyArray) {
1150:
1151: if ((strpos(strtolower($objForeignKeyArray[0]->ColumnNameArray[0]), 'parent') !== false) ||
1152: (strpos(strtolower($objForeignKeyArray[1]->ColumnNameArray[0]), 'child') !== false)) {
1153: $strGraphPrefixArray[0] = '';
1154: $strGraphPrefixArray[1] = 'Parent';
1155: } else if ((strpos(strtolower($objForeignKeyArray[0]->ColumnNameArray[0]), 'child') !== false) ||
1156: (strpos(strtolower($objForeignKeyArray[1]->ColumnNameArray[0]), 'parent') !== false)) {
1157: $strGraphPrefixArray[0] = 'Parent';
1158: $strGraphPrefixArray[1] = '';
1159: } else {
1160:
1161: $strGraphPrefixArray[0] = 'Parent';
1162: $strGraphPrefixArray[1] = '';
1163: }
1164:
1165: return $strGraphPrefixArray;
1166: }
1167:
1168: 1169: 1170: 1171: 1172: 1173:
1174: protected function VariableTypeFromDbType($strDbType) {
1175: switch ($strDbType) {
1176: case QDatabaseFieldType::Bit:
1177: return QType::Boolean;
1178: case QDatabaseFieldType::Blob:
1179: return QType::String;
1180: case QDatabaseFieldType::Char:
1181: return QType::String;
1182: case QDatabaseFieldType::Date:
1183: return QType::DateTime;
1184: case QDatabaseFieldType::DateTime:
1185: return QType::DateTime;
1186: case QDatabaseFieldType::Float:
1187: return QType::Float;
1188: case QDatabaseFieldType::Integer:
1189: return QType::Integer;
1190: case QDatabaseFieldType::Time:
1191: return QType::DateTime;
1192: case QDatabaseFieldType::VarChar:
1193: return QType::String;
1194: case QDatabaseFieldType::Json:
1195: return QType::String;
1196: default:
1197: throw new Exception("Invalid Db Type to Convert: $strDbType");
1198: }
1199: }
1200:
1201: 1202: 1203: 1204: 1205: 1206: 1207:
1208: protected function Pluralize($strName) {
1209:
1210: switch (true) {
1211: case (strtolower($strName) == 'play'):
1212: return $strName . 's';
1213: }
1214:
1215: $intLength = strlen($strName);
1216: if (substr($strName, $intLength - 1) == "y")
1217: return substr($strName, 0, $intLength - 1) . "ies";
1218: if (substr($strName, $intLength - 1) == "s")
1219: return $strName . "es";
1220: if (substr($strName, $intLength - 1) == "x")
1221: return $strName . "es";
1222: if (substr($strName, $intLength - 1) == "z")
1223: return $strName . "zes";
1224: if (substr($strName, $intLength - 2) == "sh")
1225: return $strName . "es";
1226: if (substr($strName, $intLength - 2) == "ch")
1227: return $strName . "es";
1228:
1229: return $strName . "s";
1230: }
1231:
1232: public function ReportError ($strError) {
1233: $this->strErrors .= $strError . "\r\n";
1234: }
1235:
1236:
1237:
1238:
1239:
1240: 1241: 1242: 1243: 1244: 1245: 1246: 1247: 1248:
1249: public function __get($strName) {
1250: switch ($strName) {
1251: case 'Errors':
1252: return $this->strErrors;
1253: case 'Warnings':
1254: return $this->strWarnings;
1255: default:
1256: try {
1257: return parent::__get($strName);
1258: } catch (QCallerException $objExc) {
1259: $objExc->IncrementOffset();
1260: throw $objExc;
1261: }
1262: }
1263: }
1264:
1265: 1266: 1267: 1268: 1269: 1270: 1271:
1272: public function __set($strName, $mixValue) {
1273: try {
1274: switch($strName) {
1275: case 'Errors':
1276: return ($this->strErrors = QType::Cast($mixValue, QType::String));
1277: case 'Warnings':
1278: return ($this->strWarnings = QType::Cast($mixValue, QType::String));
1279: default:
1280: return parent::__set($strName, $mixValue);
1281: }
1282: } catch (QCallerException $objExc) {
1283: $objExc->IncrementOffset();
1284: }
1285: }
1286: }