query.class.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <?php
  2. /**
  3. * [WeEngine System] Copyright (c) 2014 WE7.CC
  4. * WeEngine is NOT a free software, it under the license terms, visited http://www.we7.cc/ for more details.
  5. */
  6. defined('IN_IA') or exit('Access Denied');
  7. class Query {
  8. private $clauses;
  9. private $statements = array();
  10. private $parameters = array();
  11. private $mainTable = '';
  12. private $currentTableAlias = '';
  13. private $error = array();
  14. private $lastsql = '';
  15. private $lastparams = '';
  16. private $values;
  17. public $fixTable;
  18. public function __construct() {
  19. $this->initClauses();
  20. }
  21. private function initClauses() {
  22. $this->clauses = array(
  23. 'SELECT' => array(),
  24. 'DELETE' => '',
  25. 'UPDATE' => '',
  26. 'INSERT INTO' => '',
  27. 'FROM' => '',
  28. 'LEFTJOIN' => array(),
  29. 'INNERJOIN' => array(),
  30. 'ON' => array(),
  31. 'SET' => '',
  32. 'WHERE' => array(),
  33. 'WHEREOR' => array(),
  34. 'GROUPBY' => array(),
  35. 'HAVING' => array(),
  36. 'ORDERBY' => array(),
  37. 'LIMIT' => '',
  38. 'PAGE' => '',
  39. );
  40. foreach ($this->clauses as $clause => $value) {
  41. $this->statements[$clause] = $value;
  42. }
  43. $this->parameters = array();
  44. if (!empty($this->fixTable)) {
  45. $this->from($this->fixTable);
  46. }
  47. }
  48. private function resetClause($clause = '') {
  49. if (empty($clause)) {
  50. $this->initClauses();
  51. return $this;
  52. }
  53. $this->statements[$clause] = null;
  54. $this->parameters = array();
  55. $this->values = array();
  56. if (isset($this->clauses[$clause]) && is_array($this->clauses[$clause])) {
  57. $this->statements[$clause] = array();
  58. }
  59. return $this;
  60. }
  61. private function addStatement($clause, $statement, $parameters = array()) {
  62. if ($statement === null) {
  63. return $this->resetClause($clause);
  64. }
  65. if (isset($this->statements[$clause]) && is_array($this->statements[$clause])) {
  66. if (is_array($statement)) {
  67. $this->statements[$clause] = array_merge($this->statements[$clause], $statement);
  68. } else {
  69. if (empty($parameters) && is_array($parameters)) {
  70. $this->statements[$clause][] = $statement;
  71. } else {
  72. $this->statements[$clause][$statement] = empty($parameters) && is_array($parameters) ? '' : $parameters;
  73. }
  74. }
  75. } else {
  76. $this->statements[$clause] = $statement;
  77. }
  78. return $this;
  79. }
  80. public function __call($clause, $statement = array()) {
  81. $origin_clause = $clause;
  82. $clause = strtoupper($clause);
  83. if ($clause == 'HAVING') {
  84. array_unshift($statement, $clause);
  85. return call_user_func_array(array($this, 'condition'), $statement);
  86. }
  87. if ($clause == 'LEFTJOIN' || $clause == 'INNERJOIN') {
  88. array_unshift($statement, $clause);
  89. return call_user_func_array(array($this, 'join'), $statement);
  90. }
  91. return $this->addStatement($clause, $statement);
  92. }
  93. public function where($condition, $parameters = array(), $operator = 'AND') {
  94. if (!is_array($condition) && !($condition instanceof Closure)) {
  95. $condition = array($condition => $parameters);
  96. }
  97. $this->addStatement('WHERE', array(array($operator, $condition)));
  98. return $this;
  99. }
  100. public function whereor($condition, $parameters = array()) {
  101. return $this->where($condition, $parameters, 'OR');
  102. }
  103. public function from($tablename, $alias = '') {
  104. if (empty($tablename)) {
  105. return $this;
  106. }
  107. $this->mainTable = $tablename;
  108. $this->currentTableAlias = $alias;
  109. $this->statements['FROM'] = $this->mainTable;
  110. return $this;
  111. }
  112. public function join($clause, $tablename, $alias = '') {
  113. if (empty($tablename)) {
  114. return $this;
  115. }
  116. $this->joinTable = $tablename;
  117. return $this->addStatement($clause, $tablename . ' ' .$alias);
  118. }
  119. public function on($condition, $parameters = array()) {
  120. if ($condition === null) {
  121. return $this->resetClause('ON');
  122. }
  123. if (empty($condition)) {
  124. return $this;
  125. }
  126. if (is_array($condition)) {
  127. foreach ($condition as $key => $val) {
  128. $this->on($key, $val);
  129. }
  130. return $this;
  131. }
  132. if (empty($this->statements['ON'][$this->joinTable])) {
  133. $this->statements['ON'][$this->joinTable] = array();
  134. }
  135. $this->statements['ON'][$this->joinTable][$condition] = $parameters;
  136. return $this;
  137. }
  138. public function select($field) {
  139. if (is_string($field)) {
  140. $field = func_get_args();
  141. }
  142. if (empty($field)) {
  143. return $this;
  144. }
  145. if (count($this->statements['SELECT']) == 1) {
  146. $this->resetClause('SELECT');
  147. }
  148. return $this->addStatement('SELECT', $field);
  149. }
  150. private function condition($operator, $condition, $parameters = array()) {
  151. if ($condition === null) {
  152. return $this->resetClause('WHERE');
  153. }
  154. if (empty($condition)) {
  155. return $this;
  156. }
  157. if (is_array($condition)) {
  158. foreach ($condition as $key => $val) {
  159. $this->condition($operator, $key, $val);
  160. }
  161. return $this;
  162. }
  163. return $this->addStatement($operator, $condition, $parameters);
  164. }
  165. public function orderby($field, $direction = 'ASC') {
  166. if (is_array($field)) {
  167. foreach ($field as $column => $order) {
  168. $this->orderby($column, $order);
  169. }
  170. return $this;
  171. }
  172. $direction = strtoupper($direction);
  173. $direction = in_array($direction, array('ASC', 'DESC')) ? $direction : 'ASC';
  174. return $this->addStatement('ORDERBY', $field . ' ' . $direction);
  175. }
  176. public function fill($field, $value = '') {
  177. if (is_array($field)) {
  178. foreach ($field as $column => $val) {
  179. $this->fill($column, $val);
  180. }
  181. return $this;
  182. }
  183. $this->values[$field] = $value;
  184. return $this;
  185. }
  186. public function hasWhere() {
  187. return count($this->statements['WHERE']) > 0;
  188. }
  189. public function get() {
  190. if (empty($this->statements['SELECT'])) {
  191. $this->addStatement('SELECT', '*');
  192. }
  193. $this->lastsql = $this->buildQuery();
  194. $this->lastparams = $this->parameters;
  195. $result = pdo_fetch($this->lastsql, $this->parameters);
  196. $this->resetClause();
  197. return $result;
  198. }
  199. public function getcolumn($field = '') {
  200. if (!empty($field)) {
  201. $this->select($field);
  202. }
  203. if (empty($this->statements['SELECT'])) {
  204. $this->addStatement('SELECT', '*');
  205. }
  206. $this->lastsql = $this->buildQuery();
  207. $this->lastparams = $this->parameters;
  208. $result = pdo_fetchcolumn($this->lastsql, $this->parameters);
  209. $this->resetClause();
  210. return $result;
  211. }
  212. public function getall($keyfield = '') {
  213. if (empty($this->statements['SELECT'])) {
  214. $this->addStatement('SELECT', '*');
  215. }
  216. $this->lastsql = $this->buildQuery();
  217. $this->lastparams = $this->parameters;
  218. $result = pdo_fetchall($this->lastsql, $this->parameters, $keyfield);
  219. $this->resetClause();
  220. return $result;
  221. }
  222. public function getLastQueryTotal() {
  223. $lastquery = $this->getLastQuery();
  224. $countsql = str_replace(substr($lastquery[0], 0, strpos($lastquery[0], 'FROM')), 'SELECT COUNT(*) ', $lastquery[0]);
  225. if (strpos($countsql, 'LIMIT') !== false) {
  226. $countsql = substr($countsql, 0, strpos($countsql, 'LIMIT'));
  227. }
  228. if (strexists(strtoupper($countsql), 'GROUP BY')) {
  229. $result = pdo_fetchall($countsql, $this->lastparams, $keyfield);
  230. $result = count($result);
  231. } else {
  232. $result = pdo_fetchcolumn($countsql, $this->lastparams, $keyfield);
  233. }
  234. return $result;
  235. }
  236. public function count() {
  237. $where = array();
  238. if (!empty($this->statements['WHERE'])) {
  239. foreach ($this->statements['WHERE'] as $row) {
  240. $where = array_merge($where, $row[1]);
  241. }
  242. }
  243. return pdo_count($this->statements['FROM'], $where);
  244. }
  245. public function exists() {
  246. $where = array();
  247. if (!empty($this->statements['WHERE'])) {
  248. foreach ($this->statements['WHERE'] as $row) {
  249. $where = array_merge($where, $row[1]);
  250. }
  251. }
  252. return pdo_exists($this->statements['FROM'], $where);
  253. }
  254. public function delete() {
  255. $where = $this->buildWhereArray();
  256. $result = pdo_delete($this->statements['FROM'], $where);
  257. $this->resetClause();
  258. return $result;
  259. }
  260. public function insert() {
  261. $result = pdo_insert($this->statements['FROM'], $this->values);
  262. $this->resetClause();
  263. return $result;
  264. }
  265. public function update() {
  266. $where = $this->buildWhereArray();
  267. if (empty($where)) {
  268. return error(-1, '未指定更新条件');
  269. }
  270. $result = pdo_update($this->statements['FROM'], $this->values, $where);
  271. $this->resetClause();
  272. return $result;
  273. }
  274. private function buildQuery() {
  275. $query = '';
  276. foreach ($this->clauses as $clause => $separator) {
  277. if (!empty($this->statements[$clause])) {
  278. if (method_exists($this, 'buildQuery' . $clause)) {
  279. $query .= call_user_func(array($this, 'buildQuery' . $clause), $this->statements[$clause]);
  280. } elseif (is_string($separator)) {
  281. $query .= " $clause " . implode($separator, $this->statements[$clause]);
  282. } elseif ($separator === null) {
  283. $query .= " $clause " . $this->statements[$clause];
  284. }
  285. }
  286. }
  287. return trim($query);
  288. }
  289. private function buildQueryWhere() {
  290. $closure = array();
  291. $sql = '';
  292. foreach ($this->statements['WHERE'] as $i => $wheregroup) {
  293. $where = array();
  294. if (!empty($wheregroup[1]) && $wheregroup[1] instanceof Closure) {
  295. $closure[] = $wheregroup;
  296. } else {
  297. $where = \SqlPaser::parseParameter($wheregroup[1], 'AND', $this->currentTableAlias);
  298. $this->parameters = array_merge($this->parameters, $where['params']);
  299. $sql .= ' ' . $wheregroup[0] . ' ' . $where['fields'];
  300. }
  301. unset($this->statements['WHERE'][$i]);
  302. }
  303. foreach ($closure as $callback) {
  304. $callback[1]($this);
  305. $subsql = '';
  306. $where = array();
  307. foreach ($this->statements['WHERE'] as $i => $wheregroup) {
  308. $where = \SqlPaser::parseParameter($wheregroup[1], 'AND', $this->currentTableAlias);
  309. $this->parameters = array_merge($this->parameters, $where['params']);
  310. $subsql .= ' ' . $wheregroup[0] . ' ' . $where['fields'];
  311. unset($this->statements['WHERE'][$i]);
  312. }
  313. $subsql = ltrim(ltrim($subsql, ' AND '), ' OR ');
  314. $sql .= " {$callback[0]} ( $subsql )";
  315. }
  316. return empty($where['fields']) ? '' : " WHERE " . ltrim(ltrim($sql, ' AND '), ' OR ');
  317. }
  318. private function buildQueryWhereor() {
  319. $where = \SqlPaser::parseParameter($this->statements['WHEREOR'], 'OR', $this->currentTableAlias);
  320. $this->parameters = array_merge($this->parameters, $where['params']);
  321. if (empty($where['fields'])) {
  322. return '';
  323. }
  324. if (empty($this->statements['WHERE'])) {
  325. return " WHERE {$where['fields']} ";
  326. } else {
  327. return " OR {$where['fields']} ";
  328. }
  329. }
  330. private function buildQueryHaving() {
  331. $where = \SqlPaser::parseParameter($this->statements['HAVING'], 'AND', $this->currentTableAlias);
  332. $this->parameters = array_merge($this->parameters, $where['params']);
  333. return empty($where['fields']) ? '' : " HAVING {$where['fields']} ";
  334. }
  335. private function buildQueryFrom() {
  336. return " FROM " . tablename($this->statements['FROM']) . ' ' . $this->currentTableAlias;
  337. }
  338. private function buildQueryLeftjoin() {
  339. return $this->buildQueryJoin('LEFTJOIN');
  340. }
  341. private function buildQueryInnerjoin() {
  342. return $this->buildQueryJoin('INNERJOIN');
  343. }
  344. private function buildQueryJoin($clause) {
  345. if (empty($this->statements[$clause])) {
  346. return '';
  347. }
  348. $clause_operator = array(
  349. 'LEFTJOIN' => ' LEFT JOIN ',
  350. 'INNERJOIN' => ' INNER JOIN ',
  351. );
  352. $sql = '';
  353. foreach ($this->statements[$clause] as $tablename) {
  354. list($tablename, $alias) = explode(' ', $tablename);
  355. $sql .= $clause_operator[$clause] . tablename($tablename) . ' ' . $alias;
  356. if (!empty($this->statements['ON'][$tablename])) {
  357. $sql .= " ON ";
  358. $split = "";
  359. foreach ($this->statements['ON'][$tablename] as $field => $condition) {
  360. $operator = '';
  361. if (strexists($field, ' ')) {
  362. list($field, $operator) = explode(' ', $field);
  363. }
  364. $operator = $operator ? $operator : '=';
  365. $field = '`' . str_replace('.', '`.`', $field) . '`';
  366. if (strexists($condition, '.')) {
  367. $condition = '`' . str_replace('.', '`.`', $condition) . '`';
  368. }
  369. $sql .= " $split $field $operator $condition ";
  370. $split = " AND ";
  371. }
  372. }
  373. }
  374. return $sql;
  375. }
  376. private function buildQuerySelect() {
  377. return \SqlPaser::parseSelect($this->statements['SELECT'], $this->currentTableAlias);
  378. }
  379. private function buildQueryLimit() {
  380. return \SqlPaser::parseLimit($this->statements['LIMIT'], false);
  381. }
  382. private function buildQueryPage() {
  383. return \SqlPaser::parseLimit($this->statements['PAGE'], true);
  384. }
  385. private function buildQueryOrderby() {
  386. return \SqlPaser::parseOrderby($this->statements['ORDERBY'], $this->currentTableAlias);
  387. }
  388. private function buildQueryGroupby() {
  389. return \SqlPaser::parseGroupby($this->statements['GROUPBY'], $this->currentTableAlias);
  390. }
  391. private function buildWhereArray() {
  392. $where = array();
  393. if (!empty($this->statements['WHERE'])) {
  394. foreach ($this->statements['WHERE'] as $row) {
  395. $where = array_merge($where, $row[1]);
  396. }
  397. }
  398. return $where;
  399. }
  400. public function getLastQuery() {
  401. return array($this->lastsql, $this->lastparams);
  402. }
  403. }