123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- <?php
- // +----------------------------------------------------------------------
- // | ThinkPHP [ 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>
- // +----------------------------------------------------------------------
- /**
- * MongoModel模型类
- * 实现了ODM和ActiveRecords模式
- * @category Extend
- * @package Extend
- * @subpackage Model
- * @author liu21st <liu21st@gmail.com>
- */
- 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;
- // 链操作方法列表
- protected $methods = array('table','order','auto','filter','validate');
- /**
- * 利用__call方法实现一些特殊的Model方法
- * @access public
- * @param string $method 方法名称
- * @param array $args 调用参数
- * @return mixed
- */
- public function __call($method,$args) {
- if(in_array(strtolower($method),$this->methods,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]) && is_scalar($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,',')) { // 多字段
- if(is_numeric($sepa)) {// 限定数量
- $options['limit'] = $sepa;
- $sepa = null;// 重置为null 返回数组
- }
- $resultSet = $this->db->select($options);
- if(!empty($resultSet)) {
- $_field = explode(',', $field);
- $field = array_keys($resultSet[0]);
- $key = array_shift($field);
- $key2 = array_shift($field);
- $cols = array();
- $count = count($_field);
- foreach ($resultSet as $result){
- $name = $result[$key];
- if(2==$count) {
- $cols[$name] = $result[$key2];
- }else{
- $cols[$name] = is_null($sepa)?$result:implode($sepa,$result);
- }
- }
- return $cols;
- }
- }else{
- // 返回数据个数
- if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据
- $options['limit'] = is_numeric($sepa)?$sepa:1;
- } // 查找一条记录
- $result = $this->db->find($options);
- if(!empty($result)) {
- if(1==$options['limit']) return reset($result[0]);
- foreach ($result as $val){
- $array[] = $val[$field];
- }
- return $array;
- }
- }
- 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;
- }
- }
|