| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 | 
							- <?php
 
- namespace KIF\Dao;
 
- use KIF\Verify;
 
- use KIF\Exception\ParamsException;
 
- use KIF\Data\ResultWrapper;
 
- /**
 
-  * 数据库操作的敏捷开发模式抽象类。  敏捷开发(Agile development)
 
-  * 目的:统一数据库表的设计模式,为 增、删、改 提供便捷
 
-  * PS: 通过 cas_token 字段,提供冲突检测机制(乐观锁),保证高并发下的数据安全
 
-  *     这是模仿自 php 的 Memcached 扩展,非常好的功能,故借鉴过来
 
-  * @author gaoxiaogang@gmail.com
 
-  *
 
-  */
 
- abstract class DBAgileDev extends AbstractDao {
 
-     /**
 
-      * 除敏捷模式必须要求的字段外,多增加的字段
 
-      * 该实例变量由继承类填充
 
-      * @var array
 
-      */
 
-     protected $other_field = array();
 
-     /**
 
-      * 数据库里的真实字段
 
-      * 这个实例变量的值是自动计算出来的
 
-      * @var array
 
-      */
 
-     private $real_field;
 
-     /**
 
-      * 
 
-      * Enter description here ...
 
-      * @param unknown_type $master_flag
 
-      * @return KIF\Dao\DBAgileDev
 
-      */
 
-     public function __construct($master_flag = 'default') {
 
-     	parent::__construct($master_flag);
 
-     	# 固定字段
 
-     	$fixed_field = array(
 
-     	    $this->primaryKey,
 
-     	    'extend',
 
-     	    'create_time',
 
-     	    'update_time',
 
-     	    'cas_token',// 通过这个字段,提供冲突检测机制(乐观锁),保证高并发下的数据安全
 
-     	);
 
-     	$this->real_field = array_merge($fixed_field, $this->other_field);
 
-     }
 
-     /**
 
-      *
 
-      * 添加一条记录
 
-      * @param array $info
 
-      * @param string $actionType 动态类型,这个参数控制以下行为中的一种: create、replace、insertIgnore
 
-      *
 
-      * ## 当$actionType的值为parent::PARAM_CREATE_ACTION_ONDUPLICATE时,该值才有意义。##
 
-      * !!! 无法通过指定 $onDuplicate 来修改存储在 extend 字段里的值,因为没法把已存在的 extend 的值取出来,做一个merge。 !!!
 
-      * @param array $onDuplicate 如果重复时,需要更新的信息。如果不指定,则使用$tableInfo的值,即认为要全部更新
 
-      * ##
 
-      *
 
-      * @throws ParamsException actionType 参数非法
 
-      * @return int | boolean
 
-      */
 
-     public function add(array $info, $actionType = parent::PARAM_CREATE_ACTION_INSERT, array $onDuplicate = array()) {
 
-         if (!isset($info['create_time']) || !Verify::unsignedInt($info['create_time'])) {
 
-             $info['create_time'] = time();
 
-         }
 
-         if (!isset($info['update_time']) || !Verify::unsignedInt($info['update_time'])) {
 
-             $info['update_time'] = time();
 
-         }
 
-         $extend = array();
 
-         foreach ($info as $tmpK => $tmpV) {
 
-             if (!in_array($tmpK, $this->real_field)) {
 
-                 $extend[$tmpK]  = $tmpV;
 
-                 unset($info[$tmpK]);
 
-             }
 
-         }
 
-         # 从0开始。本来打算从1开始的,但考虑到 继续类可能会绕过 add 方法而实现自身的增加记录方法,将 cas_token默认值设为,有助于简化
 
-         $info['cas_token'] = 0;
 
-         $tableInfo = $info;
 
-         $tableInfo['extend'] = serialize($extend);
 
-         switch ($actionType) {
 
-         	case parent::PARAM_CREATE_ACTION_INSERT:
 
- 				$id = $this->create($tableInfo);
 
-         		break;
 
-         	case parent::PARAM_CREATE_ACTION_INSERT_IGNORE:
 
- 				$id = $this->insertIgnore($tableInfo);
 
-         		break;
 
-         	case parent::PARAM_CREATE_ACTION_REPLACE:
 
- 				$id = $this->replace($tableInfo);
 
-         		break;
 
-         	case parent::PARAM_CREATE_ACTION_ONDUPLICATE:
 
-         		if (empty($onDuplicate)) {
 
-         			$onDuplicate = $tableInfo;
 
-         			unset($onDuplicate['create_time']);
 
-         			unset($onDuplicate['cas_token']);
 
-         		} else {
 
-         			# 确保不允许修改 extend 字段里存储的值。因为没法把已存在的 extend 的值取出来,做一个merge。
 
- 			        foreach ($onDuplicate as $tmpK => $tmpV) {
 
- 			            if (!in_array($tmpK, $this->real_field)) {
 
- 			                unset($onDuplicate[$tmpK]);
 
- 			            }
 
- 			        }
 
-         		}
 
-         		$onDuplicate['update_time'] = $info['update_time'];
 
-         		$onDuplicate['cas_token'] = SqlHelper::wrapperNoQuote("`cas_token` + 1");
 
-         		$id = $this->insertDuplicate($tableInfo, $onDuplicate);
 
-         		break;
 
-         	default:
 
-         		throw new ParamsException("invalid actionType");
 
-         }
 
-         return $id;
 
-     }
 
-     /**
 
-      * 修改
 
-      * !!!!!!
 
-      * !!! $cas_token 提供了一种“检查并修改”机制,非常重要的优势, 在这样一个冲突检测机制(乐观锁)下, 我们才能保证高并发下的数据安全。
 
-      * !!!!!!
 
-      * 注:$info 或 $condition 里,一定要有一个指定 key 为 $this->primaryKey 对应的值
 
-      * @param array $info
 
-      * @param array $condition 条件
 
-      * @param int $cas_token 如果$cas_token不为null,会执行一个“检查并修改”的操作。因此,仅当 $cas_token 与数据库里的值一致时,才会修改记录。
 
-      * @return ResultWrapper 成功:修改并影响到了记录;
 
-      * 	       失败:数据里含失败描述。
 
-      * 		   另:cas_token检查不通过时,返回'CAS_TOKEN_NOT_MATCH'。这个返回值并不是严格意义上的正确,当$condition指定了条件,并且未匹配时,
 
-      * 		   也会返回这个值。
 
-      */
 
-     public function modify(array $info, array $condition = null, $cas_token = null) {
 
-         if (!isset($info[$this->primaryKey])) {
 
-         	if (!isset($condition[$this->primaryKey])) {
 
- 				return ResultWrapper::fail("请指定要修改的记录");
 
-         	}
 
-             $info[$this->primaryKey] = $condition[$this->primaryKey];
 
-         }
 
-         if (!Verify::unsignedInt($info[$this->primaryKey])) {
 
-             return ResultWrapper::fail("请指定有效的记录");
 
-         }
 
-         if (!isset($condition)) {
 
-         	$condition = array();
 
-         }
 
-         $useMasterFlag = $this->db->beginUseMaster();
 
-         $oldSpecialSale = parent::get($info[$this->primaryKey]);
 
-         $this->db->restore($useMasterFlag);
 
-         if (!$oldSpecialSale) {
 
-             return ResultWrapper::fail("不存在的记录:{$info[$this->primaryKey]}");;
 
-         }
 
-         # 找出待更新的扩展字段
 
-         $extend = unserialize($oldSpecialSale['extend']);
 
-         foreach ($info as $tmpK => $tmpV) {
 
-             if (!in_array($tmpK, $this->real_field)) {
 
-                 $extend[$tmpK]  = $tmpV;
 
-                 unset($info[$tmpK]);
 
-             }
 
-         }
 
-         $info['cas_token'] = SqlHelper::wrapperNoQuote('`cas_token` + 1');
 
-         $tableInfo = $info;
 
-         $tableInfo['extend'] = serialize($extend);
 
-         $tableInfo['update_time'] = time();
 
-         $condition[$this->primaryKey] = $info[$this->primaryKey];
 
-         if (Verify::naturalNumber($cas_token)) {
 
-         	$condition['cas_token'] = $cas_token;
 
-         }
 
-         $result = $this->update($tableInfo, $condition);
 
-         if (!$result) {
 
-             return ResultWrapper::fail("数据库update操作失败");
 
-         }
 
-         $affectedRows = $this->db->affectedRows();
 
-         if (!Verify::unsignedInt($affectedRows)) {
 
-         	if (Verify::naturalNumber($cas_token)) {
 
-         		return ResultWrapper::fail("CAS_TOKEN_NOT_MATCH");
 
-         	} else {
 
- 				return ResultWrapper::fail("NOT_MATCH");
 
-         	}
 
-         }
 
-         return ResultWrapper::success();
 
-     }
 
-     /**
 
-      * 获取一条记录
 
-      * @param int $id 记录id
 
-      * @param int $cas_token 引用传值,默认为 null
 
-      * @return false | array
 
-      */
 
-     public function get($id, & $cas_token = null) {
 
-         if (!Verify::unsignedInt($id)) {
 
-             return false;
 
-         }
 
-         $result = $this->gets(array($id));
 
-         if (!$result) {
 
-             return false;
 
-         }
 
-         $tmpResult = array_pop($result);
 
-         $cas_token = $tmpResult['cas_token'];
 
-         return $tmpResult;
 
-     }
 
-     /**
 
-      * 获取一批记录
 
-      * @param array $ids 记录id集
 
-      * @param array $cas_tokens 引用传值,默认为 null
 
-      * @return false | array
 
-      */
 
-     public function gets(array $ids, array & $cas_tokens = null) {
 
-         $result = parent::gets($ids);
 
-         if (!$result) {
 
-             return $result;
 
-         }
 
-         foreach ($result as & $tmpV) {
 
-             $tmpExtend = array();
 
-             $tmpExtend = unserialize($tmpV['extend']);
 
-             unset($tmpV['extend']);
 
-             # 将存在扩展字段里的信息提出来
 
-             if (is_array($tmpExtend)) foreach ($tmpExtend as $tmpKK => $tmpVV) {
 
-             	if (!in_array($tmpKK, $this->real_field)) {
 
-                     $tmpV[$tmpKK] = $tmpVV;
 
-                 }
 
-             }
 
-             $cas_tokens[$tmpV[$this->primaryKey]] = $tmpV['cas_token'];
 
-         }
 
-         return $result;
 
-     }
 
-     /**
 
-      *
 
-      * 获取所有id集
 
-      * @param string $order
 
-      * @param mixed $limit
 
-      * @return array
 
-      */
 
-     public function getsIdsAll($order = null, $limit = null) {
 
- 		$ids = parent::getsAllIds($order, $limit);
 
- 		return $ids;
 
-     }
 
-     public function fetchAll($condition = null, $limit = 10, $order = null, $selectCols = '*') {
 
-         $result = parent::findBy($condition, null, $limit, $selectCols, $order);
 
-         if (!$result) {
 
-             return false;
 
-         }
 
-         foreach ($result as & $tmpV) {
 
-             $tmpExtend = array();
 
-             $tmpExtend = unserialize($tmpV['extend']);
 
-             unset($tmpV['extend']);
 
-             # 将存在扩展字段里的信息提出来
 
-             if (is_array($tmpExtend)) foreach ($tmpExtend as $tmpKK => $tmpVV) {
 
-                 if (!in_array($tmpKK, $this->real_field)) {
 
-                     $tmpV[$tmpKK] = $tmpVV;
 
-                 }
 
-             }
 
-         }
 
-         return $result;
 
-     }
 
- 	/**
 
-      *
 
-      * 获取指定时间$update_time后的最新id集
 
-      * @param mixed $limit
 
-      * @return array
 
-      */
 
-     public function getsLatestIdsByUpdateTime($update_time, $limit = null) {
 
- 		$order = 'update_time ASC';
 
- 		$condition = array(
 
- 			'update_time'	=> SqlHelper::addCompareOperator('>=', $update_time),
 
- 		);
 
- 		return $this->findIdsBy($condition, $limit, $order);
 
-     }
 
- }
 
 
  |