query.class.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  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 (null === $statement) {
  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 ('HAVING' == $clause) {
  84. array_unshift($statement, $clause);
  85. return call_user_func_array(array($this, 'condition'), $statement);
  86. }
  87. if ('LEFTJOIN' == $clause || 'INNERJOIN' == $clause) {
  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 (null === $condition) {
  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 (1 == count($this->statements['SELECT'])) {
  146. $this->resetClause('SELECT');
  147. }
  148. return $this->addStatement('SELECT', $field);
  149. }
  150. private function condition($operator, $condition, $parameters = array()) {
  151. if (null === $condition) {
  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. if (strtoupper($field) == 'RAND()') {
  173. return $this->addStatement('ORDERBY', $field);
  174. }
  175. $direction = strtoupper($direction);
  176. $direction = in_array($direction, array('ASC', 'DESC')) ? $direction : 'ASC';
  177. return $this->addStatement('ORDERBY', $field . ' ' . $direction);
  178. }
  179. public function fill($field, $value = '') {
  180. if (is_array($field)) {
  181. foreach ($field as $column => $val) {
  182. $this->fill($column, $val);
  183. }
  184. return $this;
  185. }
  186. $this->values[$field] = $value;
  187. return $this;
  188. }
  189. public function hasWhere() {
  190. return count($this->statements['WHERE']) > 0;
  191. }
  192. public function get() {
  193. if (empty($this->statements['SELECT'])) {
  194. $this->addStatement('SELECT', '*');
  195. }
  196. $this->lastsql = $this->buildQuery();
  197. $this->lastparams = $this->parameters;
  198. $result = pdo_fetch($this->lastsql, $this->parameters);
  199. $this->resetClause();
  200. return $result;
  201. }
  202. public function getcolumn($field = '') {
  203. if (!empty($field)) {
  204. $this->select($field);
  205. }
  206. if (empty($this->statements['SELECT'])) {
  207. $this->addStatement('SELECT', '*');
  208. }
  209. $this->lastsql = $this->buildQuery();
  210. $this->lastparams = $this->parameters;
  211. $result = pdo_fetchcolumn($this->lastsql, $this->parameters);
  212. $this->resetClause();
  213. return $result;
  214. }
  215. public function getall($keyfield = '') {
  216. if (empty($this->statements['SELECT'])) {
  217. $this->addStatement('SELECT', '*');
  218. }
  219. $this->lastsql = $this->buildQuery();
  220. $this->lastparams = $this->parameters;
  221. $result = pdo_fetchall($this->lastsql, $this->parameters, $keyfield);
  222. $this->resetClause();
  223. return $result;
  224. }
  225. public function getLastQueryTotal() {
  226. $lastquery = $this->getLastQuery();
  227. $countsql = str_replace(substr($lastquery[0], 0, strpos($lastquery[0], 'FROM')), 'SELECT COUNT(*) ', $lastquery[0]);
  228. if (false !== strpos($countsql, 'LIMIT')) {
  229. $countsql = substr($countsql, 0, strpos($countsql, 'LIMIT'));
  230. }
  231. if (strexists(strtoupper($countsql), 'GROUP BY')) {
  232. $result = pdo_fetchall($countsql, $this->lastparams);
  233. $result = count($result);
  234. } else {
  235. $result = pdo_fetchcolumn($countsql, $this->lastparams);
  236. }
  237. return $result;
  238. }
  239. public function count() {
  240. $where = array();
  241. if (!empty($this->statements['WHERE'])) {
  242. foreach ($this->statements['WHERE'] as $row) {
  243. $where = array_merge($where, $row[1]);
  244. }
  245. }
  246. return pdo_count($this->statements['FROM'], $where);
  247. }
  248. public function exists() {
  249. $where = array();
  250. if (!empty($this->statements['WHERE'])) {
  251. foreach ($this->statements['WHERE'] as $row) {
  252. $where = array_merge($where, $row[1]);
  253. }
  254. }
  255. return pdo_exists($this->statements['FROM'], $where);
  256. }
  257. public function delete() {
  258. $where = $this->buildWhereArray();
  259. $result = pdo_delete($this->statements['FROM'], $where);
  260. $this->resetClause();
  261. return $result;
  262. }
  263. public function insert($replace = false) {
  264. $result = pdo_insert($this->statements['FROM'], $this->values, $replace);
  265. $this->resetClause();
  266. return $result;
  267. }
  268. public function update() {
  269. $where = $this->buildWhereArray();
  270. if (empty($where)) {
  271. return error(-1, '未指定更新条件');
  272. }
  273. $result = pdo_update($this->statements['FROM'], $this->values, $where);
  274. $this->resetClause();
  275. return $result;
  276. }
  277. private function buildQuery() {
  278. $query = '';
  279. foreach ($this->clauses as $clause => $separator) {
  280. if (!empty($this->statements[$clause])) {
  281. if (method_exists($this, 'buildQuery' . $clause)) {
  282. $query .= call_user_func(array($this, 'buildQuery' . $clause), $this->statements[$clause]);
  283. } elseif (is_string($separator)) {
  284. $query .= " $clause " . implode($separator, $this->statements[$clause]);
  285. } elseif (null === $separator) {
  286. $query .= " $clause " . $this->statements[$clause];
  287. }
  288. }
  289. }
  290. return trim($query);
  291. }
  292. private function buildQueryWhere() {
  293. $closure = array();
  294. $sql = '';
  295. foreach ($this->statements['WHERE'] as $i => $wheregroup) {
  296. $where = array();
  297. if (!empty($wheregroup[1]) && $wheregroup[1] instanceof Closure) {
  298. $closure[] = $wheregroup;
  299. } else {
  300. $where = \SqlPaser::parseParameter($wheregroup[1], 'AND', $this->currentTableAlias);
  301. $this->parameters = array_merge($this->parameters, $where['params']);
  302. $sql .= ' ' . $wheregroup[0] . ' ' . $where['fields'];
  303. }
  304. unset($this->statements['WHERE'][$i]);
  305. }
  306. foreach ($closure as $callback) {
  307. $callback[1]($this);
  308. $subsql = '';
  309. $where = array();
  310. foreach ($this->statements['WHERE'] as $i => $wheregroup) {
  311. $where = \SqlPaser::parseParameter($wheregroup[1], 'AND', $this->currentTableAlias);
  312. $this->parameters = array_merge($this->parameters, $where['params']);
  313. $subsql .= ' ' . $wheregroup[0] . ' ' . $where['fields'];
  314. unset($this->statements['WHERE'][$i]);
  315. }
  316. $subsql = ltrim(ltrim($subsql, ' AND '), ' OR ');
  317. $sql .= " {$callback[0]} ( $subsql )";
  318. }
  319. return empty($where['fields']) ? '' : ' WHERE ' . ltrim(ltrim($sql, ' AND '), ' OR ');
  320. }
  321. private function buildQueryWhereor() {
  322. $where = \SqlPaser::parseParameter($this->statements['WHEREOR'], 'OR', $this->currentTableAlias);
  323. $this->parameters = array_merge($this->parameters, $where['params']);
  324. if (empty($where['fields'])) {
  325. return '';
  326. }
  327. if (empty($this->statements['WHERE'])) {
  328. return " WHERE {$where['fields']} ";
  329. } else {
  330. return " OR {$where['fields']} ";
  331. }
  332. }
  333. private function buildQueryHaving() {
  334. $where = \SqlPaser::parseParameter($this->statements['HAVING'], 'AND', $this->currentTableAlias);
  335. $this->parameters = array_merge($this->parameters, $where['params']);
  336. return empty($where['fields']) ? '' : " HAVING {$where['fields']} ";
  337. }
  338. private function buildQueryFrom() {
  339. return ' FROM ' . tablename($this->statements['FROM']) . ' ' . $this->currentTableAlias;
  340. }
  341. private function buildQueryLeftjoin() {
  342. return $this->buildQueryJoin('LEFTJOIN');
  343. }
  344. private function buildQueryInnerjoin() {
  345. return $this->buildQueryJoin('INNERJOIN');
  346. }
  347. private function buildQueryJoin($clause) {
  348. if (empty($this->statements[$clause])) {
  349. return '';
  350. }
  351. $clause_operator = array(
  352. 'LEFTJOIN' => ' LEFT JOIN ',
  353. 'INNERJOIN' => ' INNER JOIN ',
  354. );
  355. $sql = '';
  356. foreach ($this->statements[$clause] as $tablename) {
  357. list($tablename, $alias) = explode(' ', $tablename);
  358. $sql .= $clause_operator[$clause] . tablename($tablename) . ' ' . $alias;
  359. if (!empty($this->statements['ON'][$tablename])) {
  360. $sql .= ' ON ';
  361. $split = '';
  362. foreach ($this->statements['ON'][$tablename] as $field => $condition) {
  363. $operator = '';
  364. if (strexists($field, ' ')) {
  365. list($field, $operator) = explode(' ', $field);
  366. }
  367. $operator = $operator ? $operator : '=';
  368. $field = '`' . str_replace('.', '`.`', $field) . '`';
  369. if (strexists($condition, '.')) {
  370. $condition = '`' . str_replace('.', '`.`', $condition) . '`';
  371. }
  372. $sql .= " $split $field $operator $condition ";
  373. $split = ' AND ';
  374. }
  375. }
  376. }
  377. return $sql;
  378. }
  379. private function buildQuerySelect() {
  380. return \SqlPaser::parseSelect($this->statements['SELECT'], $this->currentTableAlias);
  381. }
  382. private function buildQueryLimit() {
  383. return \SqlPaser::parseLimit($this->statements['LIMIT'], false);
  384. }
  385. private function buildQueryPage() {
  386. return \SqlPaser::parseLimit($this->statements['PAGE'], true);
  387. }
  388. private function buildQueryOrderby() {
  389. return \SqlPaser::parseOrderby($this->statements['ORDERBY'], $this->currentTableAlias);
  390. }
  391. private function buildQueryGroupby() {
  392. return \SqlPaser::parseGroupby($this->statements['GROUPBY'], $this->currentTableAlias);
  393. }
  394. private function buildWhereArray() {
  395. $where = array();
  396. if (!empty($this->statements['WHERE'])) {
  397. foreach ($this->statements['WHERE'] as $row) {
  398. $where = array_merge($where, $row[1]);
  399. }
  400. }
  401. return $where;
  402. }
  403. public function getLastQuery() {
  404. return array($this->lastsql, $this->lastparams);
  405. }
  406. }