SqlQueryWhereBuilder.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. case 'like': $sqlCompSign = 'like'; break;
  21. case 'GreaterThen': $sqlCompSign = '>'; break;
  22. case 'LessThen': $sqlCompSign = '<'; break;
  23. case 'GreaterThenOrEqualTo': $sqlCompSign = '>='; break;
  24. case 'LessThenOrEqualTo': $sqlCompSign = '<='; break;
  25. default: throw new Exception("Unsupported comparison sign");
  26. }
  27. $this->_log[] = array('comparisonFieldToValue', $fieldName, $sqlCompSign, $value);
  28. }
  29. public function addComparisonFieldFunToValue($fieldFun, $fieldName, $comparisonSign, $value) {
  30. $sqlCompSign = "";
  31. switch ($comparisonSign) {
  32. case '=': $sqlCompSign = '='; break;
  33. case 'like': $sqlCompSign = 'like'; break;
  34. case 'GreaterThen': $sqlCompSign = '>'; break;
  35. case 'LessThen': $sqlCompSign = '<'; break;
  36. case 'GreaterThenOrEqualTo': $sqlCompSign = '>='; break;
  37. case 'LessThenOrEqualTo': $sqlCompSign = '<='; break;
  38. default: throw new Exception("Unsupported comparison sign");
  39. }
  40. $this->_log[] = array('comparisonFieldFunToValue', $fieldFun, $fieldName, $sqlCompSign, $value);
  41. }
  42. public function sql_filter_comparisonFieldIsNull($fieldName) {
  43. $this->_log[] = array('comparisonFieldIsNull', $fieldName);
  44. }
  45. public function getQueryWhere($tablePrefix = '') {
  46. $sqlWhereRaw = $this->parseQueryWhere();
  47. $sqlTablePrefix = ($tablePrefix)? "`{$tablePrefix}`." : '';
  48. return str_replace('{tablePrefix}', $sqlTablePrefix, $sqlWhereRaw);
  49. }
  50. public function parseQueryWhere() {
  51. $this->_raw = "";
  52. $this->_usedFields = array();
  53. $sqlBlocksStack = array();
  54. $sqlValuesStack = array();
  55. $arr = array(); array_push($sqlValuesStack, $arr);// empty array to start
  56. foreach ($this->_log as $log) {
  57. switch ($log) {
  58. case 'open_block_and':
  59. case 'open_block_or':
  60. case 'open_block_not': {
  61. $blockType = substr($log, 11);
  62. array_push($sqlBlocksStack, $blockType);
  63. $arr = array(); array_push($sqlValuesStack, $arr);
  64. //echo "L.".__LINE__.":sqlBlocksStack:" . json_encode($sqlBlocksStack) . "\n";
  65. //echo "L.".__LINE__.":sqlValuesStack:" . json_encode($sqlValuesStack) . "\n\n";
  66. }
  67. break;
  68. case 'close_block_and':
  69. case 'close_block_or': {
  70. $blockType = substr($log, 12);
  71. if (empty($sqlBlocksStack)) throw new Exception("parse sql query failed - blocks stack is empty");
  72. $stackBlockType = array_pop($sqlBlocksStack);
  73. if ($blockType != $stackBlockType) throw new Exception("parse sql query failed - expected stop '{$blockType}', given '{$stackBlockType}'");
  74. // parse to string and add to parent value stack
  75. $stackValue = array_pop($sqlValuesStack);
  76. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  77. if (empty($stackValue)) throw new Exception("parse sql query failed - stack value is empty");
  78. $sqlFromStack = " ( " . implode(" {$blockType} ", $stackValue) . " ) ";
  79. $parentStackValue = array_pop($sqlValuesStack);
  80. if (!is_array($parentStackValue)) throw new Exception("parse sql query failed - parent stack value is not array");
  81. array_push($parentStackValue, $sqlFromStack);
  82. array_push($sqlValuesStack, $parentStackValue);
  83. }
  84. break;
  85. case 'close_block_not': {
  86. $blockType = substr($log, 12);
  87. if (empty($sqlBlocksStack)) throw new Exception("parse sql query failed - blocks stack is empty");
  88. $stackBlockType = array_pop($sqlBlocksStack);
  89. if ($blockType != $stackBlockType) throw new Exception("parse sql query failed - expected stop '{$blockType}', given '{$stackBlockType}'");
  90. // parse to string and add to parent value stack
  91. $stackValue = array_pop($sqlValuesStack);
  92. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  93. if (empty($stackValue)) throw new Exception("parse sql query failed - stack value is empty");
  94. if (1 != count($stackValue)) throw new Exception("parse sql query failed - stack value count is not equal to 1");
  95. $stackValue = reset($stackValue);
  96. $sqlFromStack = " ! ({$stackValue}) ";
  97. $parentStackValue = array_pop($sqlValuesStack);
  98. if (!is_array($parentStackValue)) throw new Exception("parse sql query failed - parent stack value is not array");
  99. array_push($parentStackValue, $sqlFromStack);
  100. array_push($sqlValuesStack, $parentStackValue);
  101. }
  102. break;
  103. default: {
  104. if (is_array($log) && 4 == count($log) && 'comparisonFieldToValue' == $log[0]) {
  105. $sqlFieldName = $log[1];
  106. $this->_usedFields[$sqlFieldName] = true;
  107. $sqlFromStack = "{tablePrefix}`{$sqlFieldName}` {$log[2]} '{$log[3]}'";
  108. $stackValue = array_pop($sqlValuesStack);
  109. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  110. array_push($stackValue, $sqlFromStack);
  111. array_push($sqlValuesStack, $stackValue);
  112. //echo "L.".__LINE__.":sqlBlocksStack:" . json_encode($sqlBlocksStack) . "\n";
  113. //echo "L.".__LINE__.":sqlValuesStack:" . json_encode($sqlValuesStack) . "\n\n";
  114. } else if (is_array($log) && 5 == count($log) && 'comparisonFieldFunToValue' == $log[0]) {
  115. $sqlFieldFunName = $log[1];
  116. if (strtolower($sqlFieldFunName) != 'geometrytype') throw new Exception("Unsupported db function {$sqlFieldName}");
  117. $sqlFieldName = $log[2];
  118. $this->_usedFields[$sqlFieldName] = true;
  119. $sqlFromStack = "{$sqlFieldFunName}({tablePrefix}`{$sqlFieldName}`) {$log[3]} '{$log[4]}'";
  120. $stackValue = array_pop($sqlValuesStack);
  121. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  122. array_push($stackValue, $sqlFromStack);
  123. array_push($sqlValuesStack, $stackValue);
  124. } else if (is_array($log) && 2 == count($log) && 'comparisonFieldIsNull' == $log[0]) {
  125. $sqlFieldName = $log[1];
  126. $sqlFromStack = "{tablePrefix}`{$sqlFieldName}` is null";
  127. $stackValue = array_pop($sqlValuesStack);
  128. if (!is_array($stackValue)) throw new Exception("parse sql query failed - stack value is not array");
  129. array_push($stackValue, $sqlFromStack);
  130. array_push($sqlValuesStack, $stackValue);
  131. } else {
  132. throw new Exception("parse sql query failed - unknown '" . json_encode($log) . "'");
  133. }
  134. }
  135. }
  136. }
  137. // TODO: parse log
  138. //echo "L.".__LINE__.":sqlBlocksStack:" . json_encode($sqlBlocksStack) . "\n";
  139. //echo "L.".__LINE__.":sqlValuesStack:" . json_encode($sqlValuesStack) . "\n--------\n";
  140. if (!empty($sqlBlocksStack)) throw new Exception("parse sql query failed - blocks stack is not empty");
  141. if (1 !== count($sqlValuesStack)) throw new Exception("parse sql query failed - values stack is empty");
  142. $this->_raw = implode("\n", $sqlValuesStack[0]);
  143. return $this->_raw;
  144. }
  145. public function getUsedFields() {
  146. return array_keys($this->_usedFields);
  147. }
  148. public function isAllowedBlockType($blockType) {
  149. if ('and' == $blockType || 'or' == $blockType) {
  150. return true;
  151. } else if ('not' == $blockType) {
  152. return true;
  153. }
  154. return false;
  155. }
  156. public function splitQueryToWords($q) {
  157. $searchWords = explode(' ', $q);
  158. $sqlSearchWords = array();
  159. if (!empty($searchWords)) {
  160. foreach ($searchWords as $word) {
  161. if (!empty($word)) {
  162. $sqlSearchWords[] = $word;
  163. }
  164. }
  165. }
  166. return $sqlSearchWords;
  167. }
  168. }