|
<?php
// +----------------------------------------------------------------------
// | TOPThink [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2010 http://topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id: MongoModel.class.php 2576 2012-01-12 15:09:01Z liu21st $
/**
+------------------------------------------------------------------------------
* TOPThink MongoModel模型类
* 实现了ODM和ActiveRecords模式
+------------------------------------------------------------------------------
* @category Think
* @package Think
* @subpackage Core
* @author liu21st <liu21st@gmail.com>
* @version $Id: MongoModel.class.php 2576 2012-01-12 15:09:01Z liu21st $
+------------------------------------------------------------------------------
*/
class MongoModel extends Model{
// 主键类型
const TYPE_OBJECT = 1;
const TYPE_INT = 2;
const TYPE_STRING = 3;
// 主键名称
protected $pk = '_id';
// _id 类型 1 Object 采用MongoId对象 2 Int 整形 支持自动增长 3 String 字符串Hash
protected $_idType = self::TYPE_OBJECT;
// 主键是否自动增长 支持Int型主键
protected $_autoInc = false;
// Mongo默认关闭字段检测 可以动态追加字段
protected $autoCheckFields = false;
/**
+----------------------------------------------------------
* 利用__call方法实现一些特殊的Model方法
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $method 方法名称
* @param array $args 调用参数
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function __call($method,$args) {
if(in_array(strtolower($method),array('table','where','order','limit','page'),true)) {
// 连贯操作的实现
$this->options[strtolower($method)] = $args[0];
return $this;
}elseif(strtolower(substr($method,0,5))=='getby') {
// 根据某个字段获取记录
$field = parse_name(substr($method,5));
$where[$field] =$args[0];
return $this->where($where)->find();
}elseif(strtolower(substr($method,0,10))=='getfieldby') {
// 根据某个字段获取记录的某个值
$name = parse_name(substr($method,10));
$where[$name] =$args[0];
return $this->where($where)->getField($args[1]);
}else{
throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
return;
}
}
/**
+----------------------------------------------------------
* 获取字段信息并缓存 主键和自增信息直接配置
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @return void
+----------------------------------------------------------
*/
public function flush() {
// 缓存不存在则查询数据表信息
$fields = $this->db->getFields();
if(!$fields) { // 暂时没有数据无法获取字段信息 下次查询
return false;
}
$this->fields = array_keys($fields);
$this->fields['_pk'] = $this->pk;
$this->fields['_autoinc'] = $this->_autoInc;
foreach ($fields as $key=>$val){
// 记录字段类型
$type[$key] = $val['type'];
}
// 记录字段类型信息
if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type;
// 2008-3-7 增加缓存开关控制
if(C('DB_FIELDS_CACHE')){
// 永久缓存数据表信息
$db = $this->dbName?$this->dbName:C('DB_NAME');
F('_fields/'.$db.'.'.$this->name,$this->fields);
}
}
// 写入数据前的回调方法 包括新增和更新
protected function _before_write(&$data) {
$pk = $this->getPk();
// 根据主键类型处理主键数据
if(isset($data[$pk]) && $this->_idType == self::TYPE_OBJECT) {
$data[$pk] = new MongoId($data[$pk]);
}
}
/**
+----------------------------------------------------------
* count统计 配合where连贯操作
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @return integer
+----------------------------------------------------------
*/
public function count(){
// 分析表达式
$options = $this->_parseOptions();
return $this->db->count($options);
}
/**
+----------------------------------------------------------
* 获取下一ID 用于自动增长型
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $pk 字段名 默认为主键
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function getMongoNextId($pk=''){
if(empty($pk)) {
$pk = $this->getPk();
}
return $this->db->mongo_next_id($pk);
}
// 插入数据前的回调方法
protected function _before_insert(&$data,$options) {
// 写入数据到数据库
if($this->_autoInc && $this->_idType== self::TYPE_INT) { // 主键自动增长
$pk = $this->getPk();
if(!isset($data[$pk])) {
$data[$pk] = $this->db->mongo_next_id($pk);
}
}
}
public function clear(){
return $this->db->clear();
}
// 查询成功后的回调方法
protected function _after_select(&$resultSet,$options) {
array_walk($resultSet,array($this,'checkMongoId'));
}
/**
+----------------------------------------------------------
* 获取MongoId
+----------------------------------------------------------
* @access protected
+----------------------------------------------------------
* @param array $result 返回数据
+----------------------------------------------------------
* @return array
+----------------------------------------------------------
*/
protected function checkMongoId(&$result){
if(is_object($result['_id'])) {
$result['_id'] = $result['_id']->__toString();
}
return $result;
}
// 表达式过滤回调方法
protected function _options_filter(&$options) {
$id = $this->getPk();
if(isset($options['where'][$id]) && $this->_idType== self::TYPE_OBJECT) {
$options['where'][$id] = new MongoId($options['where'][$id]);
}
}
/**
+----------------------------------------------------------
* 查询数据
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param mixed $options 表达式参数
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function find($options=array()) {
if( is_numeric($options) || is_string($options)) {
$id = $this->getPk();
$where[$id] = $options;
$options = array();
$options['where'] = $where;
}
// 分析表达式
$options = $this->_parseOptions($options);
$result = $this->db->find($options);
if(false === $result) {
return false;
}
if(empty($result)) {// 查询结果为空
return null;
}else{
$this->checkMongoId($result);
}
$this->data = $result;
$this->_after_find($this->data,$options);
return $this->data;
}
/**
+----------------------------------------------------------
* 字段值增长
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $field 字段名
* @param integer $step 增长值
+----------------------------------------------------------
* @return boolean
+----------------------------------------------------------
*/
public function setInc($field,$step=1) {
return $this->setField($field,array('inc',$step));
}
/**
+----------------------------------------------------------
* 字段值减少
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $field 字段名
* @param integer $step 减少值
+----------------------------------------------------------
* @return boolean
+----------------------------------------------------------
*/
public function setDec($field,$step=1) {
return $this->setField($field,array('inc','-'.$step));
}
/**
+----------------------------------------------------------
* 获取一条记录的某个字段值
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $field 字段名
* @param string $spea 字段数据间隔符号
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function getField($field,$sepa=null) {
$options['field'] = $field;
$options = $this->_parseOptions($options);
if(strpos($field,',')) { // 多字段
$resultSet = $this->db->select($options);
if(!empty($resultSet)) {
$_field = explode(',', $field);
$field = array_keys($resultSet[0]);
$move = $_field[0]==$_field[1]?false:true;
$key = array_shift($field);
$key2 = array_shift($field);
$cols = array();
$count = count($_field);
foreach ($resultSet as $result){
$name = $result[$key];
if($move) { // 删除键值记录
unset($result[$key]);
}
if(2==$count) {
$cols[$name] = $result[$key2];
}else{
$cols[$name] = is_null($sepa)?$result:implode($sepa,$result);
}
}
return $cols;
}
}else{ // 查找一条记录
$result = $this->db->find($options);
if(!empty($result)) {
return $result[$field];
}
}
return null;
}
/**
+----------------------------------------------------------
* 执行Mongo指令
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param array $command 指令
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function command($command) {
return $this->db->command($command);
}
/**
+----------------------------------------------------------
* 执行MongoCode
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $code MongoCode
* @param array $args 参数
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function mongoCode($code,$args=array()) {
return $this->db->execute($code,$args);
}
// 数据库切换后回调方法
protected function _after_db() {
// 切换Collection
$this->db->switchCollection($this->getTableName(),$this->dbName?$this->dbName:C('db_name'));
}
/**
+----------------------------------------------------------
* 得到完整的数据表名 Mongo表名不带dbName
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @return string
+----------------------------------------------------------
*/
public function getTableName() {
if(empty($this->trueTableName)) {
$tableName = !empty($this->tablePrefix) ? $this->tablePrefix : '';
if(!empty($this->tableName)) {
$tableName .= $this->tableName;
}else{
$tableName .= parse_name($this->name);
}
$this->trueTableName = strtolower($tableName);
}
return $this->trueTableName;
}
}
|