PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Framework/Db/Select.php

http://lxsphp.googlecode.com/
PHP | 488 lines | 239 code | 72 blank | 177 comment | 25 complexity | 125dd8c301525ec9a0f0865128fc8eca MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * [ActiveRecord] ?????,?????SQL
  4. *
  5. * @version $Id: Select.php 341 2012-04-26 09:09:56Z linsir123 $
  6. * @package Db
  7. */
  8. class DbSelect
  9. {
  10. /**
  11. * ?????
  12. */
  13. const AS_TABLE = '`a`';
  14. /**
  15. * @var ???????,?`Select`??????
  16. * @static
  17. */
  18. private static $__partsInit = array(
  19. 'AGGREGATION' => null,
  20. 'DISTINCT' => false,
  21. 'FIELD' => array(),
  22. 'FROM' => array(),
  23. 'WHERE' => null,
  24. 'GROUP' => null,
  25. 'ORDER' => array(),
  26. 'LIMIT' => array()
  27. );
  28. /**
  29. * @var ?????
  30. */
  31. public $asTable;
  32. /**
  33. * @var ???????
  34. */
  35. public $fromSub = false;
  36. /**
  37. * @var ?????????
  38. * // ???SQL?????
  39. */
  40. public $joinTime = 0;
  41. /**
  42. * @var ??????
  43. * // ????,????
  44. */
  45. public $joinPart;
  46. /**
  47. * @var ??????
  48. */
  49. public $parts;
  50. /**
  51. * @var `?????`
  52. */
  53. public $table;
  54. /**
  55. * @var ??????
  56. */
  57. public $oCondition;
  58. /**
  59. * ????
  60. *
  61. * @param string $table ??????????
  62. * @param DbCondition $oCondition ??????
  63. */
  64. public function __construct($table, & $oCondition)
  65. {
  66. $this->table = $table;
  67. $this->oCondition = $oCondition;
  68. ///
  69. $this->clean();
  70. }
  71. /**
  72. * ???????SQL??
  73. *
  74. * @return string
  75. */
  76. public function __toString()
  77. {
  78. $sql = 'SELECT';
  79. foreach ($this->parts as $key => $value) {
  80. $method = '_to'.ucfirst($key);
  81. if (method_exists($this, $method)) {
  82. $string = call_user_func_array(array($this, $method), array($value));
  83. empty($string) or $sql .= ' '.$string;
  84. }
  85. }
  86. ///
  87. $this->clean();
  88. //pr($sql);
  89. return $sql;
  90. }
  91. /**
  92. * ??`SELECT`??????????(??)
  93. *
  94. * @param string $key ??
  95. * @param mixed $value ??
  96. */
  97. public function set($key, $value)
  98. {
  99. $this->parts[$key] = $value;
  100. }
  101. /**
  102. * ??`SELECT`??????????(??)
  103. *
  104. * @param string $key ??
  105. * @param mixed $value ??
  106. */
  107. public function push($key, $value)
  108. {
  109. array_push($this->parts[$key], $value);
  110. }
  111. /**
  112. * ????(???????????????)
  113. *
  114. * @param string $type ????
  115. * @param string $field ??
  116. */
  117. public function setAggregation($type, $field)
  118. {
  119. $field = empty($field) ? '*' : lpString::dbQuote($field);
  120. ///
  121. $this->set('FIELD', null);
  122. $this->set('AGGREGATION', "{$type}({$field})");
  123. }
  124. /**
  125. * ???????????
  126. *
  127. * @param string $table ??????????
  128. */
  129. public function setTable($table)
  130. {
  131. $this->table = $table;
  132. }
  133. /**
  134. * ??????
  135. * // 1??????????
  136. * // 2???????
  137. */
  138. public function clean()
  139. {
  140. $this->joinTime = 0;
  141. $this->joinPart = array();
  142. $this->parts = self::$__partsInit;
  143. $this->asTable = null;
  144. $this->fromSub = false;
  145. ///
  146. $this->oCondition->clean();
  147. }
  148. /**
  149. * ????,???????
  150. *
  151. * @param DbSelect $oSelect ??????
  152. * @param string $type ????
  153. * @param string $key ???
  154. * @param string $fKey ???
  155. */
  156. public function join($oSelect, $type, $key, $fKey)
  157. {
  158. list($asTableThis, $asTable) = $this->_getJoinAsList($oSelect);
  159. $this->push('FROM', " {$type} {$oSelect->table} AS {$asTable} ON
  160. {$asTableThis}.`{$key}`={$asTable}.`{$fKey}` ");
  161. ///
  162. $this->oCondition->join($oSelect->oCondition, $asTable);
  163. foreach (array('FIELD', 'ORDER') as $k)
  164. $this->joinPart[$k][] = array($oSelect->parts[$k], $asTable);
  165. ///
  166. if ($oSelect->joinTime > 0) {
  167. $tmp = $oSelect->parts['FROM'];
  168. foreach ($tmp as $v)
  169. $this->push('FROM', $v);
  170. ///
  171. foreach ($oSelect->joinPart as $k => $v) {
  172. if (empty($this->joinPart[$k]))
  173. $this->joinPart[$k] = $v;
  174. else
  175. $this->joinPart[$k] = array_merge($this->joinPart[$k], $v);
  176. }
  177. }
  178. ///
  179. $oSelect->clean();
  180. }
  181. /**
  182. * ?????
  183. *
  184. * @param DbSelect $oSelect ????
  185. */
  186. public function fromSub($oSelect)
  187. {
  188. $from = $oSelect->__toString();
  189. ///
  190. $this->fromSub = true;
  191. $this->asTable = '`b`';
  192. $this->push('FROM', "({$from}) AS {$this->asTable}");
  193. }
  194. /// ??????? ///
  195. /**
  196. * ??????????
  197. */
  198. private function _getAsTable($default = null)
  199. {
  200. if ( ! empty($default))
  201. return $default;
  202. ///
  203. return empty($this->asTable) ? self::AS_TABLE : $this->asTable;
  204. }
  205. /**
  206. * ????????????
  207. */
  208. private function _getJoinAsList($oSelect)
  209. {
  210. static $list = array('`b`', '`c`', '`d`');
  211. if ($oSelect->joinTime > 0) {
  212. $this->joinTime = $oSelect->joinTime;
  213. $this->asTable = $this->oCondition->asTable = $list[$this->joinTime++];
  214. $asTable = self::AS_TABLE;
  215. } else
  216. $asTable = $list[$this->joinTime++];
  217. ///
  218. return array($this->_getAsTable(), $asTable);
  219. }
  220. /**
  221. * ??????
  222. */
  223. private function _toWhere()
  224. {
  225. return $this->oCondition->__toString();
  226. }
  227. /**
  228. * ??????
  229. */
  230. private function _toDistinct($data)
  231. {
  232. return ( ! $data) ? '' : 'DISTINCT';
  233. }
  234. /**
  235. * ????
  236. */
  237. private function _toAggregation($data)
  238. {
  239. return empty($data) ? '' : $data;
  240. }
  241. /**
  242. * ?????
  243. */
  244. private function _toFrom($data)
  245. {
  246. if ( ! $this->fromSub) {
  247. $from = "{$this->table} AS ".$this->_getAsTable();
  248. array_unshift($data, $from);
  249. }
  250. ///
  251. return 'FROM '.implode(' ', $data);
  252. }
  253. /**
  254. * ??????
  255. */
  256. private function _toLimit($data)
  257. {
  258. if (empty($data))
  259. return '';
  260. ///
  261. list($start, $offset) = $data;
  262. return "LIMIT {$start},{$offset}";
  263. }
  264. /**
  265. * ??????
  266. *
  267. * ??????
  268. * @example array(
  269. '`talbe`.id',
  270. 'username,password',
  271. 'position as p,count(`id`) as `count`',
  272. )
  273. */
  274. private function _toField($data)
  275. {
  276. if ( ! empty($this->parts['AGGREGATION']))
  277. return '';
  278. ///
  279. $data = $this->_formatField($data);
  280. if (is_array($this->joinPart['FIELD'])) {
  281. foreach ($this->joinPart['FIELD'] as $v) {
  282. list($tmp, $asTable) = $v;
  283. ///
  284. $tmp = $this->_formatField($tmp, $asTable);
  285. $data = array_merge($data, $tmp);
  286. }
  287. }
  288. return implode(', ', $data);
  289. }
  290. /**
  291. * ??????
  292. *
  293. * ??????
  294. * @example array(
  295. array('id', 3),
  296. array('id', 0),
  297. array('`table`.`id` desc', 2),
  298. )
  299. */
  300. private function _toOrder($data)
  301. {
  302. $list = $indexes = array();
  303. foreach ($data as $v) {
  304. $v[] = null; $list[] = $v; $indexes[] = $v[1];
  305. }
  306. if (is_array($this->joinPart['ORDER'])) {
  307. foreach ($this->joinPart['ORDER'] as $data) {
  308. list($data, $asTable) = $data;
  309. foreach ($data as $v) {
  310. $v[] = $asTable; $list[] = $v; $indexes[] = $v[1];
  311. }
  312. }
  313. }
  314. ///
  315. $data = array();
  316. array_multisort($indexes, SORT_DESC, $list);
  317. foreach ($list as $v) {
  318. list($field, , $preTable, $asTable) = $v;
  319. $tmp = $this->_formatOrder($field, $asTable, $preTable);
  320. if ( ! empty($tmp))
  321. $data[] = $tmp;
  322. }
  323. ///
  324. if (empty($data))
  325. return '';
  326. return "ORDER BY ".implode(',', $data);
  327. }
  328. /**
  329. * ??????
  330. *
  331. * ??????
  332. * @example "`table`.`id`"
  333. * @example "`table`.id"
  334. * @example "table.`id`"
  335. * @example "`id`"
  336. * @example "id, name"
  337. */
  338. private function _toGroup($data)
  339. {
  340. $data = $this->_formatGroup($data);
  341. if (empty($data))
  342. return '';
  343. return "GROUP BY ".$data;
  344. }
  345. /**
  346. * FIELD,??
  347. */
  348. private function _formatField($data, $asTable = null)
  349. {
  350. $asTable = $this->_getAsTable($asTable);
  351. ///
  352. if (empty($data))
  353. return array($asTable.'.*');
  354. /// "`table`.`position` as p"
  355. $pattern1 = "/^(`?(\w+)`?\.)?`?(\w+)`?( AS `?(\w+)`?)?$/i";
  356. /// "count(`table`.`id`) as `count`"
  357. $pattern2 = "/^(\w+)\((`?(\w+)`?\.)?`?(\w+)`?\)( AS `?(\w+)`?)?$/i";
  358. ///
  359. $columns = array();
  360. foreach ($data as $v) {
  361. foreach (explode(',', $v) as $field) {
  362. $field = trim($field);
  363. if (preg_match($pattern1, $field, $m)) {
  364. ///
  365. $field = $asTable.'.'.lpString::dbQuote($m[3]);
  366. if (isset($m[5]) && ! empty($m[5]))
  367. $field .= ' AS '.lpString::dbQuote($m[5]);
  368. $columns[] = $field;
  369. } elseif (preg_match($pattern2, $field, $m)) {
  370. ///
  371. $field = strtoupper($m[1]);
  372. $field .= '('.$asTable.'.'.lpString::dbQuote($m[4]).')';
  373. if (isset($m[6]) && ! empty($m[6]))
  374. $field .= ' AS '.lpString::dbQuote($m[6]);
  375. $columns[] = $field;
  376. }
  377. }
  378. }
  379. return $columns;
  380. }
  381. /**
  382. * ORDER,??
  383. */
  384. private function _formatOrder($data, $asTable = null, $preTable = true)
  385. {
  386. if ($preTable)
  387. $asTable = $this->_getAsTable($asTable).'.';
  388. else
  389. $asTable = '';
  390. ///
  391. $pattern = "/^(`?(\w+)`?\.)?`?(\w+)`?( (asc|desc))?$/i";
  392. ///
  393. if (preg_match($pattern, $data, $m))
  394. return $asTable.
  395. lpString::dbQuote($m[3]).
  396. ' '.($m[5] ? strtoupper($m[5]) : "ASC");
  397. return '';
  398. }
  399. /**
  400. * GROUP,??
  401. */
  402. private function _formatGroup($data, $asTable = null)
  403. {
  404. $asTable = $this->_getAsTable($asTable);
  405. ///
  406. $pattern = "/^(`?(\w+)`?\.)?`?(\w+)`?$/i";
  407. ///
  408. $columns = array();
  409. foreach (explode(',', $data) as $field) {
  410. if (preg_match($pattern, $data, $m))
  411. $columns[] = $asTable.
  412. '.'.lpString::dbQuote($m[3]);
  413. }
  414. return implode(',', $columns);
  415. }
  416. }