1: <?php
2:
3: 4: 5: 6: 7:
8:
9:
10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
30: abstract class QQNode extends QBaseClass {
31:
32: protected $objParentNode;
33:
34: protected $strType;
35:
36: protected $strName;
37:
38: protected $strAlias;
39:
40: protected $strFullAlias;
41:
42: protected $strPropertyName;
43:
44: protected $strRootTableName;
45:
46: protected $strTableName;
47:
48:
49: protected $strPrimaryKey;
50:
51: protected $strClassName;
52:
53:
54:
55: protected $blnExpandAsArray;
56:
57: protected $objChildNodeArray;
58:
59: protected $blnIsType;
60:
61: abstract public function Join(QQueryBuilder $objBuilder, $blnExpandSelection = false, QQCondition $objJoinCondition = null, QQSelect $objSelect = null);
62:
63: 64: 65: 66:
67: public function GetType() {
68: return $this->strType;
69: }
70:
71: 72: 73: 74: 75: 76: 77:
78: public function SetAlias($strAlias) {
79: if ($this->strFullAlias) {
80: throw new Exception ("You cannot set an alias on a node after you have used it in a query. See the examples doc. You must set the alias while creating the node.");
81: }
82: try {
83:
84: $strNewAlias = QType::Cast($strAlias, QType::String);
85: if ($this->objParentNode) {
86: assert (is_object($this->objParentNode));
87: unset($this->objParentNode->objChildNodeArray[$this->strAlias]);
88: $this->objParentNode->objChildNodeArray[$strNewAlias] = $this;
89: }
90: $this->strAlias = $strNewAlias;
91: } catch (QCallerException $objExc) {
92: $objExc->IncrementOffset();
93: throw $objExc;
94: }
95: }
96:
97: 98: 99: 100: 101:
102: public function FullAlias() {
103: if ($this->strFullAlias) {
104: return $this->strFullAlias;
105: } else {
106: assert (!empty($this->strAlias));
107: if ($this->objParentNode) {
108: assert (is_object($this->objParentNode));
109: return $this->objParentNode->FullAlias() . '__' . $this->strAlias;
110: }
111: else {
112: return $this->strAlias;
113: }
114: }
115: }
116:
117: 118: 119: 120:
121: public function Fields() {return [];}
122:
123: 124: 125: 126:
127: public function PrimaryKeyFields() {return [];}
128:
129: 130: 131: 132: 133: 134: 135: 136: 137: 138:
139: public function _MergeExpansionNode (QQNode $objNewNode) {
140: if (!$objNewNode || empty($objNewNode->objChildNodeArray)) {
141: return;
142: }
143: if ($objNewNode->strName != $this->strName) {
144: throw new QCallerException('Expansion node tables must match.');
145: }
146:
147: if (!$this->objChildNodeArray) {
148: $this->objChildNodeArray = $objNewNode->objChildNodeArray;
149: } else {
150: $objChildNode = reset($objNewNode->objChildNodeArray);
151: if (isset ($this->objChildNodeArray[$objChildNode->strAlias])) {
152: if ($objChildNode->blnExpandAsArray) {
153: $this->objChildNodeArray[$objChildNode->strAlias]->blnExpandAsArray = true;
154:
155: }
156: else {
157: $this->objChildNodeArray[$objChildNode->strAlias]->_MergeExpansionNode ($objChildNode);
158: }
159: } else {
160: $this->objChildNodeArray[$objChildNode->strAlias] = $objChildNode;
161: }
162: }
163: }
164:
165: 166: 167: 168: 169: 170: 171:
172: public function PutSelectFields($objBuilder, $strPrefix = null, $objSelect = null) {
173: if ($strPrefix) {
174: $strTableName = $strPrefix;
175: $strAliasPrefix = $strPrefix . '__';
176: } else {
177: $strTableName = $this->strTableName;
178: $strAliasPrefix = '';
179: }
180:
181: if ($objSelect) {
182: if (!$objSelect->SkipPrimaryKey()) {
183: $strFields = $this->PrimaryKeyFields();
184: foreach ($strFields as $strField) {
185: $objBuilder->AddSelectItem($strTableName, $strField, $strAliasPrefix . $strField);
186: }
187: }
188: $objSelect->AddSelectItems($objBuilder, $strTableName, $strAliasPrefix);
189: } else {
190: $strFields = $this->Fields();
191: foreach ($strFields as $strField) {
192: $objBuilder->AddSelectItem($strTableName, $strField, $strAliasPrefix . $strField);
193: }
194: }
195: }
196:
197: 198: 199:
200: public function FirstChild() {
201: $a = $this->objChildNodeArray;
202: if ($a) {
203: return reset ($a);
204: } else {
205: return null;
206: }
207: }
208:
209: 210: 211: 212:
213: public function GetTable() {
214: return $this->FullAlias();
215: }
216:
217: 218: 219: 220: 221: 222: 223: 224:
225: public static function GetValue($mixValue, QQueryBuilder $objBuilder, $blnEqualityType = null) {
226: if ($mixValue instanceof QQNamedValue) {
227:
228: return $mixValue->Parameter($blnEqualityType);
229: }
230:
231: if ($mixValue instanceof QQNode) {
232:
233: if ($n = $mixValue->_PrimaryKeyNode) {
234: $mixValue = $n;
235: }
236:
237: if (is_null($blnEqualityType))
238: $strToReturn = '';
239: else if ($blnEqualityType)
240: $strToReturn = '= ';
241: else
242: $strToReturn = '!= ';
243:
244: try {
245: return $strToReturn . $mixValue->GetColumnAlias($objBuilder);
246: } catch (QCallerException $objExc) {
247: $objExc->IncrementOffset();
248: throw $objExc;
249: }
250: } else {
251: if (is_null($blnEqualityType)) {
252: $blnIncludeEquality = false;
253: $blnReverseEquality = false;
254: } else {
255: $blnIncludeEquality = true;
256: if ($blnEqualityType)
257: $blnReverseEquality = false;
258: else
259: $blnReverseEquality = true;
260: }
261:
262: return $objBuilder->Database->SqlVariable($mixValue, $blnIncludeEquality, $blnReverseEquality);
263: }
264: }
265:
266: public function __get($strName) {
267: switch ($strName) {
268: case '_ParentNode':
269: return $this->objParentNode;
270: case '_Name':
271: return $this->strName;
272: case '_Alias':
273: return $this->strAlias;
274: case '_PropertyName':
275: return $this->strPropertyName;
276: case '_Type':
277: return $this->strType;
278: case '_RootTableName':
279: return $this->strRootTableName;
280: case '_TableName':
281: return $this->strTableName;
282: case '_PrimaryKey':
283: return $this->strPrimaryKey;
284: case '_ClassName':
285: return $this->strClassName;
286: case '_PrimaryKeyNode':
287: return null;
288:
289: case 'ExpandAsArray':
290: return $this->blnExpandAsArray;
291: case 'IsType':
292: return $this->blnIsType;
293:
294: case 'ChildNodeArray':
295: return $this->objChildNodeArray;
296:
297: default:
298: try {
299: return parent::__get($strName);
300: } catch (QCallerException $objExc) {
301: $objExc->IncrementOffset();
302: throw $objExc;
303: }
304: }
305: }
306:
307: public function __set($strName, $mixValue) {
308: switch ($strName) {
309: case 'ExpandAsArray':
310: try {
311: return ($this->blnExpandAsArray = QType::Cast($mixValue, QType::Boolean));
312: } catch (QCallerException $objExc) {
313: $objExc->IncrementOffset();
314: throw $objExc;
315: }
316:
317: default:
318: try {
319: return parent::__set($strName, $mixValue);
320: } catch (QCallerException $objExc) {
321: $objExc->IncrementOffset();
322: throw $objExc;
323: }
324: }
325: }
326:
327:
328:
329:
330:
331:
332: 333: 334: 335:
336: public function GetDataGridHtml() {
337:
338: $objNodeArray = array();
339:
340: $objNodeArray[] = $this;
341: while ($objNodeArray[count($objNodeArray) - 1]->objParentNode)
342: $objNodeArray[] = $objNodeArray[count($objNodeArray) - 1]->objParentNode;
343:
344: $objNodeArray = array_reverse($objNodeArray, false);
345:
346:
347:
348:
349: if (count($objNodeArray) < 2)
350: throw new Exception('Invalid QQNode to GetDataGridHtml on');
351:
352:
353: else if (count($objNodeArray) == 2) {
354: $strToReturn = '$_ITEM->' . $objNodeArray[1]->strPropertyName;
355: if (class_exists($this->strClassName)) {
356: $strToReturn = sprintf('(%s) ? %s->__toString() : null;', $strToReturn, $strToReturn);
357: }
358: }
359:
360: else {
361: $strNodeLabelArray[0] = '$_ITEM->' . $objNodeArray[1]->strPropertyName;
362: for ($intIndex = 2; $intIndex < count($objNodeArray); $intIndex++) {
363: $strNodeLabelArray[$intIndex - 1] = $strNodeLabelArray[$intIndex - 2] . '->' . $objNodeArray[$intIndex]->strPropertyName;
364: }
365:
366: $slice_count = count ($objNodeArray) - 2;
367: $blnIsClass = class_exists($this->strClassName);
368:
369: if ($blnIsClass) {
370: $slice_count++;
371: }
372:
373: $aTest = array_slice ($strNodeLabelArray, 0, $slice_count);
374: $strTest = implode (' && ', $aTest);
375: $strLastNode = $strNodeLabelArray[count($strNodeLabelArray) - 1];
376:
377: if ($blnIsClass) {
378: return sprintf ('(%s) ? %s->__toString() : null', $strTest, $strLastNode);
379: } else {
380: $strToReturn = sprintf ('(%s) ? %s : null', $strTest, $strLastNode);
381: }
382: }
383:
384: if($this->strType == QDatabaseFieldType::Time)
385: return sprintf('(%s) ? %s->qFormat(QDateTime::$DefaultTimeFormat) : null', $strToReturn, $strToReturn);
386:
387: if ($this->strType == QDatabaseFieldType::Bit)
388: return sprintf('(null === %s)? "" : ((%s)? "%s" : "%s")', $strToReturn, $strToReturn, QApplication::Translate('True'), QApplication::Translate('False'));
389:
390:
391: return $strToReturn;
392: }
393:
394: public function GetDataGridOrderByNode() {
395: if ($this instanceof QQReverseReferenceNode)
396: return $this->_PrimaryKeyNode;
397: else
398: return $this;
399: }
400:
401: public function SetFilteredDataGridColumnFilter(QDataGridLegacyColumn $col)
402: {
403: if ($this->_PrimaryKeyNode) {
404: $objNode = $this->_PrimaryKeyNode;
405: } else {
406: $objNode = $this;
407: }
408:
409: switch($objNode->strType)
410: {
411: case QDatabaseFieldType::Bit:
412:
413: $col->FilterType = QFilterType::ListFilter;
414: $col->FilterAddListItem("True", QQ::Equal($objNode, true));
415: $col->FilterAddListItem("False", QQ::Equal($objNode, false));
416: $col->FilterAddListItem("Set", QQ::IsNotNull($objNode));
417: $col->FilterAddListItem("Unset", QQ::IsNull($objNode));
418: break;
419: case QDatabaseFieldType::Blob:
420: case QDatabaseFieldType::Char:
421: case QDatabaseFieldType::Time:
422: case QDatabaseFieldType::VarChar:
423: case QDatabaseFieldType::Date:
424: case QDatabaseFieldType::DateTime:
425:
426: $col->FilterType = QFilterType::TextFilter;
427: $col->FilterPrefix = '%';
428: $col->FilterPostfix = '%';
429: $col->Filter = QQ::Like($objNode, null);
430: break;
431: case QDatabaseFieldType::Float:
432: case QDatabaseFieldType::Integer:
433:
434: $col->FilterType = QFilterType::TextFilter;
435: $col->Filter = QQ::Equal($objNode, null);
436: break;
437: case QType::Object:
438: case QType::Resource:
439: default:
440:
441: $col->FilterType = QFilterType::None;
442: $col->ClearFilter();
443: break;
444: }
445: }
446:
447: }
448:
449: 450: 451: 452:
453: class QQColumnNode extends QQNode {
454: 455: 456: 457: 458: 459: 460:
461: public function __construct($strName, $strPropertyName, $strType, QQNode $objParentNode = null) {
462: $this->objParentNode = $objParentNode;
463: $this->strName = $strName;
464: $this->strAlias = $strName;
465: if ($objParentNode) $objParentNode->objChildNodeArray[$strName] = $this;
466:
467: $this->strPropertyName = $strPropertyName;
468: $this->strType = $strType;
469: if ($objParentNode) {
470: $this->strRootTableName = $objParentNode->strRootTableName;
471: } else
472: $this->strRootTableName = $strName;
473: }
474:
475: 476: 477:
478: public function GetColumnAlias(QQueryBuilder $objBuilder) {
479: $this->Join($objBuilder);
480: $strParentAlias = $this->objParentNode->FullAlias();
481: $strTableAlias = $objBuilder->GetTableAlias($strParentAlias);
482:
483: return $this->MakeColumnAlias($objBuilder, $strTableAlias);
484: }
485:
486: 487: 488:
489: public function MakeColumnAlias(QQueryBuilder $objBuilder, $strTableAlias) {
490: $strBegin = $objBuilder->Database->EscapeIdentifierBegin;
491: $strEnd = $objBuilder->Database->EscapeIdentifierEnd;
492:
493: return sprintf('%s%s%s.%s%s%s',
494: $strBegin, $strTableAlias, $strEnd,
495: $strBegin, $this->strName, $strEnd);
496: }
497:
498:
499: 500: 501:
502: public function GetTable() {
503: return $this->objParentNode->FullAlias();
504: }
505:
506: 507: 508: 509: 510: 511: 512: 513: 514:
515: public function Join(QQueryBuilder $objBuilder, $blnExpandSelection = false, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
516: $objParentNode = $this->objParentNode;
517: if (!$objParentNode) {
518: throw new QCallerException('A column node must have a parent node.');
519: } else {
520:
521: $objParentNode->Join($objBuilder, $blnExpandSelection, $objJoinCondition, $objSelect);
522: }
523: }
524:
525: 526: 527: 528:
529: public function GetAsManualSqlColumn() {
530: if ($this->strTableName)
531: return $this->strTableName . '.' . $this->strName;
532: else if (($this->objParentNode) && ($this->objParentNode->strTableName))
533: return $this->objParentNode->strTableName . '.' . $this->strName;
534: else
535: return $this->strName;
536: }
537:
538: }
539:
540: 541: 542: 543: 544:
545: abstract class QQTableNode extends QQNode {
546: 547: 548: 549: 550: 551: 552: 553:
554: public function __construct($strName, $strPropertyName = null, $strType = null, QQNode $objParentNode = null) {
555: $this->objParentNode = $objParentNode;
556: $this->strName = $strName;
557: $this->strAlias = $strName;
558: if ($objParentNode) $objParentNode->objChildNodeArray[$strName] = $this;
559:
560: $this->strPropertyName = $strPropertyName;
561: $this->strType = $strType;
562: if ($objParentNode) {
563: $this->strRootTableName = $objParentNode->strRootTableName;
564: } else
565: $this->strRootTableName = $strName;
566: }
567:
568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580:
581: public function Join(QQueryBuilder $objBuilder, $blnExpandSelection = false, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
582: $objParentNode = $this->objParentNode;
583: if (!$objParentNode) {
584: if ($this->strTableName != $objBuilder->RootTableName) {
585: throw new QCallerException('Cannot use QQNode for "' . $this->strTableName . '" when querying against the "' . $objBuilder->RootTableName . '" table', 3);
586: }
587: } else {
588:
589:
590:
591: if ($objJoinCondition &&
592: $this->objParentNode instanceof QQAssociationNode &&
593: $objJoinCondition->EqualTables($this->objParentNode->FullAlias())) {
594:
595: $objParentNode->Join($objBuilder, $blnExpandSelection, $objJoinCondition, $objSelect);
596: $objJoinCondition = null;
597: } else {
598: $objParentNode->Join($objBuilder, $blnExpandSelection, null, $objSelect);
599: if ($objJoinCondition && !$objJoinCondition->EqualTables($this->FullAlias())) {
600: throw new QCallerException("The join condition on the \"" . $this->strTableName . "\" table must only contain conditions for that table.");
601: }
602: }
603:
604: try {
605: $strParentAlias = $objParentNode->FullAlias();
606: $strAlias = $this->FullAlias();
607:
608: $objBuilder->AddJoinItem($this->strTableName, $strAlias,
609: $strParentAlias, $this->strName, $this->strPrimaryKey, $objJoinCondition);
610:
611: if ($blnExpandSelection) {
612: $this->PutSelectFields($objBuilder, $strAlias, $objSelect);
613: }
614: } catch (QCallerException $objExc) {
615: $objExc->IncrementOffset();
616: throw $objExc;
617: }
618: }
619: }
620: }
621:
622: 623: 624: 625: 626: 627:
628: class QQReverseReferenceNode extends QQTableNode {
629:
630: protected $strForeignKey;
631:
632: 633: 634: 635: 636: 637: 638: 639: 640: 641:
642: public function __construct(QQNode $objParentNode, $strName, $strType, $strForeignKey, $strPropertyName = null) {
643: parent::__construct($strName, $strPropertyName, $strType, $objParentNode);
644: if (!$objParentNode) {
645: throw new QCallerException('ReverseReferenceNodes must have a Parent Node');
646: }
647: $objParentNode->objChildNodeArray[$strName] = $this;
648: $this->strForeignKey = $strForeignKey;
649: }
650:
651: 652: 653: 654: 655:
656: public function IsUnique() {
657: return !empty($this->strPropertyName);
658: }
659:
660: 661: 662: 663: 664: 665: 666: 667: 668: 669:
670: public function Join(QQueryBuilder $objBuilder, $blnExpandSelection = false, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
671: $objParentNode = $this->objParentNode;
672: $objParentNode->Join($objBuilder, $blnExpandSelection, null, $objSelect);
673: if ($objJoinCondition && !$objJoinCondition->EqualTables($this->FullAlias())) {
674: throw new QCallerException("The join condition on the \"" . $this->strTableName . "\" table must only contain conditions for that table.");
675: }
676:
677: try {
678: $strParentAlias = $objParentNode->FullAlias();
679: $strAlias = $this->FullAlias();
680:
681: $objBuilder->AddJoinItem($this->strTableName, $strAlias,
682: $strParentAlias, $this->objParentNode->_PrimaryKey, $this->strForeignKey, $objJoinCondition);
683:
684: if ($blnExpandSelection) {
685: $this->PutSelectFields($objBuilder, $strAlias, $objSelect);
686: }
687: } catch (QCallerException $objExc) {
688: $objExc->IncrementOffset();
689: throw $objExc;
690: }
691: }
692:
693: }
694:
695: 696: 697: 698: 699:
700: class QQAssociationNode extends QQNode {
701: 702: 703: 704:
705: public function __construct(QQNode $objParentNode) {
706: $this->objParentNode = $objParentNode;
707: if ($objParentNode) {
708: $this->strRootTableName = $objParentNode->_RootTableName;
709: $this->strAlias = $this->strName;
710: $objParentNode->objChildNodeArray[$this->strAlias] = $this;
711: } else {
712: throw new Exception ("Association Nodes must always have a parent node");
713: }
714: }
715:
716: 717: 718: 719: 720: 721: 722: 723: 724: 725:
726: public function Join(QQueryBuilder $objBuilder, $blnExpandSelection = false, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
727: $objParentNode = $this->objParentNode;
728: $objParentNode->Join($objBuilder, $blnExpandSelection, null, $objSelect);
729: if ($objJoinCondition && !$objJoinCondition->EqualTables($this->FullAlias())) {
730: throw new QCallerException("The join condition on the \"" . $this->strTableName . "\" table must only contain conditions for that table.");
731: }
732:
733: try {
734: $strParentAlias = $objParentNode->FullAlias();
735: $strAlias = $this->FullAlias();
736:
737: $objBuilder->AddJoinItem($this->strTableName, $strAlias,
738: $strParentAlias, $objParentNode->_PrimaryKey, $this->strPrimaryKey, $objJoinCondition);
739:
740: if ($blnExpandSelection) {
741: $this->PutSelectFields($objBuilder, $strAlias, $objSelect);
742: }
743: } catch (QCallerException $objExc) {
744: $objExc->IncrementOffset();
745: throw $objExc;
746: }
747: }
748: }
749:
750:
751: 752: 753: 754: 755:
756: class QQNamedValue extends QQNode
757: {
758: const DelimiterCode = 3;
759:
760: 761: 762:
763: public function __construct($strName) {
764: $this->strName = $strName;
765: }
766:
767: 768: 769: 770:
771: public function Parameter($blnEqualityType = null)
772: {
773: if (is_null($blnEqualityType))
774: return chr(QQNamedValue::DelimiterCode) . '{' . $this->strName . '}';
775: else if ($blnEqualityType)
776: return chr(QQNamedValue::DelimiterCode) . '{=' . $this->strName . '=}';
777: else
778: return chr(QQNamedValue::DelimiterCode) . '{!' . $this->strName . '!}';
779: }
780:
781: 782: 783: 784: 785: 786:
787: public function Join(QQueryBuilder $objBuilder, $blnExpandSelection = false, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
788: assert(0);
789: }
790: }
791:
792: abstract class QQCondition extends QBaseClass {
793: protected $strOperator;
794: abstract public function UpdateQueryBuilder(QQueryBuilder $objBuilder);
795: public function __toString() {
796: return 'QQCondition Object';
797: }
798:
799: protected $blnProcessed;
800:
801: 802: 803: 804: 805: 806: 807: 808: 809: 810:
811: public function GetWhereClause(QQueryBuilder $objBuilder, $blnProcessOnce = false) {
812: if ($blnProcessOnce && $this->blnProcessed)
813: return null;
814:
815: $this->blnProcessed = true;
816:
817: try {
818: $objConditionBuilder = new QPartialQueryBuilder($objBuilder);
819: $this->UpdateQueryBuilder($objConditionBuilder);
820: return $objConditionBuilder->GetWhereStatement();
821: } catch (QCallerException $objExc) {
822: $objExc->IncrementOffset();
823: $objExc->IncrementOffset();
824: throw $objExc;
825: }
826: }
827:
828: 829: 830: 831:
832: public function EqualTables($strTableName) {
833: return true;
834: }
835: }
836: class QQConditionAll extends QQCondition {
837: 838: 839: 840:
841: public function __construct($mixParameterArray) {
842: if (count($mixParameterArray))
843: throw new QCallerException('All clause takes in no parameters', 3);
844: }
845:
846: 847: 848:
849: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
850: $objBuilder->AddWhereItem('1=1');
851: }
852: }
853: class QQConditionNone extends QQCondition {
854: 855: 856: 857:
858: public function __construct($mixParameterArray) {
859: if (count($mixParameterArray))
860: throw new QCallerException('None clause takes in no parameters', 3);
861: }
862: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
863: $objBuilder->AddWhereItem('1=0');
864: }
865: }
866: abstract class QQConditionLogical extends QQCondition {
867:
868: protected $objConditionArray;
869: protected function CollapseConditions($mixParameterArray) {
870: $objConditionArray = array();
871: foreach ($mixParameterArray as $mixParameter) {
872: if (is_array($mixParameter))
873: $objConditionArray = array_merge($objConditionArray, $mixParameter);
874: else
875: array_push($objConditionArray, $mixParameter);
876: }
877:
878: foreach ($objConditionArray as $objCondition)
879: if (!($objCondition instanceof QQCondition))
880: throw new QCallerException('Logical Or/And clause parameters must all be QQCondition objects', 3);
881:
882: if (count($objConditionArray))
883: return $objConditionArray;
884: else
885: throw new QCallerException('No parameters passed in to logical Or/And clause', 3);
886: }
887: public function __construct($mixParameterArray) {
888: $objConditionArray = $this->CollapseConditions($mixParameterArray);
889: try {
890: $this->objConditionArray = QType::Cast($objConditionArray, QType::ArrayType);
891: } catch (QCallerException $objExc) {
892: $objExc->IncrementOffset();
893: throw $objExc;
894: }
895: }
896: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
897: $intLength = count($this->objConditionArray);
898: if ($intLength) {
899: $objBuilder->AddWhereItem('(');
900: for ($intIndex = 0; $intIndex < $intLength; $intIndex++) {
901: if (!($this->objConditionArray[$intIndex] instanceof QQCondition))
902: throw new QCallerException($this->strOperator . ' clause has elements that are not Conditions');
903: try {
904: $this->objConditionArray[$intIndex]->UpdateQueryBuilder($objBuilder);
905: } catch (QCallerException $objExc) {
906: $objExc->IncrementOffset();
907: throw $objExc;
908: }
909: if (($intIndex + 1) != $intLength)
910: $objBuilder->AddWhereItem($this->strOperator);
911: }
912: $objBuilder->AddWhereItem(')');
913: }
914: }
915:
916: public function EqualTables($strTableName) {
917: foreach ($this->objConditionArray as $objCondition) {
918: if (!$objCondition->EqualTables($strTableName)) {
919: return false;
920: }
921: }
922: return true;
923: }
924: }
925: class QQConditionOr extends QQConditionLogical {
926: protected $strOperator = 'OR';
927: }
928: class QQConditionAnd extends QQConditionLogical {
929: protected $strOperator = 'AND';
930: }
931:
932: class QQConditionNot extends QQCondition {
933: protected $objCondition;
934: public function __construct(QQCondition $objCondition) {
935: $this->objCondition = $objCondition;
936: }
937: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
938: $objBuilder->AddWhereItem('(NOT');
939: try {
940: $this->objCondition->UpdateQueryBuilder($objBuilder);
941: } catch (QCallerException $objExc) {
942: $objExc->IncrementOffset();
943: throw $objExc;
944: }
945: $objBuilder->AddWhereItem(')');
946: }
947: }
948:
949: abstract class QQConditionComparison extends QQCondition {
950:
951: public $objQueryNode;
952: public $mixOperand;
953:
954: 955: 956: 957: 958:
959: public function __construct(QQColumnNode $objQueryNode, $mixOperand = null) {
960: $this->objQueryNode = $objQueryNode;
961:
962: if ($mixOperand instanceof QQNamedValue || $mixOperand === null)
963: $this->mixOperand = $mixOperand;
964: else if ($mixOperand instanceof QQAssociationNode)
965: throw new QInvalidCastException('Comparison operand cannot be an Association-based QQNode', 3);
966: else if ($mixOperand instanceof QQCondition)
967: throw new QInvalidCastException('Comparison operand cannot be a QQCondition', 3);
968: else if ($mixOperand instanceof QQClause)
969: throw new QInvalidCastException('Comparison operand cannot be a QQClause', 3);
970: else if (!($mixOperand instanceof QQNode)) {
971: $this->mixOperand = $mixOperand;
972: } else {
973: if (!($mixOperand instanceof QQColumnNode))
974: throw new QInvalidCastException('Unable to cast "' . $mixOperand->_Name . '" table to Column-based QQNode', 3);
975: $this->mixOperand = $mixOperand;
976: }
977: }
978: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
979: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . $this->strOperator . QQNode::GetValue($this->mixOperand, $objBuilder));
980: }
981:
982: 983: 984: 985: 986:
987: public function EqualTables($strTableName) {
988: return $this->objQueryNode->GetTable() == $strTableName;
989: }
990: }
991:
992: 993: 994: 995:
996: class QQConditionIsNull extends QQConditionComparison {
997: 998: 999:
1000: public function __construct(QQColumnNode $objQueryNode) {
1001: parent::__construct($objQueryNode);
1002: }
1003:
1004: 1005: 1006:
1007: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1008: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' IS NULL');
1009: }
1010: }
1011:
1012: class QQConditionIsNotNull extends QQConditionComparison {
1013: public function __construct(QQColumnNode $objQueryNode) {
1014: parent::__construct($objQueryNode);
1015: }
1016:
1017: 1018: 1019:
1020: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1021: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' IS NOT NULL');
1022: }
1023: }
1024:
1025: class QQConditionIn extends QQConditionComparison {
1026: 1027: 1028: 1029: 1030: 1031: 1032:
1033: public function __construct(QQColumnNode $objQueryNode, $mixValuesArray) {
1034: parent::__construct($objQueryNode);
1035:
1036: if ($mixValuesArray instanceof QQNamedValue)
1037: $this->mixOperand = $mixValuesArray;
1038: else if ($mixValuesArray instanceof QQSubQueryNode)
1039: $this->mixOperand = $mixValuesArray;
1040: else {
1041: try {
1042: $this->mixOperand = QType::Cast($mixValuesArray, QType::ArrayType);
1043: } catch (QCallerException $objExc) {
1044: $objExc->IncrementOffset();
1045: $objExc->IncrementOffset();
1046: throw $objExc;
1047: }
1048: }
1049: }
1050:
1051: 1052: 1053:
1054: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1055: $mixOperand = $this->mixOperand;
1056: if ($mixOperand instanceof QQNamedValue) {
1057:
1058: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' IN (' . $mixOperand->Parameter() . ')');
1059: } else if ($mixOperand instanceof QQSubQueryNode) {
1060:
1061: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' IN ' . $mixOperand->GetColumnAlias($objBuilder));
1062: } else {
1063: $strParameters = array();
1064: foreach ($mixOperand as $mixParameter) {
1065: array_push($strParameters, $objBuilder->Database->SqlVariable($mixParameter));
1066: }
1067: if (count($strParameters))
1068: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' IN (' . implode(',', $strParameters) . ')');
1069: else
1070: $objBuilder->AddWhereItem('1=0');
1071: }
1072: }
1073: }
1074:
1075: class QQConditionNotIn extends QQConditionComparison {
1076: 1077: 1078: 1079: 1080: 1081:
1082: public function __construct(QQColumnNode $objQueryNode, $mixValuesArray) {
1083: parent::__construct($objQueryNode);
1084:
1085: if ($mixValuesArray instanceof QQNamedValue)
1086: $this->mixOperand = $mixValuesArray;
1087: else if ($mixValuesArray instanceof QQSubQueryNode)
1088: $this->mixOperand = $mixValuesArray;
1089: else {
1090: try {
1091: $this->mixOperand = QType::Cast($mixValuesArray, QType::ArrayType);
1092: } catch (QCallerException $objExc) {
1093: $objExc->IncrementOffset();
1094: $objExc->IncrementOffset();
1095: throw $objExc;
1096: }
1097: }
1098: }
1099:
1100: 1101: 1102:
1103: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1104: $mixOperand = $this->mixOperand;
1105: if ($mixOperand instanceof QQNamedValue) {
1106:
1107: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT IN (' . $mixOperand->Parameter() . ')');
1108: } else if ($mixOperand instanceof QQSubQueryNode) {
1109:
1110: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT IN ' . $mixOperand->GetColumnAlias($objBuilder));
1111: } else {
1112: $strParameters = array();
1113: foreach ($mixOperand as $mixParameter) {
1114: array_push($strParameters, $objBuilder->Database->SqlVariable($mixParameter));
1115: }
1116: if (count($strParameters))
1117: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT IN (' . implode(',', $strParameters) . ')');
1118: else
1119: $objBuilder->AddWhereItem('1=1');
1120: }
1121: }
1122: }
1123:
1124: class QQConditionLike extends QQConditionComparison {
1125: 1126: 1127: 1128: 1129: 1130: 1131:
1132: public function __construct(QQColumnNode $objQueryNode, $strValue) {
1133: parent::__construct($objQueryNode);
1134:
1135: if ($strValue instanceof QQNamedValue)
1136: $this->mixOperand = $strValue;
1137: else {
1138: try {
1139: $this->mixOperand = QType::Cast($strValue, QType::String);
1140: } catch (QCallerException $objExc) {
1141: $objExc->IncrementOffset();
1142: $objExc->IncrementOffset();
1143: throw $objExc;
1144: }
1145: }
1146: }
1147:
1148: 1149: 1150:
1151: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1152: $mixOperand = $this->mixOperand;
1153: if ($mixOperand instanceof QQNamedValue) {
1154:
1155: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' LIKE ' . $mixOperand->Parameter());
1156: } else {
1157: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' LIKE ' . $objBuilder->Database->SqlVariable($mixOperand));
1158: }
1159: }
1160: }
1161:
1162: class QQConditionNotLike extends QQConditionComparison {
1163: 1164: 1165: 1166: 1167: 1168:
1169: public function __construct(QQColumnNode $objQueryNode, $strValue) {
1170: parent::__construct($objQueryNode);
1171:
1172: if ($strValue instanceof QQNamedValue)
1173: $this->mixOperand = $strValue;
1174: else {
1175: try {
1176: $this->mixOperand = QType::Cast($strValue, QType::String);
1177: } catch (QCallerException $objExc) {
1178: $objExc->IncrementOffset();
1179: $objExc->IncrementOffset();
1180: throw $objExc;
1181: }
1182: }
1183: }
1184:
1185: 1186: 1187:
1188: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1189: $mixOperand = $this->mixOperand;
1190: if ($mixOperand instanceof QQNamedValue) {
1191:
1192: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT LIKE ' . $mixOperand->Parameter());
1193: } else {
1194: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT LIKE ' . $objBuilder->Database->SqlVariable($mixOperand));
1195: }
1196: }
1197: }
1198:
1199: class QQConditionBetween extends QQConditionComparison {
1200:
1201: protected $mixOperandTwo;
1202:
1203: 1204: 1205: 1206: 1207: 1208: 1209:
1210: public function __construct(QQColumnNode $objQueryNode, $mixMinValue, $mixMaxValue) {
1211: parent::__construct($objQueryNode);
1212: try {
1213: $this->mixOperand = $mixMinValue;
1214: $this->mixOperandTwo = $mixMaxValue;
1215: } catch (QCallerException $objExc) {
1216: $objExc->IncrementOffset();
1217: $objExc->IncrementOffset();
1218: throw $objExc;
1219: }
1220: }
1221:
1222: 1223: 1224:
1225: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1226: $mixOperand = $this->mixOperand;
1227: $mixOperandTwo = $this->mixOperandTwo;
1228: if ($mixOperand instanceof QQNamedValue) {
1229:
1230:
1231: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' BETWEEN ' . $mixOperand->Parameter() . ' AND ' . $mixOperandTwo->Parameter());
1232: } else {
1233: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' BETWEEN ' . $objBuilder->Database->SqlVariable($mixOperand) . ' AND ' . $objBuilder->Database->SqlVariable($mixOperandTwo));
1234: }
1235: }
1236: }
1237:
1238: class QQConditionNotBetween extends QQConditionComparison {
1239:
1240: protected $mixOperandTwo;
1241:
1242: 1243: 1244: 1245: 1246: 1247: 1248:
1249: public function __construct(QQColumnNode $objQueryNode, $strMinValue, $strMaxValue) {
1250: parent::__construct($objQueryNode);
1251: try {
1252: $this->mixOperand = QType::Cast($strMinValue, QType::String);
1253: $this->mixOperandTwo = QType::Cast($strMaxValue, QType::String);
1254: } catch (QCallerException $objExc) {
1255: $objExc->IncrementOffset();
1256: $objExc->IncrementOffset();
1257: throw $objExc;
1258: }
1259:
1260: if ($strMinValue instanceof QQNamedValue)
1261: $this->mixOperand = $strMinValue;
1262: if ($strMaxValue instanceof QQNamedValue)
1263: $this->mixOperandTwo = $strMaxValue;
1264:
1265: }
1266:
1267: 1268: 1269:
1270: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1271: $mixOperand = $this->mixOperand;
1272: $mixOperandTwo = $this->mixOperandTwo;
1273: if ($mixOperand instanceof QQNamedValue) {
1274:
1275:
1276: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT BETWEEN ' . $mixOperand->Parameter() . ' AND ' . $mixOperandTwo->Parameter());
1277: } else {
1278: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' NOT BETWEEN ' . $objBuilder->Database->SqlVariable($mixOperand) . ' AND ' . $objBuilder->Database->SqlVariable($mixOperandTwo));
1279: }
1280: }
1281: }
1282:
1283: class QQConditionEqual extends QQConditionComparison {
1284: protected $strOperator = ' = ';
1285:
1286: 1287: 1288: 1289: 1290:
1291: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1292: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' ' . QQNode::GetValue($this->mixOperand, $objBuilder, true));
1293: }
1294: }
1295: class QQConditionNotEqual extends QQConditionComparison {
1296: protected $strOperator = ' != ';
1297:
1298: 1299: 1300: 1301: 1302:
1303: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1304: $objBuilder->AddWhereItem($this->objQueryNode->GetColumnAlias($objBuilder) . ' ' . QQNode::GetValue($this->mixOperand, $objBuilder, false));
1305: }
1306: }
1307:
1308: class QQConditionExists extends QQCondition {
1309:
1310: protected $objNode;
1311:
1312: 1313: 1314:
1315: public function __construct(QQSubQuerySqlNode $objNode) {
1316: $this->objNode = $objNode;
1317: }
1318:
1319: 1320: 1321:
1322: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1323: $objBuilder->AddWhereItem('EXISTS ' . $this->objNode->GetColumnAlias($objBuilder));
1324: }
1325: }
1326:
1327: class QQConditionNotExists extends QQCondition {
1328:
1329: protected $objNode;
1330:
1331: 1332: 1333:
1334: public function __construct(QQSubQuerySqlNode $objNode) {
1335: $this->objNode = $objNode;
1336: }
1337:
1338: 1339: 1340:
1341: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
1342: $objBuilder->AddWhereItem('NOT EXISTS ' . $this->objNode->GetColumnAlias($objBuilder));
1343: }
1344: }
1345:
1346:
1347:
1348: class QQConditionGreaterThan extends QQConditionComparison {
1349: protected $strOperator = ' > ';
1350: }
1351: class QQConditionLessThan extends QQConditionComparison {
1352: protected $strOperator = ' < ';
1353: }
1354: class QQConditionGreaterOrEqual extends QQConditionComparison {
1355: protected $strOperator = ' >= ';
1356: }
1357: class QQConditionLessOrEqual extends QQConditionComparison {
1358: protected $strOperator = ' <= ';
1359: }
1360:
1361: class QQ {
1362:
1363:
1364:
1365:
1366: static public function All() {
1367: return new QQConditionAll(func_get_args());
1368: }
1369:
1370: static public function None() {
1371: return new QQConditionNone(func_get_args());
1372: }
1373:
1374: static public function OrCondition() {
1375: return new QQConditionOr(func_get_args());
1376: }
1377:
1378: static public function AndCondition() {
1379: return new QQConditionAnd(func_get_args());
1380: }
1381:
1382: static public function Not(QQCondition $objCondition) {
1383: return new QQConditionNot($objCondition);
1384: }
1385:
1386: static public function Equal(QQColumnNode $objQueryNode, $mixValue) {
1387: return new QQConditionEqual($objQueryNode, $mixValue);
1388: }
1389: static public function NotEqual(QQColumnNode $objQueryNode, $mixValue) {
1390: return new QQConditionNotEqual($objQueryNode, $mixValue);
1391: }
1392: static public function GreaterThan(QQColumnNode $objQueryNode, $mixValue) {
1393: return new QQConditionGreaterThan($objQueryNode, $mixValue);
1394: }
1395: static public function GreaterOrEqual(QQColumnNode $objQueryNode, $mixValue) {
1396: return new QQConditionGreaterOrEqual($objQueryNode, $mixValue);
1397: }
1398: static public function LessThan(QQColumnNode $objQueryNode, $mixValue) {
1399: return new QQConditionLessThan($objQueryNode, $mixValue);
1400: }
1401: static public function LessOrEqual(QQColumnNode $objQueryNode, $mixValue) {
1402: return new QQConditionLessOrEqual($objQueryNode, $mixValue);
1403: }
1404: static public function IsNull(QQColumnNode $objQueryNode) {
1405: return new QQConditionIsNull($objQueryNode);
1406: }
1407: static public function IsNotNull(QQColumnNode $objQueryNode) {
1408: return new QQConditionIsNotNull($objQueryNode);
1409: }
1410: static public function In(QQColumnNode $objQueryNode, $mixValuesArray) {
1411: return new QQConditionIn($objQueryNode, $mixValuesArray);
1412: }
1413: static public function NotIn(QQColumnNode $objQueryNode, $mixValuesArray) {
1414: return new QQConditionNotIn($objQueryNode, $mixValuesArray);
1415: }
1416: static public function Like(QQColumnNode $objQueryNode, $strValue) {
1417: return new QQConditionLike($objQueryNode, $strValue);
1418: }
1419: static public function NotLike(QQColumnNode $objQueryNode, $strValue) {
1420: return new QQConditionNotLike($objQueryNode, $strValue);
1421: }
1422: static public function Between(QQColumnNode $objQueryNode, $mixMinValue, $mixMaxValue) {
1423: return new QQConditionBetween($objQueryNode, $mixMinValue, $mixMaxValue);
1424: }
1425: static public function NotBetween(QQColumnNode $objQueryNode, $strMinValue, $strMaxValue) {
1426: return new QQConditionNotBetween($objQueryNode, $strMinValue, $strMaxValue);
1427: }
1428: static public function Exists(QQSubQuerySqlNode $objQueryNode) {
1429: return new QQConditionExists($objQueryNode);
1430: }
1431: static public function NotExists(QQSubQuerySqlNode $objQueryNode) {
1432: return new QQConditionNotExists($objQueryNode);
1433: }
1434:
1435:
1436:
1437:
1438:
1439: 1440: 1441: 1442: 1443: 1444: 1445: 1446: 1447:
1448: static public function _(QQColumnNode $objQueryNode, $strSymbol, $mixValue = null, $mixValueTwo = null) {
1449: try {
1450: switch(strtolower(trim($strSymbol))) {
1451: case '=': return QQ::Equal($objQueryNode, $mixValue);
1452: case '!=': return QQ::NotEqual($objQueryNode, $mixValue);
1453: case '>': return QQ::GreaterThan($objQueryNode, $mixValue);
1454: case '<': return QQ::LessThan($objQueryNode, $mixValue);
1455: case '>=': return QQ::GreaterOrEqual($objQueryNode, $mixValue);
1456: case '<=': return QQ::LessOrEqual($objQueryNode, $mixValue);
1457: case 'in': return QQ::In($objQueryNode, $mixValue);
1458: case 'not in': return QQ::NotIn($objQueryNode, $mixValue);
1459: case 'like': return QQ::Like($objQueryNode, $mixValue);
1460: case 'not like': return QQ::NotLike($objQueryNode, $mixValue);
1461: case 'is null': return QQ::IsNull($objQueryNode);
1462: case 'is not null': return QQ::IsNotNull($objQueryNode);
1463: case 'between': return QQ::Between($objQueryNode, $mixValue, $mixValueTwo);
1464: case 'not between': return QQ::NotBetween($objQueryNode, $mixValue, $mixValueTwo);
1465: default:
1466: throw new QCallerException('Unknown Query Comparison Operation: ' . $strSymbol, 0);
1467: }
1468: } catch (QCallerException $objExc) {
1469: $objExc->IncrementOffset();
1470: throw $objExc;
1471: }
1472: }
1473:
1474:
1475:
1476:
1477:
1478: 1479: 1480: 1481: 1482:
1483: static public function SubSql($strSql, $objParentQueryNodes = null) {
1484: $objParentQueryNodeArray = func_get_args();
1485: return new QQSubQuerySqlNode($strSql, $objParentQueryNodeArray);
1486: }
1487:
1488: static public function Virtual($strName, QQSubQueryNode $objSubQueryDefinition = null) {
1489: return new QQVirtualNode($strName, $objSubQueryDefinition);
1490: }
1491:
1492: 1493: 1494: 1495: 1496: 1497: 1498: 1499:
1500: static public function GetVirtualAlias($strName) {
1501: $strName = trim($strName);
1502: $strName = str_replace(" ", "_", $strName);
1503: $strName = strtolower($strName);
1504: return $strName;
1505: }
1506:
1507:
1508:
1509:
1510:
1511: static public function Clause() {
1512: $objClauseArray = array();
1513:
1514: foreach (func_get_args() as $objClause)
1515: if ($objClause) {
1516: if (!($objClause instanceof QQClause))
1517: throw new QCallerException('Non-QQClause object was passed in to QQ::Clause');
1518: else
1519: array_push($objClauseArray, $objClause);
1520: }
1521:
1522: return $objClauseArray;
1523: }
1524:
1525: static public function OrderBy() {
1526: return new QQOrderBy(func_get_args());
1527: }
1528:
1529: static public function GroupBy() {
1530: return new QQGroupBy(func_get_args());
1531: }
1532:
1533: static public function Having(QQSubQuerySqlNode $objNode) {
1534: return new QQHavingClause($objNode);
1535: }
1536:
1537: static public function Count(QQColumnNode $objNode, $strAttributeName) {
1538: return new QQCount($objNode, $strAttributeName);
1539: }
1540:
1541: static public function Sum(QQColumnNode $objNode, $strAttributeName) {
1542: return new QQSum($objNode, $strAttributeName);
1543: }
1544:
1545: static public function Minimum(QQColumnNode $objNode, $strAttributeName) {
1546: return new QQMinimum($objNode, $strAttributeName);
1547: }
1548:
1549: static public function Maximum(QQColumnNode $objNode, $strAttributeName) {
1550: return new QQMaximum($objNode, $strAttributeName);
1551: }
1552:
1553: static public function Average(QQColumnNode $objNode, $strAttributeName) {
1554: return new QQAverage($objNode, $strAttributeName);
1555: }
1556:
1557: static public function Expand(QQNode $objNode, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
1558:
1559:
1560:
1561: if ($objNode instanceof QQVirtualNode)
1562: return new QQExpandVirtualNode($objNode);
1563: else
1564: return new QQExpand($objNode, $objJoinCondition, $objSelect);
1565: }
1566:
1567: static public function ExpandAsArray(QQNode $objNode, $objCondition = null, QQSelect $objSelect = null) {
1568: return new QQExpandAsArray($objNode, $objCondition, $objSelect);
1569: }
1570:
1571: static public function Select() {
1572: if (func_num_args() == 1 && is_array($a = func_get_arg(0))) {
1573: return new QQSelect($a);
1574: } else {
1575: return new QQSelect(func_get_args());
1576: }
1577: }
1578:
1579: static public function LimitInfo($intMaxRowCount, $intOffset = 0) {
1580: return new QQLimitInfo($intMaxRowCount, $intOffset);
1581: }
1582:
1583: static public function Distinct() {
1584: return new QQDistinct();
1585: }
1586:
1587: 1588: 1589: 1590: 1591: 1592: 1593: 1594:
1595: public static function ExtractSelectClause($objClauses) {
1596: if ($objClauses instanceof QQSelect)
1597: return $objClauses;
1598:
1599: if (is_array($objClauses)) {
1600: $hasSelects = false;
1601: $objSelect = QQuery::Select();
1602: foreach ($objClauses as $objClause) {
1603: if ($objClause instanceof QQSelect) {
1604: $hasSelects = true;
1605: $objSelect->Merge($objClause);
1606: }
1607: }
1608: if (!$hasSelects)
1609: return null;
1610: return $objSelect;
1611: }
1612: return null;
1613: }
1614:
1615:
1616:
1617:
1618: 1619: 1620: 1621: 1622: 1623: 1624: 1625:
1626: static public function Alias(QQNode $objNode, $strAlias)
1627: {
1628: $objNode->SetAlias($strAlias);
1629: return $objNode;
1630: }
1631:
1632:
1633:
1634:
1635: static public function NamedValue($strName) {
1636: return new QQNamedValue($strName);
1637: }
1638:
1639: 1640: 1641: 1642: 1643: 1644: 1645: 1646: 1647: 1648:
1649: static public function Func($strName, $param1 ) {
1650: $args = func_get_args();
1651: $strFunc = array_shift($args);
1652: return new QQFunctionNode($strFunc, $args);
1653: }
1654:
1655:
1656:
1657:
1658:
1659: 1660: 1661: 1662: 1663: 1664:
1665: static public function Abs($param) {
1666: return QQ::Func('ABS', $param);
1667: }
1668: 1669: 1670: 1671: 1672: 1673:
1674: static public function Ceil($param) {
1675: return QQ::Func('CEIL', $param);
1676: }
1677: 1678: 1679: 1680: 1681: 1682:
1683: static public function Floor($param) {
1684: return QQ::Func('FLOOR', $param);
1685: }
1686: 1687: 1688: 1689: 1690: 1691:
1692: static public function Mod($dividend, $divider) {
1693: return QQ::Func('MOD', $dividend, $divider);
1694: }
1695: 1696: 1697: 1698: 1699: 1700:
1701: static public function Power($base, $exponent) {
1702: return QQ::Func('POWER', $base, $exponent);
1703: }
1704: 1705: 1706: 1707: 1708: 1709:
1710: static public function Sqrt($param) {
1711: return QQ::Func('SQRT', $param);
1712: }
1713:
1714: 1715: 1716: 1717: 1718: 1719: 1720:
1721: static public function MathOp($strOperation, $param1 ) {
1722: $args = func_get_args();
1723: $strFunc = array_shift($args);
1724: return new QQMathNode($strFunc, $args);
1725: }
1726:
1727: 1728: 1729: 1730: 1731: 1732: 1733:
1734: static public function Mul($op1, $op2 ) {
1735: return new QQMathNode('*', func_get_args());
1736: }
1737: 1738: 1739: 1740: 1741: 1742: 1743:
1744: static public function Div($op1, $op2 ) {
1745: return new QQMathNode('/', func_get_args());
1746: }
1747: 1748: 1749: 1750: 1751: 1752: 1753:
1754: static public function Sub($op1, $op2 ) {
1755: return new QQMathNode('-', func_get_args());
1756: }
1757: 1758: 1759: 1760: 1761: 1762: 1763:
1764: static public function Add($op1, $op2 ) {
1765: return new QQMathNode('+', func_get_args());
1766: }
1767: 1768: 1769: 1770: 1771: 1772:
1773: static public function Neg($op1) {
1774: return new QQMathNode('-', [$op1]);
1775: }
1776:
1777: }
1778:
1779: abstract class QQSubQueryNode extends QQColumnNode {
1780: }
1781:
1782: abstract class QQNoParentNode extends QQSubQueryNode {
1783: 1784: 1785:
1786: public function GetTable() {
1787: return $this->FullAlias();
1788: }
1789: 1790: 1791: 1792: 1793: 1794: 1795:
1796: public function SetAlias($strAlias) {
1797: if ($this->strFullAlias) {
1798: throw new Exception ("You cannot set an alias on a node after you have used it in a query. See the examples doc. You must set the alias while creating the node.");
1799: }
1800: try {
1801:
1802: $strNewAlias = QType::Cast($strAlias, QType::String);
1803: $this->strAlias = $strNewAlias;
1804: } catch (QCallerException $objExc) {
1805: $objExc->IncrementOffset();
1806: throw $objExc;
1807: }
1808: }
1809: 1810: 1811: 1812: 1813:
1814: public function FullAlias() {
1815: if ($this->strFullAlias) {
1816: return $this->strFullAlias;
1817: } else {
1818: assert (!empty($this->strAlias));
1819: return $this->strAlias;
1820: }
1821: }
1822: }
1823:
1824: class QQSubQueryCountNode extends QQSubQueryNode {
1825: protected $strFunctionName = 'COUNT';
1826: }
1827:
1828: class QQSubQuerySqlNode extends QQNoParentNode {
1829: protected $strSql;
1830:
1831: protected $objParentQueryNodes;
1832: 1833: 1834: 1835:
1836: public function __construct($strSql, $objParentQueryNodes = null) {
1837: parent::__construct('', '', '');
1838: $this->objParentNode = true;
1839: $this->objParentQueryNodes = $objParentQueryNodes;
1840: $this->strSql = $strSql;
1841: }
1842:
1843: 1844: 1845: 1846:
1847: public function GetColumnAlias(QQueryBuilder $objBuilder) {
1848: $strSql = $this->strSql;
1849: for ($intIndex = 1; $intIndex < count($this->objParentQueryNodes); $intIndex++) {
1850: if (!is_null($this->objParentQueryNodes[$intIndex]))
1851: $strSql = str_replace('{' . $intIndex . '}', $this->objParentQueryNodes[$intIndex]->GetColumnAlias($objBuilder), $strSql);
1852: }
1853: return '(' . $strSql . ')';
1854: }
1855: }
1856:
1857: class QQVirtualNode extends QQNoParentNode {
1858: protected $objSubQueryDefinition;
1859:
1860: 1861: 1862: 1863:
1864: public function __construct($strName, QQSubQueryNode $objSubQueryDefinition = null) {
1865: parent::__construct('', '', '');
1866: $this->objParentNode = true;
1867: $this->strName = QQ::GetVirtualAlias($strName);
1868: $this->strAlias = $this->strName;
1869: $this->objSubQueryDefinition = $objSubQueryDefinition;
1870: }
1871:
1872: 1873: 1874: 1875: 1876: 1877:
1878: public function GetColumnAlias(QQueryBuilder $objBuilder) {
1879: if ($this->objSubQueryDefinition) {
1880: $objBuilder->SetVirtualNode($this->strName, $this->objSubQueryDefinition);
1881: return $this->objSubQueryDefinition->GetColumnAlias($objBuilder);
1882: } else {
1883: try {
1884: $objNode = $objBuilder->GetVirtualNode($this->strName);
1885: return $objNode->GetColumnAlias($objBuilder);
1886: } catch (QCallerException $objExc) {
1887: $objExc->IncrementOffset();
1888: $objExc->IncrementOffset();
1889: throw $objExc;
1890: }
1891: }
1892: }
1893: public function GetAttributeName() {
1894: return $this->strName;
1895: }
1896:
1897: public function HasSubquery() {
1898: return $this->objSubQueryDefinition != null;
1899: }
1900: }
1901:
1902: class QQFunctionNode extends QQSubQueryNode {
1903:
1904: protected $strFunctionName;
1905:
1906: protected $params;
1907:
1908: 1909: 1910: 1911:
1912: public function __construct($strFunctionName, $params) {
1913: parent::__construct('', '', '');
1914: $this->strFunctionName = $strFunctionName;
1915: $this->params = $params;
1916: }
1917:
1918: 1919: 1920: 1921:
1922: public function GetColumnAlias(QQueryBuilder $objBuilder) {
1923: $strSql = $this->strFunctionName . '(';
1924: foreach ($this->params as $param) {
1925: if ($param instanceof QQColumnNode) {
1926: $strSql .= $param->GetColumnAlias($objBuilder);
1927: }
1928: else {
1929:
1930: $strSql .= $param;
1931: }
1932: $strSql .= ',';
1933: }
1934: $strSql = substr($strSql, 0, -1);
1935: $strSql .= ')';
1936: return $strSql;
1937: }
1938:
1939: public function __toString() {
1940: return 'QQFunctionNode ' . $this->strFunctionName;
1941: }
1942: }
1943:
1944: class QQMathNode extends QQSubQueryNode {
1945:
1946: protected $strOperation;
1947:
1948: protected $params;
1949:
1950: 1951: 1952: 1953:
1954: public function __construct($strOperation, $params) {
1955: parent::__construct('', '', '');
1956: $this->strOperation = $strOperation;
1957: $this->params = $params;
1958: }
1959:
1960: 1961: 1962: 1963:
1964: public function GetColumnAlias(QQueryBuilder $objBuilder) {
1965: if (count($this->params) == 0) return '';
1966:
1967: $strSql = '(';
1968:
1969: if (count($this->params) == 1) {
1970:
1971: $strSql .= $this->strOperation;
1972: }
1973: foreach ($this->params as $param) {
1974: if ($param instanceof QQColumnNode) {
1975: $strSql .= $param->GetColumnAlias($objBuilder);
1976: }
1977: else {
1978:
1979: $strSql .= $param;
1980: }
1981: $strSql .= ' ' . $this->strOperation . ' ';
1982: }
1983: $strSql = substr($strSql, 0, -(strlen($this->strOperation) + 2));
1984: $strSql .= ')';
1985: return $strSql;
1986: }
1987:
1988: public function __toString() {
1989: return 'QQMathNode ' . $this->strOperation;
1990: }
1991:
1992: }
1993:
1994:
1995: abstract class QQClause extends QBaseClass {
1996: abstract public function UpdateQueryBuilder(QQueryBuilder $objBuilder);
1997: abstract public function __toString();
1998: }
1999:
2000: 2001: 2002:
2003: class QQOrderBy extends QQClause {
2004:
2005: protected $objNodeArray;
2006:
2007: 2008: 2009: 2010: 2011: 2012: 2013: 2014: 2015: 2016:
2017: protected function CollapseNodes($mixParameterArray) {
2018:
2019: $objNodeArray = array();
2020: foreach ($mixParameterArray as $mixParameter) {
2021: if (is_array($mixParameter)) {
2022: $objNodeArray = array_merge($objNodeArray, $mixParameter);
2023: } else {
2024: array_push($objNodeArray, $mixParameter);
2025: }
2026: }
2027:
2028: $blnPreviousIsNode = false;
2029: $objFinalNodeArray = array();
2030: foreach ($objNodeArray as $objNode) {
2031: if (!($objNode instanceof QQNode || $objNode instanceof QQCondition)) {
2032: if (!$blnPreviousIsNode)
2033: throw new QCallerException('OrderBy clause parameters must all be QQNode or QQCondition objects followed by an optional true/false "Ascending Order" option', 3);
2034: $blnPreviousIsNode = false;
2035: array_push($objFinalNodeArray, $objNode);
2036: } elseif ($objNode instanceof QQCondition) {
2037: $blnPreviousIsNode = true;
2038: array_push($objFinalNodeArray, $objNode);
2039: } else {
2040: if (!$objNode->_ParentNode) {
2041: throw new QInvalidCastException('Unable to cast "' . $objNode->_Name . '" table to Column-based QQNode', 4);
2042: }
2043: if ($objNode->_PrimaryKeyNode) {
2044: array_push($objFinalNodeArray, $objNode->_PrimaryKeyNode);
2045: } else {
2046: array_push($objFinalNodeArray, $objNode);
2047: }
2048: $blnPreviousIsNode = true;
2049: }
2050: }
2051:
2052: if (count($objFinalNodeArray)) {
2053: return $objFinalNodeArray;
2054: } else {
2055: throw new QCallerException('No parameters passed in to OrderBy clause', 3);
2056: }
2057: }
2058:
2059: 2060: 2061: 2062: 2063: 2064: 2065:
2066: public function __construct($mixParameterArray) {
2067: $this->objNodeArray = $this->CollapseNodes($mixParameterArray);
2068: }
2069:
2070: 2071: 2072: 2073: 2074:
2075: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2076: $objBuilder->SetOrderByClause($this);
2077: }
2078:
2079: 2080: 2081: 2082: 2083: 2084: 2085:
2086: public function _UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2087: $intLength = count($this->objNodeArray);
2088: for ($intIndex = 0; $intIndex < $intLength; $intIndex++) {
2089: $objNode = $this->objNodeArray[$intIndex];
2090: if ($objNode instanceof QQVirtualNode) {
2091: if ($objNode->HasSubquery()) {
2092: throw new QCallerException('You cannot define a virtual node in an order by clause. You must use an Expand clause to define it.');
2093: }
2094: $strOrderByCommand = '__' . $objNode->GetAttributeName();
2095: } elseif ($objNode instanceof QQColumnNode) {
2096:
2097: $strOrderByCommand = $objNode->GetColumnAlias($objBuilder);
2098: } elseif ($objNode instanceof QQCondition) {
2099:
2100: $strOrderByCommand = $objNode->GetWhereClause($objBuilder);
2101: } else {
2102: $strOrderByCommand = '';
2103: }
2104:
2105:
2106: if ((($intIndex + 1) < $intLength) &&
2107: !($this->objNodeArray[$intIndex + 1] instanceof QQNode)) {
2108: if ((!$this->objNodeArray[$intIndex + 1]) ||
2109: (trim(strtolower($this->objNodeArray[$intIndex + 1])) == 'desc'))
2110: $strOrderByCommand .= ' DESC';
2111: else
2112: $strOrderByCommand .= ' ASC';
2113: $intIndex++;
2114: }
2115:
2116: $objBuilder->AddOrderByItem($strOrderByCommand);
2117: }
2118: }
2119:
2120:
2121:
2122: 2123: 2124: 2125: 2126: 2127: 2128:
2129: public function GetAsManualSql() {
2130: $strOrderByArray = array();
2131: $intLength = count($this->objNodeArray);
2132: for ($intIndex = 0; $intIndex < $intLength; $intIndex++) {
2133: $strOrderByCommand = $this->objNodeArray[$intIndex]->GetAsManualSqlColumn();
2134:
2135:
2136: if ((($intIndex + 1) < $intLength) &&
2137: !($this->objNodeArray[$intIndex + 1] instanceof QQNode)) {
2138: if ((!$this->objNodeArray[$intIndex + 1]) ||
2139: (trim(strtolower($this->objNodeArray[$intIndex + 1])) == 'desc'))
2140: $strOrderByCommand .= ' DESC';
2141: else
2142: $strOrderByCommand .= ' ASC';
2143: $intIndex++;
2144: }
2145:
2146: array_push($strOrderByArray, $strOrderByCommand);
2147: }
2148:
2149: return implode(',', $strOrderByArray);
2150: }
2151:
2152: public function __toString() {
2153: return 'QQOrderBy Clause';
2154: }
2155: }
2156:
2157: class QQDistinct extends QQClause {
2158: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2159: $objBuilder->SetDistinctFlag();
2160: }
2161: public function __toString() {
2162: return 'QQDistinct Clause';
2163: }
2164: }
2165:
2166: class QQLimitInfo extends QQClause {
2167: protected $intMaxRowCount;
2168: protected $intOffset;
2169: public function __construct($intMaxRowCount, $intOffset = 0) {
2170: try {
2171: $this->intMaxRowCount = QType::Cast($intMaxRowCount, QType::Integer);
2172: $this->intOffset = QType::Cast($intOffset, QType::Integer);
2173: } catch (QCallerException $objExc) {
2174: $objExc->IncrementOffset();
2175: throw $objExc;
2176: }
2177: }
2178: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2179: if ($this->intOffset)
2180: $objBuilder->SetLimitInfo($this->intOffset . ',' . $this->intMaxRowCount);
2181: else
2182: $objBuilder->SetLimitInfo($this->intMaxRowCount);
2183: }
2184: public function __toString() {
2185: return 'QQLimitInfo Clause';
2186: }
2187:
2188: public function __get($strName) {
2189: switch ($strName) {
2190: case 'MaxRowCount':
2191: return $this->intMaxRowCount;
2192: case 'Offset':
2193: return $this->intOffset;
2194: default:
2195: try {
2196: return parent::__get($strName);
2197: } catch (QCallerException $objExc) {
2198: $objExc->IncrementOffset();
2199: throw $objExc;
2200: }
2201: }
2202: }
2203: }
2204:
2205: class QQExpandVirtualNode extends QQClause {
2206: protected $objNode;
2207: public function __construct(QQVirtualNode $objNode) {
2208: $this->objNode = $objNode;
2209: }
2210: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2211: try {
2212: $objBuilder->AddSelectFunction(null, $this->objNode->GetColumnAlias($objBuilder), $this->objNode->GetAttributeName());
2213: } catch (QCallerException $objExc) {
2214: $objExc->IncrementOffset();
2215: throw $objExc;
2216: }
2217: }
2218: public function __toString() {
2219: return 'QQExpandVirtualNode Clause';
2220: }
2221: }
2222: class QQExpand extends QQClause {
2223:
2224: protected $objNode;
2225: protected $objJoinCondition;
2226: protected $objSelect;
2227:
2228: public function __construct($objNode, QQCondition $objJoinCondition = null, QQSelect $objSelect = null) {
2229:
2230: if ($objNode instanceof QQAssociationNode)
2231: throw new QCallerException('Expand clause parameter cannot be an association table node. Try expanding one level deeper.', 2);
2232: else if (!($objNode instanceof QQNode))
2233: throw new QCallerException('Expand clause parameter must be a QQNode object', 2);
2234: else if (!$objNode->_ParentNode)
2235: throw new QInvalidCastException('Cannot expand on this kind of node.', 3);
2236:
2237: $this->objNode = $objNode;
2238: $this->objJoinCondition = $objJoinCondition;
2239: $this->objSelect = $objSelect;
2240: }
2241: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2242: $this->objNode->Join($objBuilder, true, $this->objJoinCondition, $this->objSelect);
2243: }
2244: public function __toString() {
2245: return 'QQExpand Clause';
2246: }
2247: }
2248:
2249: 2250: 2251: 2252:
2253: class QQHavingClause extends QQClause {
2254: protected $objNode;
2255: public function __construct(QQSubQueryNode $objSubQueryDefinition) {
2256: $this->objNode = $objSubQueryDefinition;
2257: }
2258: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2259: $objBuilder->AddHavingItem (
2260: $this->objNode->GetColumnAlias($objBuilder)
2261: );
2262: }
2263: public function GetAttributeName() {
2264: return $this->objNode->strName;
2265: }
2266: public function __toString() {
2267: return "Having Clause";
2268: }
2269:
2270: }
2271:
2272: abstract class QQAggregationClause extends QQClause {
2273:
2274: protected $objNode;
2275: protected $strAttributeName;
2276: protected $strFunctionName;
2277: public function __construct(QQColumnNode $objNode, $strAttributeName) {
2278: $this->objNode = QQ::Func($this->strFunctionName, $objNode);
2279: $this->strAttributeName = QQ::GetVirtualAlias($strAttributeName);
2280: }
2281: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2282: $objBuilder->SetVirtualNode($this->strAttributeName, $this->objNode);
2283: $objBuilder->AddSelectFunction(null, $this->objNode->GetColumnAlias($objBuilder), $this->strAttributeName);
2284: }
2285: }
2286: class QQCount extends QQAggregationClause {
2287: protected $strFunctionName = 'COUNT';
2288: public function __toString() {
2289: return 'QQCount Clause';
2290: }
2291: }
2292: class QQSum extends QQAggregationClause {
2293: protected $strFunctionName = 'SUM';
2294: public function __toString() {
2295: return 'QQSum Clause';
2296: }
2297: }
2298: class QQMinimum extends QQAggregationClause {
2299: protected $strFunctionName = 'MIN';
2300: public function __toString() {
2301: return 'QQMinimum Clause';
2302: }
2303: }
2304: class QQMaximum extends QQAggregationClause {
2305: protected $strFunctionName = 'MAX';
2306: public function __toString() {
2307: return 'QQMaximum Clause';
2308: }
2309: }
2310: class QQAverage extends QQAggregationClause {
2311: protected $strFunctionName = 'AVG';
2312: public function __toString() {
2313: return 'QQAverage Clause';
2314: }
2315: }
2316:
2317: class QQExpandAsArray extends QQClause {
2318:
2319: protected $objNode;
2320: protected $objCondition;
2321: protected $objSelect;
2322:
2323: 2324: 2325: 2326: 2327: 2328:
2329: public function __construct(QQNode $objNode, $objCondition = null, QQSelect $objSelect = null) {
2330:
2331:
2332: if ((!($objNode instanceof QQAssociationNode)) && (!($objNode instanceof QQReverseReferenceNode)))
2333: throw new QCallerException('ExpandAsArray clause parameter must be an Association or ReverseReference node', 2);
2334:
2335: if ($objCondition instanceof QQSelect) {
2336: $this->objNode = $objNode;
2337: $this->objSelect = $objCondition;
2338: } else {
2339: if (!is_null($objCondition)) {
2340: 2341: 2342: 2343:
2344: if (!($objCondition instanceof QQCondition)) {
2345: throw new QCallerException('Condition clause parameter must be a QQCondition dervied class.', 2);
2346: }
2347: }
2348: $this->objNode = $objNode;
2349: $this->objSelect = $objSelect;
2350: $this->objCondition = $objCondition;
2351: }
2352:
2353: }
2354: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2355: if ($this->objNode instanceof QQAssociationNode) {
2356:
2357: $this->objNode->_ChildTableNode->Join($objBuilder, true, $this->objCondition, $this->objSelect);
2358: }
2359: else {
2360: $this->objNode->Join($objBuilder, true, $this->objCondition, $this->objSelect);
2361: }
2362: $objBuilder->AddExpandAsArrayNode($this->objNode);
2363: }
2364: public function __toString() {
2365: return 'QQExpandAsArray Clause';
2366: }
2367: }
2368:
2369: class QQGroupBy extends QQClause {
2370:
2371: protected $objNodeArray;
2372:
2373: 2374: 2375: 2376: 2377: 2378: 2379: 2380: 2381: 2382:
2383: protected function CollapseNodes($mixParameterArray) {
2384: $objNodeArray = array();
2385: foreach ($mixParameterArray as $mixParameter) {
2386: if (is_array($mixParameter)) {
2387: $objNodeArray = array_merge($objNodeArray, $mixParameter);
2388: } else {
2389: array_push($objNodeArray, $mixParameter);
2390: }
2391: }
2392:
2393: $objFinalNodeArray = array();
2394: foreach ($objNodeArray as $objNode) {
2395:
2396: if ($objNode instanceof QQAssociationNode)
2397: throw new QCallerException('GroupBy clause parameter cannot be an association table node.', 3);
2398: else if (!($objNode instanceof QQNode))
2399: throw new QCallerException('GroupBy clause parameters must all be QQNode objects.', 3);
2400:
2401: if (!$objNode->_ParentNode)
2402: throw new QInvalidCastException('Unable to cast "' . $objNode->_Name . '" table to Column-based QQNode', 4);
2403:
2404: if ($objNode->_PrimaryKeyNode) {
2405: array_push($objFinalNodeArray, $objNode->_PrimaryKeyNode);
2406: } else
2407: array_push($objFinalNodeArray, $objNode);
2408: }
2409:
2410: if (count($objFinalNodeArray))
2411: return $objFinalNodeArray;
2412: else
2413: throw new QCallerException('No parameters passed in to Expand clause', 3);
2414: }
2415: public function __construct($mixParameterArray) {
2416: $this->objNodeArray = $this->CollapseNodes($mixParameterArray);
2417: }
2418: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2419: $intLength = count($this->objNodeArray);
2420: for ($intIndex = 0; $intIndex < $intLength; $intIndex++)
2421: $objBuilder->AddGroupByItem($this->objNodeArray[$intIndex]->GetColumnAlias($objBuilder));
2422: }
2423: public function __toString() {
2424: return 'QQGroupBy Clause';
2425: }
2426: }
2427:
2428:
2429: class QQSelect extends QQClause {
2430:
2431: protected $arrNodeObj = array();
2432: protected $blnSkipPrimaryKey = false;
2433:
2434: 2435: 2436: 2437:
2438: public function __construct($arrNodeObj) {
2439: $this->arrNodeObj = $arrNodeObj;
2440: foreach ($this->arrNodeObj as $objNode) {
2441: if (!($objNode instanceof QQColumnNode)) {
2442: throw new QCallerException('Select nodes must be column nodes.', 3);
2443: }
2444: }
2445: }
2446:
2447: public function UpdateQueryBuilder(QQueryBuilder $objBuilder) {
2448: }
2449:
2450: public function AddSelectItems(QQueryBuilder $objBuilder, $strTableName, $strAliasPrefix) {
2451: foreach ($this->arrNodeObj as $objNode) {
2452: $strNodeTable = $objNode->GetTable();
2453: if ($strNodeTable == $strTableName) {
2454: $objBuilder->AddSelectItem($strTableName, $objNode->_Name, $strAliasPrefix . $objNode->_Name);
2455: }
2456: }
2457: }
2458:
2459: public function Merge(QQSelect $objSelect = null) {
2460: if ($objSelect) {
2461: foreach ($objSelect->arrNodeObj as $objNode) {
2462: array_push($this->arrNodeObj, $objNode);
2463: }
2464: if ($objSelect->blnSkipPrimaryKey) {
2465: $this->blnSkipPrimaryKey = true;
2466: }
2467: }
2468: }
2469:
2470: 2471: 2472:
2473: public function SkipPrimaryKey() {
2474: return $this->blnSkipPrimaryKey;
2475: }
2476:
2477: 2478: 2479:
2480: public function SetSkipPrimaryKey($blnSkipPrimaryKey) {
2481: $this->blnSkipPrimaryKey = $blnSkipPrimaryKey;
2482: }
2483:
2484: public function __toString() {
2485: return 'QQSelectColumn Clause';
2486: }
2487: }
2488:
2489:
2490: class QQuery extends QQ {}
2491:
2492: 2493: 2494: 2495: 2496: 2497: 2498:
2499: class QQueryBuilder extends QBaseClass {
2500:
2501: protected $strSelectArray;
2502:
2503: protected $strColumnAliasArray;
2504:
2505: protected $intColumnAliasCount = 0;
2506:
2507: protected $strTableAliasArray;
2508:
2509: protected $intTableAliasCount = 0;
2510:
2511: protected $strFromArray;
2512:
2513: protected $strJoinArray;
2514:
2515: protected $strJoinConditionArray;
2516:
2517: protected $strWhereArray;
2518:
2519: protected $strOrderByArray;
2520:
2521: protected $strGroupByArray;
2522:
2523: protected $strHavingArray;
2524:
2525: protected $objVirtualNodeArray;
2526:
2527: protected $strLimitInfo;
2528:
2529: protected $blnDistinctFlag;
2530:
2531: protected $objExpandAsArrayNode;
2532:
2533: protected $blnCountOnlyFlag;
2534:
2535:
2536: protected $objDatabase;
2537:
2538: protected $strRootTableName;
2539:
2540: protected $strEscapeIdentifierBegin;
2541:
2542: protected $strEscapeIdentifierEnd;
2543:
2544: protected $objOrderByClause;
2545:
2546: 2547: 2548: 2549:
2550: public function __construct(QDatabaseBase $objDatabase, $strRootTableName) {
2551: $this->objDatabase = $objDatabase;
2552: $this->strEscapeIdentifierBegin = $objDatabase->EscapeIdentifierBegin;
2553: $this->strEscapeIdentifierEnd = $objDatabase->EscapeIdentifierEnd;
2554: $this->strRootTableName = $strRootTableName;
2555:
2556: $this->strSelectArray = array();
2557: $this->strColumnAliasArray = array();
2558: $this->strTableAliasArray = array();
2559: $this->strFromArray = array();
2560: $this->strJoinArray = array();
2561: $this->strJoinConditionArray = array();
2562: $this->strWhereArray = array();
2563: $this->strOrderByArray = array();
2564: $this->strGroupByArray = array();
2565: $this->strHavingArray = array();
2566: $this->objVirtualNodeArray = array();
2567: }
2568:
2569: 2570: 2571: 2572: 2573:
2574: public function AddSelectItem($strTableName, $strColumnName, $strFullAlias) {
2575: $strTableAlias = $this->GetTableAlias($strTableName);
2576:
2577: if (!array_key_exists($strFullAlias, $this->strColumnAliasArray)) {
2578: $strColumnAlias = 'a' . $this->intColumnAliasCount++;
2579: $this->strColumnAliasArray[$strFullAlias] = $strColumnAlias;
2580: } else {
2581: $strColumnAlias = $this->strColumnAliasArray[$strFullAlias];
2582: }
2583:
2584: $this->strSelectArray[$strFullAlias] = sprintf('%s%s%s.%s%s%s AS %s%s%s',
2585: $this->strEscapeIdentifierBegin, $strTableAlias, $this->strEscapeIdentifierEnd,
2586: $this->strEscapeIdentifierBegin, $strColumnName, $this->strEscapeIdentifierEnd,
2587: $this->strEscapeIdentifierBegin, $strColumnAlias, $this->strEscapeIdentifierEnd);
2588: }
2589:
2590: 2591: 2592: 2593: 2594:
2595: public function AddSelectFunction($strFunctionName, $strColumnName, $strFullAlias) {
2596: $this->strSelectArray[$strFullAlias] = sprintf('%s(%s) AS %s__%s%s',
2597: $strFunctionName, $strColumnName,
2598: $this->strEscapeIdentifierBegin, $strFullAlias, $this->strEscapeIdentifierEnd);
2599: }
2600:
2601: 2602: 2603:
2604: public function AddFromItem($strTableName) {
2605: $strTableAlias = $this->GetTableAlias($strTableName);
2606:
2607: $this->strFromArray[$strTableName] = sprintf('%s%s%s AS %s%s%s',
2608: $this->strEscapeIdentifierBegin, $strTableName, $this->strEscapeIdentifierEnd,
2609: $this->strEscapeIdentifierBegin, $strTableAlias, $this->strEscapeIdentifierEnd);
2610: }
2611:
2612: 2613: 2614: 2615:
2616: public function GetTableAlias($strTableName) {
2617: if (!array_key_exists($strTableName, $this->strTableAliasArray)) {
2618: $strTableAlias = 't' . $this->intTableAliasCount++;
2619: $this->strTableAliasArray[$strTableName] = $strTableAlias;
2620: return $strTableAlias;
2621: } else {
2622: return $this->strTableAliasArray[$strTableName];
2623: }
2624: }
2625:
2626: 2627: 2628: 2629: 2630: 2631: 2632: 2633: 2634: 2635:
2636: public function AddJoinItem($strJoinTableName, $strJoinTableAlias, $strTableName, $strColumnName, $strLinkedColumnName, QQCondition $objJoinCondition = null) {
2637: $strJoinItem = sprintf('LEFT JOIN %s%s%s AS %s%s%s ON %s%s%s.%s%s%s = %s%s%s.%s%s%s',
2638: $this->strEscapeIdentifierBegin, $strJoinTableName, $this->strEscapeIdentifierEnd,
2639: $this->strEscapeIdentifierBegin, $this->GetTableAlias($strJoinTableAlias), $this->strEscapeIdentifierEnd,
2640:
2641: $this->strEscapeIdentifierBegin, $this->GetTableAlias($strTableName), $this->strEscapeIdentifierEnd,
2642: $this->strEscapeIdentifierBegin, $strColumnName, $this->strEscapeIdentifierEnd,
2643:
2644: $this->strEscapeIdentifierBegin, $this->GetTableAlias($strJoinTableAlias), $this->strEscapeIdentifierEnd,
2645: $this->strEscapeIdentifierBegin, $strLinkedColumnName, $this->strEscapeIdentifierEnd);
2646:
2647: $strJoinIndex = $strJoinItem;
2648: try {
2649: $strConditionClause = null;
2650: if ($objJoinCondition &&
2651: ($strConditionClause = $objJoinCondition->GetWhereClause($this, false)))
2652: $strJoinItem .= ' AND ' . $strConditionClause;
2653: } catch (QCallerException $objExc) {
2654: $objExc->IncrementOffset();
2655: throw $objExc;
2656: }
2657:
2658: 2659: 2660: 2661: 2662: 2663: 2664: 2665: 2666: 2667: 2668: 2669:
2670: if (array_key_exists($strJoinIndex, $this->strJoinArray)) {
2671:
2672: if (!array_key_exists($strJoinIndex, $this->strJoinConditionArray)) {
2673:
2674:
2675: if (!$strConditionClause) {
2676: return;
2677:
2678:
2679: } else {
2680: $this->strJoinArray[$strJoinIndex] = $strJoinItem;
2681: $this->strJoinConditionArray[$strJoinIndex] = $strConditionClause;
2682: return;
2683: }
2684: }
2685:
2686:
2687: if (!$strConditionClause)
2688: return;
2689:
2690:
2691: if ($strConditionClause == $this->strJoinConditionArray[$strJoinIndex])
2692: return;
2693:
2694:
2695: throw new QCallerException('You have two different Join Conditions on the same Expanded Table: ' . $strJoinIndex . "\r\n[" . $this->strJoinConditionArray[$strJoinIndex] . '] vs. [' . $strConditionClause . ']');
2696: }
2697:
2698:
2699: $this->strJoinArray[$strJoinIndex] = $strJoinItem;
2700:
2701:
2702: if ($strConditionClause)
2703: $this->strJoinConditionArray[$strJoinIndex] = $strConditionClause;
2704: }
2705:
2706: 2707: 2708: 2709: 2710: 2711: 2712:
2713: public function AddJoinCustomItem($strJoinTableName, $strJoinTableAlias, QQCondition $objJoinCondition) {
2714: $strJoinItem = sprintf('LEFT JOIN %s%s%s AS %s%s%s ON ',
2715: $this->strEscapeIdentifierBegin, $strJoinTableName, $this->strEscapeIdentifierEnd,
2716: $this->strEscapeIdentifierBegin, $this->GetTableAlias($strJoinTableAlias), $this->strEscapeIdentifierEnd
2717: );
2718:
2719: $strJoinIndex = $strJoinItem;
2720:
2721: try {
2722: if (($strConditionClause = $objJoinCondition->GetWhereClause($this, true)))
2723: $strJoinItem .= ' AND ' . $strConditionClause;
2724: } catch (QCallerException $objExc) {
2725: $objExc->IncrementOffset();
2726: throw $objExc;
2727: }
2728:
2729: $this->strJoinArray[$strJoinIndex] = $strJoinItem;
2730: }
2731:
2732: 2733: 2734:
2735: public function AddJoinCustomSqlItem($strSql) {
2736: $this->strJoinArray[$strSql] = $strSql;
2737: }
2738:
2739: 2740: 2741:
2742: public function AddWhereItem($strItem) {
2743: array_push($this->strWhereArray, $strItem);
2744: }
2745:
2746: 2747: 2748:
2749: public function AddOrderByItem($strItem) {
2750: array_push($this->strOrderByArray, $strItem);
2751: }
2752:
2753: 2754: 2755:
2756: public function AddGroupByItem($strItem) {
2757: array_push($this->strGroupByArray, $strItem);
2758: }
2759:
2760: 2761: 2762:
2763: public function AddHavingItem ($strItem) {
2764: array_push($this->strHavingArray, $strItem);
2765: }
2766:
2767: 2768: 2769:
2770: public function SetLimitInfo($strLimitInfo) {
2771: $this->strLimitInfo = $strLimitInfo;
2772: }
2773:
2774: public function SetDistinctFlag() {
2775: $this->blnDistinctFlag = true;
2776: }
2777:
2778: public function SetCountOnlyFlag() {
2779: $this->blnCountOnlyFlag = true;
2780: }
2781:
2782: 2783: 2784: 2785:
2786: public function SetVirtualNode($strName, QQColumnNode $objNode) {
2787: $this->objVirtualNodeArray[QQ::GetVirtualAlias($strName)] = $objNode;
2788: }
2789:
2790: 2791: 2792: 2793: 2794:
2795: public function GetVirtualNode($strName) {
2796: $strName = QQ::GetVirtualAlias($strName);
2797: if (isset($this->objVirtualNodeArray[$strName])) {
2798: return $this->objVirtualNodeArray[$strName];
2799: }
2800: else throw new QCallerException('Undefined Virtual Node: ' . $strName);
2801: }
2802:
2803: 2804: 2805: 2806:
2807: public function AddExpandAsArrayNode(QQNode $objNode) {
2808:
2809:
2810: $objNode->ExpandAsArray = true;
2811: while ($objNode->_ParentNode) {
2812: $objNode = $objNode->_ParentNode;
2813: }
2814:
2815: if (!$this->objExpandAsArrayNode) {
2816: $this->objExpandAsArrayNode = $objNode;
2817: }
2818: else {
2819:
2820: $this->objExpandAsArrayNode->_MergeExpansionNode ($objNode);
2821: }
2822: }
2823:
2824: 2825: 2826:
2827: public function GetStatement() {
2828: $this->ProcessClauses();
2829:
2830:
2831: if ($this->blnCountOnlyFlag) {
2832: if ($this->blnDistinctFlag) {
2833: $strSql = "SELECT\r\n COUNT(*) AS q_row_count\r\n" .
2834: "FROM (SELECT DISTINCT ";
2835: $strSql .= " " . implode(",\r\n ", $this->strSelectArray);
2836: } else
2837: $strSql = "SELECT\r\n COUNT(*) AS q_row_count\r\n";
2838: } else {
2839: if ($this->blnDistinctFlag)
2840: $strSql = "SELECT DISTINCT\r\n";
2841: else
2842: $strSql = "SELECT\r\n";
2843: if ($this->strLimitInfo)
2844: $strSql .= $this->objDatabase->SqlLimitVariablePrefix($this->strLimitInfo) . "\r\n";
2845: $strSql .= " " . implode(",\r\n ", $this->strSelectArray);
2846: }
2847:
2848:
2849: $strSql .= sprintf("\r\nFROM\r\n %s\r\n %s",
2850: implode(",\r\n ", $this->strFromArray),
2851: implode("\r\n ", $this->strJoinArray));
2852:
2853:
2854: if (count($this->strWhereArray)) {
2855: $strWhere = implode("\r\n ", $this->strWhereArray);
2856: if (trim($strWhere) != '1=1')
2857: $strSql .= "\r\nWHERE\r\n " . $strWhere;
2858: }
2859:
2860:
2861: if (count($this->strGroupByArray))
2862: $strSql .= "\r\nGROUP BY\r\n " . implode(",\r\n ", $this->strGroupByArray);
2863: if (count($this->strHavingArray)) {
2864: $strHaving = implode("\r\n ", $this->strHavingArray);
2865: $strSql .= "\r\nHaving\r\n " . $strHaving;
2866: }
2867: if (count($this->strOrderByArray))
2868: $strSql .= "\r\nORDER BY\r\n " . implode(",\r\n ", $this->strOrderByArray);
2869:
2870:
2871: if ($this->strLimitInfo)
2872: $strSql .= "\r\n" . $this->objDatabase->SqlLimitVariableSuffix($this->strLimitInfo);
2873:
2874:
2875: if ($this->blnCountOnlyFlag && $this->blnDistinctFlag)
2876: $strSql .= "\r\n) as q_count_table";
2877:
2878: return $strSql;
2879: }
2880:
2881: 2882: 2883: 2884: 2885:
2886: public function SetOrderByClause(QQOrderBy $objOrderByClause) {
2887: if ($this->objOrderByClause) {
2888: throw new QCallerException('You can only have one OrderBy clause in a query.');
2889: }
2890: $this->objOrderByClause = $objOrderByClause;
2891: }
2892: 2893: 2894: 2895:
2896: protected function ProcessClauses() {
2897: if ($this->objOrderByClause) {
2898: $this->objOrderByClause->_UpdateQueryBuilder($this);
2899: }
2900: }
2901:
2902: public function __get($strName) {
2903: switch ($strName) {
2904: case 'Database':
2905: return $this->objDatabase;
2906: case 'RootTableName':
2907: return $this->strRootTableName;
2908: case 'ColumnAliasArray':
2909: return $this->strColumnAliasArray;
2910: case 'ExpandAsArrayNode':
2911: return $this->objExpandAsArrayNode;
2912:
2913: default:
2914: try {
2915: return parent::__get($strName);
2916: } catch (QCallerException $objExc) {
2917: $objExc->IncrementOffset();
2918: throw $objExc;
2919: }
2920: }
2921: }
2922: }
2923:
2924: 2925: 2926: 2927: 2928:
2929: class QPartialQueryBuilder extends QQueryBuilder {
2930: protected $objParentBuilder;
2931:
2932: 2933: 2934:
2935: public function __construct(QQueryBuilder $objBuilder) {
2936: parent::__construct($objBuilder->objDatabase, $objBuilder->strRootTableName);
2937: $this->objParentBuilder = $objBuilder;
2938: $this->strColumnAliasArray = &$objBuilder->strColumnAliasArray;
2939: $this->strTableAliasArray = &$objBuilder->strTableAliasArray;
2940:
2941: $this->intTableAliasCount = &$objBuilder->intTableAliasCount;
2942: $this->intColumnAliasCount = &$objBuilder->intColumnAliasCount;
2943: }
2944:
2945: 2946: 2947:
2948: public function GetWhereStatement() {
2949: return implode(' ', $this->strWhereArray);
2950: }
2951:
2952: 2953: 2954:
2955: public function GetFromStatement() {
2956: return implode(' ', $this->strFromArray) . ' ' . implode(' ', $this->strJoinArray);
2957: }
2958: }
2959:
2960: