AdvModel.class.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. // $Id$
  12. /**
  13. +------------------------------------------------------------------------------
  14. * ThinkPHP 高级模型类
  15. +------------------------------------------------------------------------------
  16. * @category Think
  17. * @package Think
  18. * @subpackage Core
  19. * @author liu21st <liu21st@gmail.com>
  20. * @version $Id$
  21. +------------------------------------------------------------------------------
  22. */
  23. class AdvModel extends Model {
  24. // 数据库连接对象列表
  25. private $_db = array();
  26. private $_fields = null;
  27. protected $optimLock = 'lock_version';
  28. protected $returnType = 'array';
  29. protected $blobFields = array();
  30. protected $blobValues = null;
  31. protected $serializeField = array();
  32. protected $readonlyField = array();
  33. protected $_filter = array();
  34. public function __construct($name='') {
  35. if('' !== $name || is_subclass_of($this,'AdvModel') ){
  36. // 如果是AdvModel子类或者有传入模型名称则获取字段缓存
  37. }else{
  38. // 空的模型 关闭字段缓存
  39. $this->autoCheckFields = false;
  40. }
  41. parent::__construct($name);
  42. // 设置默认的数据库连接
  43. $this->_db[0] = $this->db;
  44. // 备份当前的数据表字段信息
  45. $this->_fields = $this->fields;
  46. }
  47. /**
  48. +----------------------------------------------------------
  49. * 利用__call方法重载 实现一些特殊的Model方法 (魔术方法)
  50. +----------------------------------------------------------
  51. * @access public
  52. +----------------------------------------------------------
  53. * @param string $method 方法名称
  54. * @param mixed $args 调用参数
  55. +----------------------------------------------------------
  56. * @return mixed
  57. +----------------------------------------------------------
  58. */
  59. public function __call($method,$args) {
  60. if(strtolower(substr($method,0,3))=='top'){
  61. // 获取前N条记录
  62. $count = substr($method,3);
  63. array_unshift($args,$count);
  64. return call_user_func_array(array(&$this, 'topN'), $args);
  65. }else{
  66. return parent::__call($method,$args);
  67. }
  68. }
  69. /**
  70. +----------------------------------------------------------
  71. * 对保存到数据库的数据进行处理
  72. +----------------------------------------------------------
  73. * @access protected
  74. +----------------------------------------------------------
  75. * @param mixed $data 要操作的数据
  76. +----------------------------------------------------------
  77. * @return boolean
  78. +----------------------------------------------------------
  79. */
  80. protected function _facade($data) {
  81. // 检查序列化字段
  82. $data = $this->serializeField($data);
  83. return parent::_facade($data);
  84. }
  85. // 查询成功后的回调方法
  86. protected function _after_find(&$result,$options='') {
  87. // 检查序列化字段
  88. $this->checkSerializeField($result);
  89. // 获取文本字段
  90. $this->getBlobFields($result);
  91. // 检查字段过滤
  92. $result = $this->getFilterFields($result);
  93. // 缓存乐观锁
  94. $this->cacheLockVersion($result);
  95. }
  96. // 查询数据集成功后的回调方法
  97. protected function _after_select(&$resultSet,$options='') {
  98. // 检查序列化字段
  99. $resultSet = $this->checkListSerializeField($resultSet);
  100. // 获取文本字段
  101. $resultSet = $this->getListBlobFields($resultSet);
  102. // 检查列表字段过滤
  103. $resultSet = $this->getFilterListFields($resultSet);
  104. }
  105. // 写入前的回调方法
  106. protected function _before_insert(&$data,$options='') {
  107. // 记录乐观锁
  108. $data = $this->recordLockVersion($data);
  109. // 检查文本字段
  110. $data = $this->checkBlobFields($data);
  111. // 检查字段过滤
  112. $data = $this->setFilterFields($data);
  113. }
  114. protected function _after_insert($data,$options) {
  115. // 保存文本字段
  116. $this->saveBlobFields($data);
  117. }
  118. // 更新前的回调方法
  119. protected function _before_update(&$data,$options='') {
  120. // 检查乐观锁
  121. if(!$this->checkLockVersion($data,$options)) {
  122. return false;
  123. }
  124. // 检查文本字段
  125. $data = $this->checkBlobFields($data);
  126. // 检查只读字段
  127. $data = $this->checkReadonlyField($data);
  128. // 检查字段过滤
  129. $data = $this->setFilterFields($data);
  130. }
  131. protected function _after_update($data,$options) {
  132. // 保存文本字段
  133. $this->saveBlobFields($data);
  134. }
  135. protected function _after_delete($data,$options) {
  136. // 删除Blob数据
  137. $this->delBlobFields($data);
  138. }
  139. /**
  140. +----------------------------------------------------------
  141. * 记录乐观锁
  142. +----------------------------------------------------------
  143. * @access protected
  144. +----------------------------------------------------------
  145. * @param array $data 数据对象
  146. +----------------------------------------------------------
  147. * @return array
  148. +----------------------------------------------------------
  149. */
  150. protected function recordLockVersion($data) {
  151. // 记录乐观锁
  152. if($this->optimLock && !isset($data[$this->optimLock]) ) {
  153. if(in_array($this->optimLock,$this->fields,true)) {
  154. $data[$this->optimLock] = 0;
  155. }
  156. }
  157. return $data;
  158. }
  159. /**
  160. +----------------------------------------------------------
  161. * 缓存乐观锁
  162. +----------------------------------------------------------
  163. * @access protected
  164. +----------------------------------------------------------
  165. * @param array $data 数据对象
  166. +----------------------------------------------------------
  167. * @return void
  168. +----------------------------------------------------------
  169. */
  170. protected function cacheLockVersion($data) {
  171. if($this->optimLock) {
  172. if(isset($data[$this->optimLock]) && isset($data[$this->getPk()])) {
  173. // 只有当存在乐观锁字段和主键有值的时候才记录乐观锁
  174. $_SESSION[$this->name.'_'.$data[$this->getPk()].'_lock_version'] = $data[$this->optimLock];
  175. }
  176. }
  177. }
  178. /**
  179. +----------------------------------------------------------
  180. * 检查乐观锁
  181. +----------------------------------------------------------
  182. * @access protected
  183. +----------------------------------------------------------
  184. * @param array $data 当前数据
  185. * @param array $options 查询表达式
  186. +----------------------------------------------------------
  187. * @return mixed
  188. +----------------------------------------------------------
  189. */
  190. protected function checkLockVersion(&$data,$options) {
  191. $id = $data[$this->getPk()];
  192. // 检查乐观锁
  193. $identify = $this->name.'_'.$id.'_lock_version';
  194. if($this->optimLock && isset($_SESSION[$identify])) {
  195. $lock_version = $_SESSION[$identify];
  196. $vo = $this->field($this->optimLock)->find($id);
  197. $_SESSION[$identify] = $lock_version;
  198. $curr_version = $vo[$this->optimLock];
  199. if(isset($curr_version)) {
  200. if($curr_version>0 && $lock_version != $curr_version) {
  201. // 记录已经更新
  202. $this->error = L('_RECORD_HAS_UPDATE_');
  203. return false;
  204. }else{
  205. // 更新乐观锁
  206. $save_version = $data[$this->optimLock];
  207. if($save_version != $lock_version+1) {
  208. $data[$this->optimLock] = $lock_version+1;
  209. }
  210. $_SESSION[$identify] = $lock_version+1;
  211. }
  212. }
  213. }
  214. return true;
  215. }
  216. /**
  217. +----------------------------------------------------------
  218. * 查找前N个记录
  219. +----------------------------------------------------------
  220. * @access public
  221. +----------------------------------------------------------
  222. * @param integer $count 记录个数
  223. * @param array $options 查询表达式
  224. +----------------------------------------------------------
  225. * @return array
  226. +----------------------------------------------------------
  227. */
  228. public function topN($count,$options=array()) {
  229. $options['limit'] = $count;
  230. return $this->select($options);
  231. }
  232. /**
  233. +----------------------------------------------------------
  234. * 查询符合条件的第N条记录
  235. * 0 表示第一条记录 -1 表示最后一条记录
  236. +----------------------------------------------------------
  237. * @access public
  238. +----------------------------------------------------------
  239. * @param integer $position 记录位置
  240. * @param array $options 查询表达式
  241. +----------------------------------------------------------
  242. * @return mixed
  243. +----------------------------------------------------------
  244. */
  245. public function getN($position=0,$options=array()) {
  246. if($position>=0) { // 正向查找
  247. $options['limit'] = $position.',1';
  248. $list = $this->select($options);
  249. return $list?$list[0]:false;
  250. }else{ // 逆序查找
  251. $list = $this->select($options);
  252. return $list?$list[count($list)-abs($position)]:false;
  253. }
  254. }
  255. /**
  256. +----------------------------------------------------------
  257. * 获取满足条件的第一条记录
  258. +----------------------------------------------------------
  259. * @access public
  260. +----------------------------------------------------------
  261. * @param array $options 查询表达式
  262. +----------------------------------------------------------
  263. * @return mixed
  264. +----------------------------------------------------------
  265. */
  266. public function first($options=array()) {
  267. return $this->getN(0,$options);
  268. }
  269. /**
  270. +----------------------------------------------------------
  271. * 获取满足条件的最后一条记录
  272. +----------------------------------------------------------
  273. * @access public
  274. +----------------------------------------------------------
  275. * @param array $options 查询表达式
  276. +----------------------------------------------------------
  277. * @return mixed
  278. +----------------------------------------------------------
  279. */
  280. public function last($options=array()) {
  281. return $this->getN(-1,$options);
  282. }
  283. /**
  284. +----------------------------------------------------------
  285. * 返回数据
  286. +----------------------------------------------------------
  287. * @access public
  288. +----------------------------------------------------------
  289. * @param array $data 数据
  290. * @param string $type 返回类型 默认为数组
  291. +----------------------------------------------------------
  292. * @return mixed
  293. +----------------------------------------------------------
  294. */
  295. public function returnResult($data,$type='') {
  296. if('' === $type)
  297. $type = $this->returnType;
  298. switch($type) {
  299. case 'array' : return $data;
  300. case 'object': return (object)$data;
  301. default:// 允许用户自定义返回类型
  302. if(class_exists($type))
  303. return new $type($data);
  304. else
  305. throw_exception(L('_CLASS_NOT_EXIST_').':'.$type);
  306. }
  307. }
  308. /**
  309. +----------------------------------------------------------
  310. * 获取数据的时候过滤数据字段
  311. +----------------------------------------------------------
  312. * @access protected
  313. +----------------------------------------------------------
  314. * @param mixed $result 查询的数据
  315. +----------------------------------------------------------
  316. * @return array
  317. +----------------------------------------------------------
  318. */
  319. protected function getFilterFields(&$result) {
  320. if(!empty($this->_filter)) {
  321. foreach ($this->_filter as $field=>$filter){
  322. if(isset($result[$field])) {
  323. $fun = $filter[1];
  324. if(!empty($fun)) {
  325. if(isset($filter[2]) && $filter[2]){
  326. // 传递整个数据对象作为参数
  327. $result[$field] = call_user_func($fun,$result);
  328. }else{
  329. // 传递字段的值作为参数
  330. $result[$field] = call_user_func($fun,$result[$field]);
  331. }
  332. }
  333. }
  334. }
  335. }
  336. return $result;
  337. }
  338. protected function getFilterListFields(&$resultSet) {
  339. if(!empty($this->_filter)) {
  340. foreach ($resultSet as $key=>$result)
  341. $resultSet[$key] = $this->getFilterFields($result);
  342. }
  343. return $resultSet;
  344. }
  345. /**
  346. +----------------------------------------------------------
  347. * 写入数据的时候过滤数据字段
  348. +----------------------------------------------------------
  349. * @access pubic
  350. +----------------------------------------------------------
  351. * @param mixed $result 查询的数据
  352. +----------------------------------------------------------
  353. * @return array
  354. +----------------------------------------------------------
  355. */
  356. protected function setFilterFields($data) {
  357. if(!empty($this->_filter)) {
  358. foreach ($this->_filter as $field=>$filter){
  359. if(isset($data[$field])) {
  360. $fun = $filter[0];
  361. if(!empty($fun)) {
  362. if(isset($filter[2]) && $filter[2]) {
  363. // 传递整个数据对象作为参数
  364. $data[$field] = call_user_func($fun,$data);
  365. }else{
  366. // 传递字段的值作为参数
  367. $data[$field] = call_user_func($fun,$data[$field]);
  368. }
  369. }
  370. }
  371. }
  372. }
  373. return $data;
  374. }
  375. /**
  376. +----------------------------------------------------------
  377. * 返回数据列表
  378. +----------------------------------------------------------
  379. * @access protected
  380. +----------------------------------------------------------
  381. * @param array $resultSet 数据
  382. * @param string $type 返回类型 默认为数组
  383. +----------------------------------------------------------
  384. * @return void
  385. +----------------------------------------------------------
  386. */
  387. protected function returnResultSet(&$resultSet,$type='') {
  388. foreach ($resultSet as $key=>$data)
  389. $resultSet[$key] = $this->returnResult($data,$type);
  390. return $resultSet;
  391. }
  392. protected function checkBlobFields(&$data) {
  393. // 检查Blob文件保存字段
  394. if(!empty($this->blobFields)) {
  395. foreach ($this->blobFields as $field){
  396. if(isset($data[$field])) {
  397. if(isset($data[$this->getPk()]))
  398. $this->blobValues[$this->name.'/'.$data[$this->getPk()].'_'.$field] = $data[$field];
  399. else
  400. $this->blobValues[$this->name.'/@?id@_'.$field] = $data[$field];
  401. unset($data[$field]);
  402. }
  403. }
  404. }
  405. return $data;
  406. }
  407. /**
  408. +----------------------------------------------------------
  409. * 获取数据集的文本字段
  410. +----------------------------------------------------------
  411. * @access protected
  412. +----------------------------------------------------------
  413. * @param mixed $resultSet 查询的数据
  414. * @param string $field 查询的字段
  415. +----------------------------------------------------------
  416. * @return void
  417. +----------------------------------------------------------
  418. */
  419. protected function getListBlobFields(&$resultSet,$field='') {
  420. if(!empty($this->blobFields)) {
  421. foreach ($resultSet as $key=>$result){
  422. $result = $this->getBlobFields($result,$field);
  423. $resultSet[$key] = $result;
  424. }
  425. }
  426. return $resultSet;
  427. }
  428. /**
  429. +----------------------------------------------------------
  430. * 获取数据的文本字段
  431. +----------------------------------------------------------
  432. * @access protected
  433. +----------------------------------------------------------
  434. * @param mixed $data 查询的数据
  435. * @param string $field 查询的字段
  436. +----------------------------------------------------------
  437. * @return void
  438. +----------------------------------------------------------
  439. */
  440. protected function getBlobFields(&$data,$field='') {
  441. if(!empty($this->blobFields)) {
  442. $pk = $this->getPk();
  443. $id = $data[$pk];
  444. if(empty($field)) {
  445. foreach ($this->blobFields as $field){
  446. $identify = $this->name.'/'.$id.'_'.$field;
  447. $data[$field] = F($identify);
  448. }
  449. return $data;
  450. }else{
  451. $identify = $this->name.'/'.$id.'_'.$field;
  452. return F($identify);
  453. }
  454. }
  455. }
  456. /**
  457. +----------------------------------------------------------
  458. * 保存File方式的字段
  459. +----------------------------------------------------------
  460. * @access protected
  461. +----------------------------------------------------------
  462. * @param mixed $data 保存的数据
  463. +----------------------------------------------------------
  464. * @return void
  465. +----------------------------------------------------------
  466. */
  467. protected function saveBlobFields(&$data) {
  468. if(!empty($this->blobFields)) {
  469. foreach ($this->blobValues as $key=>$val){
  470. if(strpos($key,'@?id@'))
  471. $key = str_replace('@?id@',$data[$this->getPk()],$key);
  472. F($key,$val);
  473. }
  474. }
  475. }
  476. /**
  477. +----------------------------------------------------------
  478. * 删除File方式的字段
  479. +----------------------------------------------------------
  480. * @access protected
  481. +----------------------------------------------------------
  482. * @param mixed $data 保存的数据
  483. * @param string $field 查询的字段
  484. +----------------------------------------------------------
  485. * @return void
  486. +----------------------------------------------------------
  487. */
  488. protected function delBlobFields(&$data,$field='') {
  489. if(!empty($this->blobFields)) {
  490. $pk = $this->getPk();
  491. $id = $data[$pk];
  492. if(empty($field)) {
  493. foreach ($this->blobFields as $field){
  494. $identify = $this->name.'/'.$id.'_'.$field;
  495. F($identify,null);
  496. }
  497. }else{
  498. $identify = $this->name.'/'.$id.'_'.$field;
  499. F($identify,null);
  500. }
  501. }
  502. }
  503. /**
  504. +----------------------------------------------------------
  505. * 字段值延迟增长
  506. +----------------------------------------------------------
  507. * @access public
  508. +----------------------------------------------------------
  509. * @param string $field 字段名
  510. * @param mixed $condition 条件
  511. * @param integer $step 增长值
  512. * @param integer $lazyTime 延时时间(s)
  513. +----------------------------------------------------------
  514. * @return boolean
  515. +----------------------------------------------------------
  516. */
  517. public function setLazyInc($field,$condition='',$step=1,$lazyTime=0) {
  518. if(empty($condition) && isset($this->options['where']))
  519. $condition = $this->options['where'];
  520. if(empty($condition)) { // 没有条件不做任何更新
  521. return false;
  522. }
  523. if($lazyTime>0) {// 延迟写入
  524. $guid = md5($this->name.'_'.$field.'_'.serialize($conditon));
  525. $step = $this->lazyWrite($guid,$step,$lazyTime);
  526. if(false === $step ) return true; // 等待下次写入
  527. }
  528. return $this->setField($field,array('exp',$field.'+'.$step),$condition);
  529. }
  530. /**
  531. +----------------------------------------------------------
  532. * 字段值延迟减少
  533. +----------------------------------------------------------
  534. * @access public
  535. +----------------------------------------------------------
  536. * @param string $field 字段名
  537. * @param mixed $condition 条件
  538. * @param integer $step 减少值
  539. * @param integer $lazyTime 延时时间(s)
  540. +----------------------------------------------------------
  541. * @return boolean
  542. +----------------------------------------------------------
  543. */
  544. public function setLazyDec($field,$condition='',$step=1,$lazyTime=0) {
  545. if(empty($condition) && isset($this->options['where']))
  546. $condition = $this->options['where'];
  547. if(empty($condition)) { // 没有条件不做任何更新
  548. return false;
  549. }
  550. if($lazyTime>0) {// 延迟写入
  551. $guid = md5($this->name.'_'.$field.'_'.serialize($conditon));
  552. $step = $this->lazyWrite($guid,$step,$lazyTime);
  553. if(false === $step ) return true; // 等待下次写入
  554. }
  555. return $this->setField($field,array('exp',$field.'-'.$step),$condition);
  556. }
  557. /**
  558. +----------------------------------------------------------
  559. * 延时更新检查 返回false表示需要延时
  560. * 否则返回实际写入的数值
  561. +----------------------------------------------------------
  562. * @access public
  563. +----------------------------------------------------------
  564. * @param string $guid 写入标识
  565. * @param integer $step 写入步进值
  566. * @param integer $lazyTime 延时时间(s)
  567. +----------------------------------------------------------
  568. * @return false|integer
  569. +----------------------------------------------------------
  570. */
  571. protected function lazyWrite($guid,$step,$lazyTime) {
  572. if(false !== ($value = F($guid))) { // 存在缓存写入数据
  573. if(time()>F($guid.'_time')+$lazyTime) {
  574. // 延时更新时间到了,删除缓存数据 并实际写入数据库
  575. F($guid,NULL);
  576. F($guid.'_time',NULL);
  577. return $value+$step;
  578. }else{
  579. // 追加数据到缓存
  580. F($guid,$value+$step);
  581. return false;
  582. }
  583. }else{ // 没有缓存数据
  584. F($guid,$step);
  585. // 计时开始
  586. F($guid.'_time',time());
  587. return false;
  588. }
  589. }
  590. /**
  591. +----------------------------------------------------------
  592. * 检查序列化数据字段
  593. +----------------------------------------------------------
  594. * @access protected
  595. +----------------------------------------------------------
  596. * @param array $data 数据
  597. +----------------------------------------------------------
  598. * @return array
  599. +----------------------------------------------------------
  600. */
  601. protected function serializeField(&$data) {
  602. // 检查序列化字段
  603. if(!empty($this->serializeField)) {
  604. // 定义方式 $this->serializeField = array('ser'=>array('name','email'));
  605. foreach ($this->serializeField as $key=>$val){
  606. if(empty($data[$key])) {
  607. $serialize = array();
  608. foreach ($val as $name){
  609. if(isset($data[$name])) {
  610. $serialize[$name] = $data[$name];
  611. unset($data[$name]);
  612. }
  613. }
  614. $data[$key] = serialize($serialize);
  615. }
  616. }
  617. }
  618. return $data;
  619. }
  620. // 检查返回数据的序列化字段
  621. protected function checkSerializeField(&$result) {
  622. // 检查序列化字段
  623. if(!empty($this->serializeField)) {
  624. foreach ($this->serializeField as $key=>$val){
  625. if(isset($result[$key])) {
  626. $serialize = unserialize($result[$key]);
  627. foreach ($serialize as $name=>$value)
  628. $result[$name] = $value;
  629. unset($serialize,$result[$key]);
  630. }
  631. }
  632. }
  633. return $result;
  634. }
  635. // 检查数据集的序列化字段
  636. protected function checkListSerializeField(&$resultSet) {
  637. // 检查序列化字段
  638. if(!empty($this->serializeField)) {
  639. foreach ($this->serializeField as $key=>$val){
  640. foreach ($resultSet as $k=>$result){
  641. if(isset($result[$key])) {
  642. $serialize = unserialize($result[$key]);
  643. foreach ($serialize as $name=>$value)
  644. $result[$name] = $value;
  645. unset($serialize,$result[$key]);
  646. $resultSet[$k] = $result;
  647. }
  648. }
  649. }
  650. }
  651. return $resultSet;
  652. }
  653. /**
  654. +----------------------------------------------------------
  655. * 检查只读字段
  656. +----------------------------------------------------------
  657. * @access protected
  658. +----------------------------------------------------------
  659. * @param array $data 数据
  660. +----------------------------------------------------------
  661. * @return array
  662. +----------------------------------------------------------
  663. */
  664. protected function checkReadonlyField(&$data) {
  665. if(!empty($this->readonlyField)) {
  666. foreach ($this->readonlyField as $key=>$field){
  667. if(isset($data[$field]))
  668. unset($data[$field]);
  669. }
  670. }
  671. return $data;
  672. }
  673. /**
  674. +----------------------------------------------------------
  675. * 增加数据库连接
  676. +----------------------------------------------------------
  677. * @access public
  678. +----------------------------------------------------------
  679. * @param mixed $config 数据库连接信息
  680. * 支持批量添加 例如 array(1=>$config1,2=>$config2)
  681. * @param mixed $linkNum 创建的连接序号
  682. +----------------------------------------------------------
  683. * @return boolean
  684. +----------------------------------------------------------
  685. */
  686. public function addConnect($config,$linkNum=NULL) {
  687. if(isset($this->_db[$linkNum]))
  688. return false;
  689. if(NULL === $linkNum && is_array($config)) {
  690. // 支持批量增加数据库连接
  691. foreach ($config as $key=>$val)
  692. $this->_db[$key] = Db::getInstance($val);
  693. return true;
  694. }
  695. // 创建一个新的实例
  696. $this->_db[$linkNum] = Db::getInstance($config);
  697. return true;
  698. }
  699. /**
  700. +----------------------------------------------------------
  701. * 删除数据库连接
  702. +----------------------------------------------------------
  703. * @access public
  704. +----------------------------------------------------------
  705. * @param integer $linkNum 创建的连接序号
  706. +----------------------------------------------------------
  707. * @return boolean
  708. +----------------------------------------------------------
  709. */
  710. public function delConnect($linkNum) {
  711. if(isset($this->_db[$linkNum])) {
  712. $this->_db[$linkNum]->close();
  713. unset($this->_db[$linkNum]);
  714. // 恢复之前的数据表字段信息
  715. $this->fields = $this->_fields;
  716. return true;
  717. }
  718. return false;
  719. }
  720. /**
  721. +----------------------------------------------------------
  722. * 关闭数据库连接
  723. +----------------------------------------------------------
  724. * @access public
  725. +----------------------------------------------------------
  726. * @param integer $linkNum 创建的连接序号
  727. +----------------------------------------------------------
  728. * @return boolean
  729. +----------------------------------------------------------
  730. */
  731. public function closeConnect($linkNum) {
  732. if(isset($this->_db[$linkNum])) {
  733. $this->_db[$linkNum]->close();
  734. return true;
  735. }
  736. return false;
  737. }
  738. /**
  739. +----------------------------------------------------------
  740. * 切换数据库连接
  741. +----------------------------------------------------------
  742. * @access public
  743. +----------------------------------------------------------
  744. * @param integer $linkNum 创建的连接序号
  745. * @param string $name 要操作的模型名称
  746. +----------------------------------------------------------
  747. * @return boolean
  748. +----------------------------------------------------------
  749. */
  750. public function switchConnect($linkNum,$name='') {
  751. if(isset($this->_db[$linkNum])) {
  752. // 在不同实例直接切换
  753. $this->db = $this->_db[$linkNum];
  754. // 重置当前表名 可以在切换之前重新设置前缀
  755. $this->trueTableName = '';
  756. if(!empty($name)) $this->name = $name;
  757. // 更新数据表字段缓存信息
  758. $this->flush();
  759. return true;
  760. }else{
  761. return false;
  762. }
  763. }
  764. /**
  765. +----------------------------------------------------------
  766. * 批处理执行SQL语句
  767. * 批处理的指令都认为是execute操作
  768. +----------------------------------------------------------
  769. * @access public
  770. +----------------------------------------------------------
  771. * @param array $sql SQL批处理指令
  772. +----------------------------------------------------------
  773. * @return boolean
  774. +----------------------------------------------------------
  775. */
  776. public function patchQuery($sql=array()) {
  777. if(!is_array($sql)) return false;
  778. // 自动启动事务支持
  779. $this->startTrans();
  780. try{
  781. foreach ($sql as $_sql){
  782. $result = $this->execute($_sql);
  783. if(false === $result) {
  784. // 发生错误自动回滚事务
  785. $this->rollback();
  786. return false;
  787. }
  788. }
  789. // 提交事务
  790. $this->commit();
  791. } catch (ThinkException $e) {
  792. $this->rollback();
  793. }
  794. return true;
  795. }
  796. /**
  797. +----------------------------------------------------------
  798. * 得到分表的的数据表名
  799. +----------------------------------------------------------
  800. * @access public
  801. +----------------------------------------------------------
  802. * @param array $data 操作的数据
  803. +----------------------------------------------------------
  804. * @return string
  805. +----------------------------------------------------------
  806. */
  807. public function getPartitionTableName($data=array()) {
  808. // 对数据表进行分区
  809. if(isset($data[$this->partition['field']])) {
  810. $field = $data[$this->partition['field']];
  811. switch($this->partition['type']) {
  812. case 'id':
  813. // 按照id范围分表
  814. $step = $this->partition['expr'];
  815. $seq = floor($field / $step)+1;
  816. break;
  817. case 'year':
  818. // 按照年份分表
  819. if(!is_numeric($field)) {
  820. $field = strtotime($field);
  821. }
  822. $seq = date('Y',$field)-$this->partition['expr']+1;
  823. break;
  824. case 'mod':
  825. // 按照id的模数分表
  826. $seq = ($field % $this->partition['num'])+1;
  827. break;
  828. case 'md5':
  829. // 按照md5的序列分表
  830. $seq = (ord(substr(md5($field),0,1)) % $this->partition['num'])+1;
  831. break;
  832. default :
  833. if(function_exists($this->partition['type'])) {
  834. // 支持指定函数哈希
  835. $fun = $this->partition['type'];
  836. $seq = (ord(substr($fun($field),0,1)) % $this->partition['num'])+1;
  837. }else{
  838. // 按照字段的首字母的值分表
  839. $seq = (ord($field{0}) % $this->partition['num'])+1;
  840. }
  841. }
  842. return $this->getTableName().'_'.$seq;
  843. }else{
  844. // 当设置的分表字段不在查询条件或者数据中
  845. // 进行联合查询,必须设定 partition['num']
  846. $tableName = array();
  847. for($i=0;$i<$this->partition['num'];$i++)
  848. $tableName[] = 'SELECT * FROM '.$this->getTableName().'_'.$i;
  849. $tableName = '( '.implode(" UNION ",$tableName).') AS '.$this->name;
  850. return $tableName;
  851. }
  852. }
  853. }
  854. ?>