model.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. <?php
  2. /**
  3. * 核心文件
  4. *
  5. * 模型类
  6. */
  7. class Model
  8. {
  9. protected $name = '';
  10. protected $table_prefix = '';
  11. protected $init_table = null;
  12. protected $table_name = '';
  13. protected $options = array();
  14. protected $pk = 'id';
  15. protected $db = null;
  16. protected $fields = array();
  17. protected $unoptions = true; //是否清空参数项,默认清除
  18. public function __construct($table = null)
  19. {
  20. $this->table_prefix = DBPRE;
  21. $this->init($table);
  22. }
  23. public function init($table)
  24. {
  25. $this->options = [];
  26. $this->fields = [];
  27. if (!is_null($table)){
  28. $this->table_name = $table;
  29. $this->tableInfo($table);
  30. }
  31. if (!is_object($this->db)){
  32. $this->db = new ModelDb();
  33. }
  34. }
  35. /**
  36. * 删除表主键缓存
  37. */
  38. public static function dropTablePkArrayCache()
  39. {
  40. dkcache('field/_pk');
  41. }
  42. /**
  43. * 生成表结构信息
  44. *
  45. * @param string $table
  46. * @return
  47. */
  48. public function tableInfo($table)
  49. {
  50. if (empty($table)) return false;
  51. //只取主键,find(2)等自动匹配主键时使用
  52. static $stFields = null;
  53. if($stFields == null)
  54. {
  55. if (C('cache_open')) {
  56. $stFields = rkcache('field/_pk', __CLASS__ . '::fetchTablePkArray');
  57. }
  58. else
  59. {
  60. if (file_exists(BASE_DATA_PATH.'/cache/fields/_pk.php')){
  61. $stFields = require(BASE_DATA_PATH.'/cache/fields/_pk.php');
  62. } else {
  63. $_pk_array = self::fetchTablePkArray();
  64. F('_pk', $_pk_array, 'cache/fields');
  65. $stFields = $_pk_array;
  66. }
  67. }
  68. }
  69. $this->fields = $stFields;
  70. return $this->fields[$table];
  71. }
  72. public static function fetchTablePkArray()
  73. {
  74. $full_table = Db::showTables();
  75. $_pk_array = array();
  76. $count = strlen(C('tablepre'));
  77. foreach ($full_table as $v_table) {
  78. $v = array_values($v_table);
  79. if (substr($v[0],0,$count) != C('tablepre')) continue;
  80. $tb = preg_replace('/^'.C('tablepre').'/', '', $v[0]);
  81. $fields = DB::showColumns($tb);
  82. foreach ((array)$fields as $k=>$v) {
  83. if($v['primary']) {
  84. $_pk_array[$tb] = $k;break;
  85. }
  86. }
  87. }
  88. return $_pk_array;
  89. }
  90. public function __call($method,$args)
  91. {
  92. if(in_array(strtolower($method),array('table','order','where','on','limit','having','group','lock','master','distinct','index','attr','key'),true))
  93. {
  94. $this->options[strtolower($method)] = $args[0];
  95. if (strtolower($method) == 'table')
  96. {
  97. if (strpos($args[0],',') !== false)
  98. {
  99. $args[0] = explode(',',$args[0]);
  100. $this->table_name = '';
  101. foreach ((array)$args[0] as $value) {
  102. $this->tableInfo($value);
  103. }
  104. } else {
  105. $this->table_name = $args[0];
  106. $this->fields = array();
  107. $this->tableInfo($args[0]);
  108. }
  109. }
  110. return $this;
  111. }
  112. elseif(in_array(strtolower($method),array('page'),true))
  113. {
  114. if ($args[0] == null){
  115. return $this;
  116. }elseif(!is_numeric($args[0]) || $args[0] <= 0){
  117. $args[0] = 10;
  118. }
  119. if (is_numeric($args[1]) && $args[1] > 0){
  120. //page(2,30)形式,传入了每页显示数据和总记录数
  121. if ($args[0] > 0){
  122. $this->options[strtolower($method)] = $args[0];
  123. pagecmd('setEachNum', $args[0]);
  124. $this->unoptions = false;
  125. pagecmd('setTotalNum', $args[1]);
  126. return $this;
  127. }else{
  128. $args[0] = 10;
  129. }
  130. }
  131. $this->options[strtolower($method)] = $args[0];
  132. pagecmd('setEachNum', $args[0]);
  133. $this->unoptions = false;
  134. pagecmd('setTotalNum', $this->get_field('COUNT(*) AS nc_count'));
  135. return $this;
  136. }
  137. elseif(in_array(strtolower($method),array('min','max','count','sum','avg'),true))
  138. {
  139. $field = isset($args[0])?$args[0]:'*';
  140. return $this->get_field(strtoupper($method).'('.$field.') AS nc_'.$method);
  141. }
  142. elseif(strtolower($method)=='count1')
  143. {
  144. $field = isset($args[0])?$args[0]:'*';
  145. $options['field'] = ('count('.$field.') AS nc_count');
  146. $options = $this->parse_options($options);
  147. $options['limit'] = 1;
  148. $result = $this->db->select($options);
  149. if(!empty($result)) {
  150. return reset($result[0]);
  151. } else {
  152. return 0;
  153. }
  154. }
  155. elseif(strtolower(substr($method,0,6))=='getby_')
  156. {
  157. $field = substr($method,6);
  158. $where[$field] = $args[0];
  159. return $this->where($where)->find();
  160. }
  161. elseif(strtolower(substr($method,0,7))=='getfby_')
  162. {
  163. $name = substr($method,7);
  164. $where[$name] =$args[0];
  165. //getfby_方法只返回第一个字段值
  166. if (strpos($args[1],',') !== false){
  167. $args[1] = substr($args[1],0,strpos($args[1],','));
  168. }
  169. return $this->where($where)->get_field($args[1]);
  170. }
  171. else
  172. {
  173. $error = 'Model Error: Function '.$method.' is not exists!';
  174. throw_exception($error);
  175. return;
  176. }
  177. }
  178. /**
  179. * 查询
  180. *
  181. * @param array/int $options
  182. * @return null/array
  183. */
  184. public function select($options=array())
  185. {
  186. if(is_string($options) || is_numeric($options)) {
  187. // 默认根据主键查询
  188. $pk = $this->get_pk();
  189. if(strpos($options,',')) {
  190. $where[$pk] = array('IN',$options);
  191. }else{
  192. $where[$pk] = $this->fields[$this->table_name]['_pk_type'] == 'int' ? intval($options) : $options;
  193. }
  194. $options = array();
  195. $options['where'] = $where;
  196. }
  197. $options = $this->parse_options($options);
  198. if ($options['limit'] !== false) {
  199. if (empty($options['where']) && empty($options['limit'])){
  200. //如果无条件,默认检索30条数据
  201. $options['limit'] = 30;
  202. }elseif ($options['where'] !== true && empty($options['limit'])){
  203. //如果带WHERE,但无LIMIT,最多只检索1000条记录
  204. $options['limit'] = 1000;
  205. }
  206. }
  207. $resultSet = $this->db->select($options);
  208. if(empty($resultSet)) {
  209. return array();
  210. }
  211. if ($options['key'] != '' && is_array($resultSet))
  212. {
  213. $tmp = array();
  214. foreach ($resultSet as $value) {
  215. $tmp[$value[$options['key']]] = $value;
  216. }
  217. $resultSet = $tmp;
  218. }
  219. return $resultSet;
  220. }
  221. /**
  222. * 取得第N列内容
  223. *
  224. * @param array/int $options
  225. * @return null/array
  226. */
  227. public function getfield($col = 1)
  228. {
  229. if (intval($col)<=1) $col = 1;
  230. $options = $this->parse_options();
  231. if (empty($options['where']) && empty($options['limit'])){
  232. //如果无条件,默认检索30条数据
  233. $options['limit'] = 30;
  234. }elseif ($options['where'] !== true && empty($options['limit'])){
  235. //如果带WHERE,但无LIMIT,最多只检索1000条记录
  236. $options['limit'] = 1000;
  237. }
  238. $resultSet = $this->db->select($options);
  239. if(false === $resultSet) {
  240. return false;
  241. }
  242. if(empty($resultSet)) {
  243. return null;
  244. }
  245. $return = array();
  246. $cols = array_keys($resultSet[0]);
  247. foreach ((array)$resultSet as $k => $v) {
  248. $return[$k] = $v[$cols[$col-1]];
  249. }
  250. return $return;
  251. }
  252. protected function parse_options($options=array())
  253. {
  254. if(is_array($options)) $options = array_merge($this->options,$options);
  255. if(!isset($options['table'])){
  256. $options['table'] =$this->getTableName();
  257. }elseif(false !== strpos(trim($options['table'],', '),',')){
  258. foreach(explode(',', trim($options['table'],', ')) as $val){
  259. $tmp[] = $this->getTableName($val).' AS `'.$val.'`';
  260. }
  261. $options['table'] = implode(',',$tmp);
  262. }else{
  263. $options['table'] =$this->getTableName($options['table']);
  264. }
  265. if ($this->unoptions === true){
  266. $this->options = array();
  267. }else{
  268. $this->unoptions = true;
  269. }
  270. return $options;
  271. }
  272. public function get_field($field,$sepa=null)
  273. {
  274. $options['field'] = $field;
  275. $options = $this->parse_options($options);
  276. if(strpos($field,',')) { // 多字段
  277. $resultSet = $this->db->select($options);
  278. if(!empty($resultSet)) {
  279. $_field = explode(',', $field);
  280. $field = array_keys($resultSet[0]);
  281. $move = $_field[0]==$_field[1]?false:true;
  282. $key = array_shift($field);
  283. $key2 = array_shift($field);
  284. $cols = array();
  285. $count = count($_field);
  286. foreach ($resultSet as $result){
  287. $name = $result[$key];
  288. if($move) { // 删除键值记录
  289. unset($result[$key]);
  290. }
  291. if(2==$count) {
  292. $cols[$name] = $result[$key2];
  293. }else{
  294. $cols[$name] = is_null($sepa)?$result:implode($sepa,$result);
  295. }
  296. }
  297. return $cols;
  298. }
  299. }else{
  300. $options['limit'] = 1;
  301. $result = $this->db->select($options);
  302. if(!empty($result)) {
  303. return reset($result[0]);
  304. }
  305. }
  306. return null;
  307. }
  308. /**
  309. * 返回一条记录
  310. *
  311. * @param string/int $options
  312. * @return null/array
  313. */
  314. public function find($options=null)
  315. {
  316. if(is_numeric($options) || is_string($options)) {
  317. $where[$this->get_pk()] = $options;
  318. $options = array();
  319. $options['where'] = $where;
  320. } elseif (!empty($options)) {
  321. return false;
  322. }
  323. $options['limit'] = 1;
  324. $options = $this->parse_options($options);
  325. $result = $this->db->select($options);
  326. if(empty($result)) {
  327. return array();
  328. }
  329. return $result[0];
  330. }
  331. /**
  332. * 删除
  333. *
  334. * @param array $options
  335. * @return bool/int
  336. */
  337. public function delete($options=array())
  338. {
  339. if(is_numeric($options) || is_string($options))
  340. {
  341. // 根据主键删除记录
  342. $pk = $this->get_pk();
  343. if(strpos($options,',')) {
  344. $where[$pk] = array('IN', $options);
  345. }else{
  346. $where[$pk] = $this->fields['_pk_type'] == 'int' ? intval($options) : $options;
  347. $pkValue = $options;
  348. }
  349. $options = array();
  350. $options['where'] = $where;
  351. }
  352. $options = $this->parse_options($options);
  353. $result = $this->db->delete($options);
  354. if(false !== $result) {
  355. return true;
  356. // $data = array();
  357. // if(isset($pkValue)) $data[$pk] = $pkValue;
  358. }
  359. return $result;
  360. }
  361. /**
  362. * 更新
  363. *
  364. * @param array $data
  365. * @param array $options
  366. * @return boolean
  367. */
  368. public function update($data='',$options=array()) {
  369. if(empty($data)) return false;
  370. // 分析表达式
  371. $options = $this->parse_options($options);
  372. if(!isset($options['where'])) {
  373. // 如果存在主键,自动作为更新条件
  374. if(isset($data[$this->get_pk()])) {
  375. $pk = $this->get_pk();
  376. $where[$pk] = $data[$pk];
  377. $options['where'] = $where;
  378. $pkValue = $data[$pk];
  379. unset($data[$pk]);
  380. }else{
  381. return false;
  382. }
  383. }
  384. $result = $this->db->update($data,$options);
  385. if(false !== $result) {
  386. return true;
  387. }
  388. return $result;
  389. }
  390. public function affected_rows()
  391. {
  392. return $this->db->affected_rows();
  393. }
  394. /**
  395. * 插入
  396. *
  397. * @param array $data
  398. * @param bool $replace
  399. * @param array $options
  400. * @return mixed int/false
  401. */
  402. public function insert($data='', $replace=false, $options=array()) {
  403. if(empty($data)) return false;
  404. $options = $this->parse_options($options);
  405. $result = $this->db->insert($data,$options,$replace);
  406. if(false !== $result ) {
  407. $insertId = $this->getLastId();
  408. if($insertId) {
  409. return $insertId;
  410. }
  411. }
  412. return $result;
  413. }
  414. /**
  415. * 批量插入
  416. *
  417. * @param array $dataList
  418. * @param array $options
  419. * @param bool $replace
  420. * @return boolean
  421. */
  422. public function insertAll($dataList,$options=array(),$replace=false){
  423. if(empty($dataList)) return false;
  424. // 分析表达式
  425. $options = $this->parse_options($options);
  426. // 写入数据到数据库
  427. $result = $this->db->insertAll($dataList,$options,$replace);
  428. if(false !== $result ) return true;
  429. return $result;
  430. }
  431. /**
  432. * 直接SQL查询,返回查询结果
  433. *
  434. * @param string $sql
  435. * @return array
  436. */
  437. public function query($sql){
  438. return DB::getAll($sql);
  439. }
  440. /**
  441. * 执行SQL,用于 更新、写入、删除操作
  442. *
  443. * @param string $sql
  444. * @return
  445. */
  446. public function execute($sql){
  447. return DB::execute($sql);
  448. }
  449. /**
  450. * 开始事务
  451. *
  452. * @param string $host
  453. */
  454. public static function beginTransaction($host = 'master'){
  455. Db::beginTransaction($host);
  456. }
  457. /**
  458. * 提交事务
  459. *
  460. * @param string $host
  461. */
  462. public static function commit($host = 'master'){
  463. Db::commit($host);
  464. }
  465. /**
  466. * 回滚事务
  467. *
  468. * @param string $host
  469. */
  470. public static function rollback($host = 'master'){
  471. Db::rollback($host);
  472. }
  473. /**
  474. * 清空表
  475. *
  476. * @return boolean
  477. */
  478. public function clear(){
  479. if (!$this->table_name && !$this->options['table']) return false;
  480. $options = $this->parse_options();
  481. return $this->db->clear($options);
  482. }
  483. /**
  484. * 取得表名
  485. *
  486. * @param string $table
  487. * @return string
  488. */
  489. protected function getTableName($table = null){
  490. if (is_null($table)){
  491. $return = '`'.$this->table_prefix.$this->table_name.'`';
  492. }else{
  493. $return = '`'.$this->table_prefix.$table.'`';
  494. }
  495. return $return;
  496. }
  497. /**
  498. * 取得最后插入的ID
  499. *
  500. * @return int
  501. */
  502. public function getLastId() {
  503. return $this->db->getLastId();
  504. }
  505. /**
  506. * 指定查询字段 支持字段排除
  507. *
  508. * @param mixed $field
  509. * @param boolean $except
  510. * @return Model
  511. */
  512. public function field($field,$except=false){
  513. if(true === $field) {// 获取全部字段
  514. $fields = $this->getFields();
  515. $field = $fields?$fields:'*';
  516. }elseif($except) {// 字段排除
  517. if(is_string($field)) {
  518. $field = explode(',',$field);
  519. }
  520. $fields = $this->getFields();
  521. $field = $fields?array_diff($fields,$field):$field;
  522. }
  523. $this->options['field'] = $field;
  524. return $this;
  525. }
  526. /**
  527. * 取得数据表字段信息
  528. *
  529. * @return mixed
  530. */
  531. public function getFields(){
  532. if($this->fields) {
  533. $fields = $this->fields;
  534. unset($fields['_autoinc'],$fields['_pk'],$fields['_type']);
  535. return $fields;
  536. }
  537. return false;
  538. }
  539. /**
  540. * 组装join
  541. *
  542. * @param string $join
  543. * @return Model
  544. */
  545. public function join($join) {
  546. if (false !== strpos($join,',')){
  547. foreach (explode(',',$join) as $key=>$val) {
  548. if (in_array(strtolower($val),array('left','inner','right'))){
  549. $this->options['join'][] = strtoupper($val).' JOIN';
  550. }else{
  551. $this->options['join'][] = 'LEFT JOIN';
  552. }
  553. }
  554. }elseif (in_array(strtolower($join),array('left','inner','right'))){
  555. $this->options['join'][] = strtoupper($join).' JOIN';
  556. }
  557. return $this;
  558. }
  559. /**
  560. * 取得主键
  561. *
  562. * @return string
  563. */
  564. public function get_pk() {
  565. return isset($this->fields[$this->table_name])?$this->fields[$this->table_name]:$this->pk;
  566. }
  567. /**
  568. * 检查非数据字段
  569. *
  570. * @param array $data
  571. * @return array
  572. */
  573. protected function chk_field($data) {
  574. if(!empty($this->fields[$this->table_name])) {
  575. foreach ($data as $key=>$val){
  576. if(!in_array($key,$this->fields[$this->table_name],true)){
  577. unset($data[$key]);
  578. }
  579. }
  580. }
  581. return $data;
  582. }
  583. public function setInc($field, $step=1) {
  584. return $this->set_field($field,array('exp',$field.'+'.$step));
  585. }
  586. public function setDec($field,$step=1) {
  587. return $this->set_field($field,array('exp',$field.'-'.$step));
  588. }
  589. public function set_field($field,$value='') {
  590. if(is_array($field)) {
  591. $data = $field;
  592. }else{
  593. $data[$field] = $value;
  594. }
  595. return $this->update($data);
  596. }
  597. /**
  598. * 显示分页链接
  599. *
  600. * @param int $style 分页风格
  601. * @return string
  602. */
  603. public function showpage($style = null){
  604. return pagecmd('show',$style);
  605. }
  606. /**
  607. * 获取分页总数
  608. *
  609. * @return string
  610. */
  611. public function gettotalnum(){
  612. return pagecmd('gettotalnum');
  613. }
  614. /**
  615. * 获取总页数
  616. *
  617. * @return string
  618. */
  619. public function gettotalpage(){
  620. return pagecmd('gettotalpage');
  621. }
  622. /**
  623. * 清空MODEL中的options、table_name属性
  624. *
  625. */
  626. public function cls(){
  627. $this->options = array();
  628. $this->table_name = '';
  629. return $this;
  630. }
  631. public function checkActive($host = 'master') {
  632. $this->db->checkActive($host);
  633. }
  634. }
  635. /**
  636. * 完成模型SQL组装
  637. *
  638. * SQL Helper
  639. */
  640. class ModelDb
  641. {
  642. protected $comparison = array('eq'=>'=',
  643. 'neq'=>'<>',
  644. 'gt'=>'>',
  645. 'egt'=>'>=',
  646. 'lt'=>'<',
  647. 'elt'=>'<=',
  648. 'notlike'=>'NOT LIKE',
  649. 'like'=>'LIKE',
  650. 'in'=>'IN',
  651. 'not in'=>'NOT IN');
  652. // 查询表达式
  653. protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%INDEX%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%';
  654. public function select($options=array())
  655. {
  656. if(is_mobile())
  657. {
  658. $sql = $this->buildSelectSql($options);
  659. $start = microtime(true);
  660. $result = DB::getAll($sql,($options['lock'] === true || $options['master'] === true || defined('TRANS_MASTER')) ? 'master' : 'slave');
  661. perfor_period("model",$start,"getAll");
  662. return $result;
  663. }
  664. else
  665. {
  666. static $_cache = array();
  667. $sql = $this->buildSelectSql($options);
  668. if ($options['cache'] === true)
  669. {
  670. $key = is_string($_cache['cache_key']) ? $_cache['cache_key'] : md5($sql);
  671. if (isset($_cache[$key])) {
  672. return $_cache[$key];
  673. }
  674. }
  675. $result = DB::getAll($sql,($options['lock'] === true || $options['master'] === true || defined('TRANS_MASTER')) ? 'master' : 'slave');
  676. if ($options['cache'] === true && !isset($_cache[$key])){
  677. $_cache[$key] = $result;
  678. }
  679. return $result;
  680. }
  681. }
  682. public function buildSelectSql($options=array())
  683. {
  684. if (is_numeric($options['page']))
  685. {
  686. $page = pagecmd('obj');
  687. if ($options['limit'] !== 1){
  688. $options['limit'] = $page->getLimitStart().",".$page->getEachNum();
  689. }
  690. }
  691. $sql = $this->parseSql($this->selectSql,$options);
  692. $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
  693. return $sql;
  694. }
  695. public function parseSql($sql,$options=array())
  696. {
  697. $sql = str_replace(
  698. array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%INDEX%'),
  699. array(
  700. $this->parseTable($options),
  701. $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
  702. $this->parseField(isset($options['field'])?$options['field']:'*'),
  703. $this->parseJoin(isset($options['on'])?$options:array()),
  704. $this->parseWhere(isset($options['where'])?$options['where']:''),
  705. $this->parseGroup(isset($options['group'])?$options['group']:''),
  706. $this->parseHaving(isset($options['having'])?$options['having']:''),
  707. $this->parseOrder(isset($options['order'])?$options['order']:''),
  708. $this->parseLimit(isset($options['limit'])?$options['limit']:''),
  709. $this->parseUnion(isset($options['union'])?$options['union']:''),
  710. $this->parseIndex(isset($options['index'])?$options['index']:'')
  711. ),$sql);
  712. return $sql;
  713. }
  714. protected function parseUnion(){
  715. return '';
  716. }
  717. protected function parseLock($lock=false) {
  718. if(!$lock) return '';
  719. return ' FOR UPDATE ';
  720. }
  721. protected function parseIndex($value){
  722. return empty($value) ? '':' USE INDEX ('.$value.') ';
  723. }
  724. protected function parseValue($value)
  725. {
  726. if(is_string($value) || is_numeric($value)) {
  727. $value = '\''.$this->escapeString($value).'\'';
  728. }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){
  729. $value = $value[1];
  730. }elseif(is_array($value)) {
  731. $value = array_map(array($this, 'parseValue'),$value);
  732. }elseif(is_null($value)){
  733. $value = 'NULL';
  734. }
  735. return $value;
  736. }
  737. protected function parseField($fields)
  738. {
  739. if(is_string($fields) && strpos($fields,',')) {
  740. $fields = explode(',',$fields);
  741. }
  742. if(is_array($fields))
  743. {
  744. //字段别名定义
  745. $array = array();
  746. foreach ($fields as $key=>$field){
  747. if(!is_numeric($key))
  748. $array[] = $this->parseKey($key).' AS '.$this->parseKey($field);
  749. else
  750. $array[] = $this->parseKey($field);
  751. }
  752. $fieldsStr = implode(',', $array);
  753. }
  754. elseif (is_string($fields) && !empty($fields)) {
  755. $fieldsStr = $this->parseKey($fields);
  756. }
  757. else {
  758. $fieldsStr = '*';
  759. }
  760. return $fieldsStr;
  761. }
  762. protected function parseTable($options)
  763. {
  764. if ($options['on']) return null;
  765. $tables = $options['table'];
  766. if(is_array($tables)) {// 别名定义
  767. $array = array();
  768. foreach ($tables as $table=>$alias){
  769. if(!is_numeric($table))
  770. $array[] = $this->parseKey($table).' '.$this->parseKey($alias);
  771. else
  772. $array[] = $this->parseKey($table);
  773. }
  774. $tables = $array;
  775. }
  776. elseif(is_string($tables))
  777. {
  778. $tables = explode(',',$tables);
  779. array_walk($tables, array(&$this, 'parseKey'));
  780. // if (strpos($options['table'],',') === false){
  781. // $tables = $options['table'].' AS '.$options['table'];
  782. // }
  783. // $tables = explode(',',$tables);
  784. }
  785. return implode(',',$tables);
  786. }
  787. protected function parseWhere($where)
  788. {
  789. $whereStr = '';
  790. if(is_string($where)) {
  791. $whereStr = $where;
  792. }
  793. elseif(is_array($where))
  794. {
  795. if(isset($where['_op'])) {
  796. // 定义逻辑运算规则 例如 OR XOR AND NOT
  797. $operate = ' '.strtoupper($where['_op']).' ';
  798. unset($where['_op']);
  799. } else {
  800. $operate = ' AND ';
  801. }
  802. foreach ($where as $key=>$val)
  803. {
  804. // $whereStr .= '( ';
  805. // if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
  806. // $error = 'Model Error: args '.$key.' is wrong!';
  807. // throw_exception($error);
  808. // }
  809. // $key = trim($key);
  810. // $whereStr .= $this->parseWhereItem($this->parseKey($key),$val);
  811. // $whereStr .= ' )'.$operate;
  812. $whereStrTemp = '';
  813. if(0===strpos($key,'_')) {
  814. // 解析特殊条件表达式
  815. // $whereStr .= $this->parseThinkWhere($key,$val);
  816. }
  817. else
  818. {
  819. // 查询字段的安全过滤
  820. if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
  821. throw_exception($error);
  822. }
  823. // 多条件支持
  824. $multi = is_array($val) && isset($val['_multi']);
  825. $key = trim($key);
  826. if(strpos($key,'|'))
  827. { // 支持 name|title|nickname 方式定义查询字段
  828. $array = explode('|',$key);
  829. $str = array();
  830. foreach ($array as $m=>$k){
  831. $v = $multi?$val[$m]:$val;
  832. $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')';
  833. }
  834. $whereStrTemp .= implode(' OR ',$str);
  835. }
  836. elseif(strpos($key,'&'))
  837. {
  838. $array = explode('&',$key);
  839. $str = array();
  840. foreach ($array as $m=>$k){
  841. $v = $multi?$val[$m]:$val;
  842. $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')';
  843. }
  844. $whereStrTemp .= implode(' AND ',$str);
  845. }
  846. else
  847. {
  848. $whereStrTemp .= $this->parseWhereItem($this->parseKey($key),$val);
  849. }
  850. }
  851. if(!empty($whereStrTemp)) {
  852. $whereStr .= '( '.$whereStrTemp.' )'.$operate;
  853. }
  854. }
  855. $whereStr = substr($whereStr,0,-strlen($operate));
  856. }
  857. return empty($whereStr)?'':' WHERE '.$whereStr;
  858. }
  859. // where子单元分析
  860. protected function parseWhereItem($key,$val)
  861. {
  862. $whereStr = '';
  863. if(is_array($val))
  864. {
  865. if(is_string($val[0]))
  866. {
  867. if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算
  868. $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);
  869. }
  870. elseif('exp'==strtolower($val[0])){ // 使用表达式
  871. // $whereStr .= ' ('.$key.' '.$val[1].') ';
  872. $whereStr .= $val[1];
  873. }
  874. elseif(preg_match('/IN/i',$val[0]))
  875. { // IN 运算
  876. if(isset($val[2]) && 'exp'==$val[2]) {
  877. $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1];
  878. }
  879. else
  880. {
  881. if (empty($val[1])){
  882. $whereStr .= $key.' '.strtoupper($val[0]).'(\'\')';
  883. }elseif(is_string($val[1]) || is_numeric($val[1])) {
  884. $val[1] = explode(',',$val[1]);
  885. $zone = implode(',',$this->parseValue($val[1]));
  886. $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
  887. }elseif(is_array($val[1])){
  888. $zone = implode(',',$this->parseValue($val[1]));
  889. $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
  890. }
  891. }
  892. }
  893. elseif(preg_match('/BETWEEN/i',$val[0]))
  894. {
  895. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  896. if($data[0] && $data[1]) {
  897. $whereStr .= ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )';
  898. } elseif ($data[0]) {
  899. $whereStr .= $key.' '.$this->comparison['gt'].' '.$this->parseValue($data[0]);
  900. } elseif ($data[1]) {
  901. $whereStr .= $key.' '.$this->comparison['lt'].' '.$this->parseValue($data[1]);
  902. }
  903. }
  904. elseif(preg_match('/TIME/i',$val[0]))
  905. {
  906. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  907. if($data[0] && $data[1]) {
  908. $whereStr .= ' ('.$key.' BETWEEN '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1] + 86400 -1).' )';
  909. } elseif ($data[0]) {
  910. $whereStr .= $key.' '.$this->comparison['gt'].' '.$this->parseValue($data[0]);
  911. } elseif ($data[1]) {
  912. $whereStr .= $key.' '.$this->comparison['lt'].' '.$this->parseValue($data[1] + 86400);
  913. }
  914. }
  915. else{
  916. $error = 'Model Error: args '.$val[0].' is error!';
  917. throw_exception($error);
  918. }
  919. }
  920. else
  921. {
  922. $count = count($val);
  923. if(is_array($val[$count-1]) == false && in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) {
  924. $rule = strtoupper(trim($val[$count-1]));
  925. $count = $count -1;
  926. }else{
  927. $rule = 'AND';
  928. }
  929. for($i=0;$i<$count;$i++)
  930. {
  931. if (is_array($val[$i]))
  932. {
  933. if (is_array($val[$i][1])){
  934. $data = implode(',',$val[$i][1]);
  935. }else{
  936. $data = $val[$i][1];
  937. }
  938. }
  939. else {
  940. $data = $val[$i];
  941. }
  942. if('exp'==strtolower($val[$i][0])) {
  943. $whereStr .= '('.$key.' '.$data.') '.$rule.' ';
  944. }
  945. else
  946. {
  947. $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'=';
  948. if(preg_match('/IN/i',$op)){
  949. $whereStr .= '('.$key.' '.$op.' ('.$this->parseValue($data).')) '.$rule.' ';
  950. }else{
  951. $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' ';
  952. }
  953. }
  954. }
  955. $whereStr = substr($whereStr,0,-4);
  956. }
  957. }
  958. else
  959. {
  960. $whereStr .= $key.' = '.$this->parseValue($val);
  961. }
  962. return $whereStr;
  963. }
  964. protected function parseLimit($limit) {
  965. return !empty($limit)? ' LIMIT '.$limit.' ':'';
  966. }
  967. protected function parseJoin($options = array())
  968. {
  969. $joinStr = '';
  970. if (false === strpos($options['table'],',')) return null;
  971. $table = explode(',',$options['table']);
  972. $on = explode(',',$options['on']);
  973. $join = $options['join'];
  974. $joinStr .= $table[0];
  975. for($i=0;$i<(count($table)-1);$i++) {
  976. $joinStr .= ' '.($join[$i]?$join[$i]:'LEFT JOIN').' '.$table[$i+1].' ON '.($on[$i]?$on[$i]:'');
  977. }
  978. return $joinStr;
  979. }
  980. public function delete($options=array())
  981. {
  982. $sql = 'DELETE '.$this->parseAttr($options).' FROM '
  983. .$this->parseTable($options)
  984. .$this->parseWhere(isset($options['where'])?$options['where']:'')
  985. .$this->parseOrder(isset($options['order'])?$options['order']:'')
  986. .$this->parseLimit(isset($options['limit'])?$options['limit']:'');
  987. if (stripos($sql,'where') === false && $options['where'] !== true){
  988. //防止条件传错,删除所有记录
  989. return false;
  990. }
  991. return DB::execute($sql);
  992. }
  993. public function update($data,$options)
  994. {
  995. $sql = 'UPDATE '
  996. .$this->parseAttr($options)
  997. .$this->parseTable($options)
  998. .$this->parseSet($data)
  999. .$this->parseWhere(isset($options['where'])?$options['where']:'')
  1000. .$this->parseOrder(isset($options['order'])?$options['order']:'')
  1001. .$this->parseLimit(isset($options['limit'])?$options['limit']:'');
  1002. if (stripos($sql,'where') === false && $options['where'] !== true) {
  1003. //防止条件传错,更新所有记录
  1004. return false;
  1005. }
  1006. return DB::execute($sql);
  1007. }
  1008. public function parseAttr($options)
  1009. {
  1010. if (isset($options['attr']))
  1011. {
  1012. if (in_array(isset($options['attr']),array('LOW_PRIORITY','QUICK','IGNORE','HIGH_PRIORITY','SQL_CACHE','SQL_NO_CACHE'))){
  1013. return $options['attr'].' ';
  1014. }
  1015. } else {
  1016. return '';
  1017. }
  1018. }
  1019. public function lockAttr($options)
  1020. {
  1021. if (isset($options['attr']))
  1022. {
  1023. if (in_array($options['attr'],array('FOR UPDATE'))){
  1024. return ' '.$options['attr'].' ';
  1025. }
  1026. } else {
  1027. return '';
  1028. }
  1029. }
  1030. /**
  1031. * 清空表
  1032. *
  1033. * @param array $options
  1034. * @return boolean
  1035. */
  1036. public function clear($options)
  1037. {
  1038. $sql = 'TRUNCATE TABLE '.$this->parseTable($options);
  1039. return DB::execute($sql);
  1040. }
  1041. public function insert($data,$options=array(),$replace=false)
  1042. {
  1043. $values = $fields = array();
  1044. foreach ($data as $key=>$val)
  1045. {
  1046. $value = $this->parseValue($val);
  1047. if(is_scalar($value)) {
  1048. $values[] = $value;
  1049. $fields[] = $this->parseKey($key);
  1050. }
  1051. }
  1052. $sql = ($replace?'REPLACE ':'INSERT ').$this->parseAttr($options).' INTO '.$this->parseTable($options).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
  1053. return DB::execute($sql);
  1054. }
  1055. public function getLastId() {
  1056. return DB::getLastId();
  1057. }
  1058. /**
  1059. * 批量插入
  1060. *
  1061. * @param unknown_type $datas
  1062. * @param unknown_type $options
  1063. * @param unknown_type $replace
  1064. * @return unknown
  1065. */
  1066. public function insertAll($datas,$options=array(),$replace=false)
  1067. {
  1068. if(!is_array($datas[0])) return false;
  1069. $fields = array_keys($datas[0]);
  1070. array_walk($fields, array($this, 'parseKey'));
  1071. $values = array();
  1072. foreach ($datas as $data)
  1073. {
  1074. $value = array();
  1075. foreach ($data as $key=>$val){
  1076. $val = $this->parseValue($val);
  1077. if(is_scalar($val)) {
  1078. $value[] = $val;
  1079. }
  1080. }
  1081. $values[] = '('.implode(',', $value).')';
  1082. }
  1083. $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options).' ('.implode(',', $fields).') VALUES '.implode(',',$values);
  1084. return DB::execute($sql);
  1085. }
  1086. protected function parseOrder($order)
  1087. {
  1088. if(is_array($order))
  1089. {
  1090. $array = array();
  1091. foreach ($order as $key=>$val)
  1092. {
  1093. if(is_numeric($key)) {
  1094. $array[] = $this->parseKey($val);
  1095. }else{
  1096. $array[] = $this->parseKey($key).' '.$val;
  1097. }
  1098. }
  1099. $order = implode(',',$array);
  1100. }
  1101. return !empty($order)? ' ORDER BY '.$order:'';
  1102. }
  1103. protected function parseGroup($group) {
  1104. return !empty($group)? ' GROUP BY '.$group:'';
  1105. }
  1106. protected function parseHaving($having) {
  1107. return !empty($having)? ' HAVING '.$having:'';
  1108. }
  1109. protected function parseDistinct($distinct) {
  1110. return !empty($distinct)? ' DISTINCT '.$distinct.',' :'';
  1111. }
  1112. protected function parseSet($data) {
  1113. foreach ($data as $key=>$val){
  1114. $value = $this->parseValue($val);
  1115. if(is_scalar($value))
  1116. $set[] = $this->parseKey($key).'='.$value;
  1117. }
  1118. return ' SET '.implode(',',$set);
  1119. }
  1120. public function escapeString($str) {
  1121. $str = addslashes(stripslashes($str));//重新加斜线,防止从数据库直接读取出错
  1122. return $str;
  1123. }
  1124. protected function parseKey(&$key) {
  1125. return $key;
  1126. }
  1127. public function checkActive($host) {
  1128. Db::ping($host);
  1129. }
  1130. public function affected_rows($host = 'master') {
  1131. return Db::affected_rows($host);
  1132. }
  1133. }
  1134. ?>