SqlQueryWhereBuilder.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. class SqlQueryWhereBuilder {
  3. private $_log = array();
  4. private $_usedFields = array();
  5. private $_raw = "";
  6. public function __construct() {
  7. }
  8. public function openBlock($blockType) {
  9. if (!$this->isAllowedBlockType($blockType)) throw new Exception("unsupported block type");
  10. $this->_log[] = "open_block_{$blockType}";
  11. }
  12. public function closeBlock($blockType) {
  13. if (!$this->isAllowedBlockType($blockType)) throw new Exception("unsupported block type");
  14. $this->_log[] = "close_block_{$blockType}";
  15. }
  16. public function addComparisonFieldToValue($fieldName, $comparisonSign, $value) {
  17. $sqlCompSign = "";
  18. switch ($comparisonSign) {
  19. case '=': $sqlCompSign = '='; break;
  20. default: throw new Exception("Unsupported comparison sign");
  21. }
  22. $this->_log[] = array('comparisonFieldToValue', $fieldName, $sqlCompSign, $value);
  23. }
  24. public function getQueryWhere($tablePrefix = '') {
  25. $sqlWhereRaw = $this->parseQueryWhere();
  26. $sqlTablePrefix = ($tablePrefix)? "`{$tablePrefix}`." : '';
  27. return str_replace('{tablePrefix}', $sqlTablePrefix, $sqlWhereRaw);
  28. }
  29. public function parseQueryWhere() {
  30. $this->_raw = "";
  31. $this->_usedFields = array();
  32. $sqlBlocksStack = array();
  33. $sqlValuesStack = array();
  34. $arr = array(); array_push($sqlValuesStack, $arr);// empty array to start
  35. foreach ($this->_log as $log) {
  36. switch ($log) {
  37. case 'open_block_and':
  38. case 'open_block_or': {
  39. $blockType = substr($log, 11);
  40. array_push($sqlBlocksStack, $blockType);
  41. $arr = array(); array_push($sqlValuesStack, $arr);
  42. //echo "L.".__LINE__.":sqlBlocksStack:" . json_encode($sqlBlocksStack) . "\n";
  43. //echo "L.".__LINE__.":sqlValuesStack:" . json_encode($sqlValuesStack) . "\n\n";
  44. }
  45. break;
  46. case 'close_block_and':
  47. case 'close_block_or': {
  48. $blockType = substr($log, 12);
  49. if (empty($sqlBlocksStack)) throw new Exception("parse sql query failed - blocks stack is empty");
  50. $stackBlockType = array_pop($sqlBlocksStack);
  51. if ($blockType != $stackBlockType) throw new Exception("parse sql query failed - expected stop '{$blockType}', given '{$stackBlockType}'");
  52. // parse to string and add to parent value stack
  53. $stackValue = array_pop($sqlValuesStack);
  54. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  55. if (empty($stackValue)) throw new Exception("parse sql query failed - stack value is empty");
  56. $sqlFromStack = " ( " . implode(" {$blockType} ", $stackValue) . " ) ";
  57. $parentStackValue = array_pop($sqlValuesStack);
  58. if (!is_array($parentStackValue)) throw new Exception("parse sql query failed - parent stack value is not array");
  59. array_push($parentStackValue, $sqlFromStack);
  60. array_push($sqlValuesStack, $parentStackValue);
  61. }
  62. break;
  63. default: {
  64. if (is_array($log) && 4 == count($log) && 'comparisonFieldToValue' == $log[0]) {
  65. $sqlFieldName = $log[1];
  66. $this->_usedFields[$sqlFieldName] = true;
  67. $sqlFromStack = "{tablePrefix}`{$sqlFieldName}` {$log[2]} '{$log[3]}'";
  68. $stackValue = array_pop($sqlValuesStack);
  69. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  70. array_push($stackValue, $sqlFromStack);
  71. array_push($sqlValuesStack, $stackValue);
  72. //echo "L.".__LINE__.":sqlBlocksStack:" . json_encode($sqlBlocksStack) . "\n";
  73. //echo "L.".__LINE__.":sqlValuesStack:" . json_encode($sqlValuesStack) . "\n\n";
  74. } else {
  75. throw new Exception("parse sql query failed - unknown '" . json_encode($log) . "'");
  76. }
  77. }
  78. }
  79. }
  80. // TODO: parse log
  81. //echo "L.".__LINE__.":sqlBlocksStack:" . json_encode($sqlBlocksStack) . "\n";
  82. //echo "L.".__LINE__.":sqlValuesStack:" . json_encode($sqlValuesStack) . "\n--------\n";
  83. if (!empty($sqlBlocksStack)) throw new Exception("parse sql query failed - blocks stack is not empty");
  84. if (1 !== count($sqlValuesStack)) throw new Exception("parse sql query failed - values stack is empty");
  85. $this->_raw = implode("\n", $sqlValuesStack[0]);
  86. return $this->_raw;
  87. }
  88. public function getUsedFields() {
  89. return array_keys($this->_usedFields);
  90. }
  91. public function isAllowedBlockType($blockType) {
  92. if ('and' == $blockType || 'or' == $blockType) {
  93. return true;
  94. } else if ('not' == $blockType) {
  95. return false;// TODO: allow not operator: expect only one children, if more -> use only last
  96. }
  97. return false;
  98. }
  99. }