You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

891 lines
29 KiB

3 years ago
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 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. namespace Think\Db\Driver;
  12. use Think\Db\Driver;
  13. /**
  14. * Mongo数据库驱动
  15. */
  16. class Mongo extends Driver
  17. {
  18. protected $_mongo = null; // MongoDb Object
  19. protected $_collection = null; // MongoCollection Object
  20. protected $_dbName = ''; // dbName
  21. protected $_collectionName = ''; // collectionName
  22. protected $_cursor = null; // MongoCursor Object
  23. protected $comparison = array('neq' => 'ne', 'ne' => 'ne', 'gt' => 'gt', 'egt' => 'gte', 'gte' => 'gte', 'lt' => 'lt', 'elt' => 'lte', 'lte' => 'lte', 'in' => 'in', 'not in' => 'nin', 'nin' => 'nin');
  24. /**
  25. * 架构函数 读取数据库配置信息
  26. * @access public
  27. * @param array $config 数据库配置数组
  28. */
  29. public function __construct($config = '')
  30. {
  31. if (!class_exists('mongoClient')) {
  32. E(L('_NOT_SUPPORT_') . ':Mongo');
  33. }
  34. if (!empty($config)) {
  35. $this->config = array_merge($this->config, $config);
  36. if (empty($this->config['params'])) {
  37. $this->config['params'] = array();
  38. }
  39. }
  40. }
  41. /**
  42. * 连接数据库方法
  43. * @access public
  44. */
  45. public function connect($config = '', $linkNum = 0)
  46. {
  47. if (!isset($this->linkID[$linkNum])) {
  48. if (empty($config)) {
  49. $config = $this->config;
  50. }
  51. $host = 'mongodb://' . ($config['username'] ? "{$config['username']}" : '') . ($config['password'] ? ":{$config['password']}@" : '') . $config['hostname'] . ($config['hostport'] ? ":{$config['hostport']}" : '') . '/' . ($config['database'] ? "{$config['database']}" : '');
  52. try {
  53. $this->linkID[$linkNum] = new \mongoClient($host, $this->config['params']);
  54. } catch (\MongoConnectionException $e) {
  55. E($e->getmessage());
  56. }
  57. }
  58. return $this->linkID[$linkNum];
  59. }
  60. /**
  61. * 切换当前操作的Db和Collection
  62. * @access public
  63. * @param string $collection collection
  64. * @param string $db db
  65. * @param boolean $master 是否主服务器
  66. * @return void
  67. */
  68. public function switchCollection($collection, $db = '', $master = true)
  69. {
  70. // 当前没有连接 则首先进行数据库连接
  71. if (!$this->_linkID) {
  72. $this->initConnect($master);
  73. }
  74. try {
  75. if (!empty($db)) {
  76. // 传人Db则切换数据库
  77. // 当前MongoDb对象
  78. $this->_dbName = $db;
  79. $this->_mongo = $this->_linkID->selectDb($db);
  80. }
  81. // 当前MongoCollection对象
  82. if ($this->config['debug']) {
  83. $this->queryStr = $this->_dbName . '.getCollection(' . $collection . ')';
  84. }
  85. if ($this->_collectionName != $collection) {
  86. $this->queryTimes++;
  87. N('db_query', 1); // 兼容代码
  88. $this->debug(true);
  89. $this->_collection = $this->_mongo->selectCollection($collection);
  90. $this->debug(false);
  91. $this->_collectionName = $collection; // 记录当前Collection名称
  92. }
  93. } catch (MongoException $e) {
  94. E($e->getMessage());
  95. }
  96. }
  97. /**
  98. * 释放查询结果
  99. * @access public
  100. */
  101. public function free()
  102. {
  103. $this->_cursor = null;
  104. }
  105. /**
  106. * 执行命令
  107. * @access public
  108. * @param array $command 指令
  109. * @return array
  110. */
  111. public function command($command = array(), $options = array())
  112. {
  113. $cache = isset($options['cache']) ? $options['cache'] : false;
  114. if ($cache) {
  115. // 查询缓存检测
  116. $key = is_string($cache['key']) ? $cache['key'] : md5(serialize($command));
  117. $value = S($key, '', '', $cache['type']);
  118. if (false !== $value) {
  119. return $value;
  120. }
  121. }
  122. N('db_write', 1); // 兼容代码
  123. $this->executeTimes++;
  124. try {
  125. if ($this->config['debug']) {
  126. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.runCommand(';
  127. $this->queryStr .= json_encode($command);
  128. $this->queryStr .= ')';
  129. }
  130. $this->debug(true);
  131. $result = $this->_mongo->command($command);
  132. $this->debug(false);
  133. if ($cache && $result['ok']) {
  134. // 查询缓存写入
  135. S($key, $result, $cache['expire'], $cache['type']);
  136. }
  137. return $result;
  138. } catch (\MongoCursorException $e) {
  139. E($e->getMessage());
  140. }
  141. }
  142. /**
  143. * 执行语句
  144. * @access public
  145. * @param string $code sql指令
  146. * @param array $args 参数
  147. * @return mixed
  148. */
  149. public function execute($code, $args = array())
  150. {
  151. $this->executeTimes++;
  152. N('db_write', 1); // 兼容代码
  153. $this->debug(true);
  154. $this->queryStr = 'execute:' . $code;
  155. $result = $this->_mongo->execute($code, $args);
  156. $this->debug(false);
  157. if ($result['ok']) {
  158. return $result['retval'];
  159. } else {
  160. E($result['errmsg']);
  161. }
  162. }
  163. /**
  164. * 关闭数据库
  165. * @access public
  166. */
  167. public function close()
  168. {
  169. if ($this->_linkID) {
  170. $this->_linkID->close();
  171. $this->_linkID = null;
  172. $this->_mongo = null;
  173. $this->_collection = null;
  174. $this->_cursor = null;
  175. }
  176. }
  177. /**
  178. * 数据库错误信息
  179. * @access public
  180. * @return string
  181. */
  182. public function error()
  183. {
  184. $this->error = $this->_mongo->lastError();
  185. trace($this->error, '', 'ERR');
  186. return $this->error;
  187. }
  188. /**
  189. * 插入记录
  190. * @access public
  191. * @param mixed $data 数据
  192. * @param array $options 参数表达式
  193. * @param boolean $replace 是否replace
  194. * @return false | integer
  195. */
  196. public function insert($data, $options = array(), $replace = false)
  197. {
  198. if (isset($options['table'])) {
  199. $this->switchCollection($options['table']);
  200. }
  201. $this->model = $options['model'];
  202. $this->executeTimes++;
  203. N('db_write', 1); // 兼容代码
  204. if ($this->config['debug']) {
  205. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.insert(';
  206. $this->queryStr .= $data ? json_encode($data) : '{}';
  207. $this->queryStr .= ')';
  208. }
  209. try {
  210. $this->debug(true);
  211. $result = $replace ? $this->_collection->save($data) : $this->_collection->insert($data);
  212. $this->debug(false);
  213. if ($result) {
  214. $_id = $data['_id'];
  215. if (is_object($_id)) {
  216. $_id = $_id->__toString();
  217. }
  218. $this->lastInsID = $_id;
  219. }
  220. return $result;
  221. } catch (\MongoCursorException $e) {
  222. E($e->getMessage());
  223. }
  224. }
  225. /**
  226. * 插入多条记录
  227. * @access public
  228. * @param array $dataList 数据
  229. * @param array $options 参数表达式
  230. * @return bool
  231. */
  232. public function insertAll($dataList, $options = array())
  233. {
  234. if (isset($options['table'])) {
  235. $this->switchCollection($options['table']);
  236. }
  237. $this->model = $options['model'];
  238. $this->executeTimes++;
  239. N('db_write', 1); // 兼容代码
  240. try {
  241. $this->debug(true);
  242. $result = $this->_collection->batchInsert($dataList);
  243. $this->debug(false);
  244. return $result;
  245. } catch (\MongoCursorException $e) {
  246. E($e->getMessage());
  247. }
  248. }
  249. /**
  250. * 生成下一条记录ID 用于自增非MongoId主键
  251. * @access public
  252. * @param string $pk 主键名
  253. * @return integer
  254. */
  255. public function getMongoNextId($pk,$options=array())
  256. {
  257. if (isset($options['table'])) {
  258. $this->switchCollection($options['table']);
  259. }
  260. if ($this->config['debug']) {
  261. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.find({},{' . $pk . ':1}).sort({' . $pk . ':-1}).limit(1)';
  262. }
  263. try {
  264. $this->debug(true);
  265. $result = $this->_collection->find(array(), array($pk => 1))->sort(array($pk => -1))->limit(1);
  266. $this->debug(false);
  267. } catch (\MongoCursorException $e) {
  268. E($e->getMessage());
  269. }
  270. $data = $result->getNext();
  271. return isset($data[$pk]) ? $data[$pk] + 1 : 1;
  272. }
  273. /**
  274. * 更新记录
  275. * @access public
  276. * @param mixed $data 数据
  277. * @param array $options 表达式
  278. * @return bool
  279. */
  280. public function update($data, $options)
  281. {
  282. if (isset($options['table'])) {
  283. $this->switchCollection($options['table']);
  284. }
  285. $this->executeTimes++;
  286. N('db_write', 1); // 兼容代码
  287. $this->model = $options['model'];
  288. $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());
  289. $set = $this->parseSet($data);
  290. if ($this->config['debug']) {
  291. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.update(';
  292. $this->queryStr .= $query ? json_encode($query) : '{}';
  293. $this->queryStr .= ',' . json_encode($set) . ')';
  294. }
  295. try {
  296. $this->debug(true);
  297. if (isset($options['limit']) && 1 == $options['limit']) {
  298. $multiple = array("multiple" => false);
  299. } else {
  300. $multiple = array("multiple" => true);
  301. }
  302. $result = $this->_collection->update($query, $set, $multiple);
  303. $this->debug(false);
  304. return $result;
  305. } catch (\MongoCursorException $e) {
  306. E($e->getMessage());
  307. }
  308. }
  309. /**
  310. * 删除记录
  311. * @access public
  312. * @param array $options 表达式
  313. * @return false | integer
  314. */
  315. public function delete($options = array())
  316. {
  317. if (isset($options['table'])) {
  318. $this->switchCollection($options['table']);
  319. }
  320. $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());
  321. $this->model = $options['model'];
  322. $this->executeTimes++;
  323. N('db_write', 1); // 兼容代码
  324. if ($this->config['debug']) {
  325. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.remove(' . json_encode($query) . ')';
  326. }
  327. try {
  328. $this->debug(true);
  329. $result = $this->_collection->remove($query);
  330. $this->debug(false);
  331. return $result;
  332. } catch (\MongoCursorException $e) {
  333. E($e->getMessage());
  334. }
  335. }
  336. /**
  337. * 清空记录
  338. * @access public
  339. * @param array $options 表达式
  340. * @return false | integer
  341. */
  342. public function clear($options = array())
  343. {
  344. if (isset($options['table'])) {
  345. $this->switchCollection($options['table']);
  346. }
  347. $this->model = $options['model'];
  348. $this->executeTimes++;
  349. N('db_write', 1); // 兼容代码
  350. if ($this->config['debug']) {
  351. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.remove({})';
  352. }
  353. try {
  354. $this->debug(true);
  355. $result = $this->_collection->drop();
  356. $this->debug(false);
  357. return $result;
  358. } catch (\MongoCursorException $e) {
  359. E($e->getMessage());
  360. }
  361. }
  362. /**
  363. * 查找记录
  364. * @access public
  365. * @param array $options 表达式
  366. * @return iterator
  367. */
  368. public function select($options = array())
  369. {
  370. if (isset($options['table'])) {
  371. $this->switchCollection($options['table'], '', false);
  372. }
  373. $this->model = $options['model'];
  374. $this->queryTimes++;
  375. N('db_query', 1); // 兼容代码
  376. $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());
  377. $field = $this->parseField(isset($options['field']) ? $options['field'] : array());
  378. try {
  379. if ($this->config['debug']) {
  380. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.find(';
  381. $this->queryStr .= $query ? json_encode($query) : '{}';
  382. if (is_array($field) && count($field)) {
  383. foreach ($field as $f => $v) {
  384. $_field_array[$f] = $v ? 1 : 0;
  385. }
  386. $this->queryStr .= $field ? ', ' . json_encode($_field_array) : ', {}';
  387. }
  388. $this->queryStr .= ')';
  389. }
  390. $this->debug(true);
  391. $_cursor = $this->_collection->find($query, $field);
  392. if (!empty($options['order'])) {
  393. $order = $this->parseOrder($options['order']);
  394. if ($this->config['debug']) {
  395. $this->queryStr .= '.sort(' . json_encode($order) . ')';
  396. }
  397. $_cursor = $_cursor->sort($order);
  398. }
  399. if (isset($options['page'])) {
  400. // 根据页数计算limit
  401. list($page, $length) = $options['page'];
  402. $page = $page > 0 ? $page : 1;
  403. $length = $length > 0 ? $length : (is_numeric($options['limit']) ? $options['limit'] : 20);
  404. $offset = $length * ((int) $page - 1);
  405. $options['limit'] = $offset . ',' . $length;
  406. }
  407. if (isset($options['limit'])) {
  408. list($offset, $length) = $this->parseLimit($options['limit']);
  409. if (!empty($offset)) {
  410. if ($this->config['debug']) {
  411. $this->queryStr .= '.skip(' . intval($offset) . ')';
  412. }
  413. $_cursor = $_cursor->skip(intval($offset));
  414. }
  415. if ($this->config['debug']) {
  416. $this->queryStr .= '.limit(' . intval($length) . ')';
  417. }
  418. $_cursor = $_cursor->limit(intval($length));
  419. }
  420. $this->debug(false);
  421. $this->_cursor = $_cursor;
  422. $resultSet = iterator_to_array($_cursor);
  423. return $resultSet;
  424. } catch (\MongoCursorException $e) {
  425. E($e->getMessage());
  426. }
  427. }
  428. /**
  429. * 查找某个记录
  430. * @access public
  431. * @param array $options 表达式
  432. * @return array
  433. */
  434. public function find($options = array())
  435. {
  436. $options['limit'] = 1;
  437. $find = $this->select($options);
  438. return array_shift($find);
  439. }
  440. /**
  441. * 统计记录数
  442. * @access public
  443. * @param array $options 表达式
  444. * @return iterator
  445. */
  446. public function count($options = array())
  447. {
  448. if (isset($options['table'])) {
  449. $this->switchCollection($options['table'], '', false);
  450. }
  451. $this->model = $options['model'];
  452. $this->queryTimes++;
  453. N('db_query', 1); // 兼容代码
  454. $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());
  455. if ($this->config['debug']) {
  456. $this->queryStr = $this->_dbName . '.' . $this->_collectionName;
  457. $this->queryStr .= $query ? '.find(' . json_encode($query) . ')' : '';
  458. $this->queryStr .= '.count()';
  459. }
  460. try {
  461. $this->debug(true);
  462. $count = $this->_collection->count($query);
  463. $this->debug(false);
  464. return $count;
  465. } catch (\MongoCursorException $e) {
  466. E($e->getMessage());
  467. }
  468. }
  469. public function group($keys, $initial, $reduce, $options = array())
  470. {
  471. if (isset($options['table']) && $this->_collectionName != $options['table']) {
  472. $this->switchCollection($options['table'], '', false);
  473. }
  474. $cache = isset($options['cache']) ? $options['cache'] : false;
  475. if ($cache) {
  476. $key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));
  477. $value = S($key, '', '', $cache['type']);
  478. if (false !== $value) {
  479. return $value;
  480. }
  481. }
  482. $this->model = $options['model'];
  483. $this->queryTimes++;
  484. N('db_query', 1); // 兼容代码
  485. $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());
  486. if ($this->config['debug']) {
  487. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.group({key:' . json_encode($keys) . ',cond:' .
  488. json_encode($options['condition']) . ',reduce:' .
  489. json_encode($reduce) . ',initial:' .
  490. json_encode($initial) . '})';
  491. }
  492. try {
  493. $this->debug(true);
  494. $option = array();
  495. isset($options['condition'])&&$option['condition']=$options['condition'];
  496. isset($options['finalize'])&&$option['finalize']=$options['condition'];
  497. isset($options['maxTimeMS'])&&$option['maxTimeMS']=$options['condition'];
  498. $group = $this->_collection->group($keys,$initial,$reduce,$option);
  499. $this->debug(false);
  500. if ($cache && $group['ok']) {
  501. S($key, $group, $cache['expire'], $cache['type']);
  502. }
  503. return $group;
  504. } catch (\MongoCursorException $e) {
  505. E($e->getMessage());
  506. }
  507. }
  508. /**
  509. * 取得数据表的字段信息
  510. * @access public
  511. * @return array
  512. */
  513. public function getFields($collection = '')
  514. {
  515. if (!empty($collection) && $collection != $this->_collectionName) {
  516. $this->switchCollection($collection, '', false);
  517. }
  518. $this->queryTimes++;
  519. N('db_query', 1); // 兼容代码
  520. if ($this->config['debug']) {
  521. $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.findOne()';
  522. }
  523. try {
  524. $this->debug(true);
  525. $result = $this->_collection->findOne();
  526. $this->debug(false);
  527. } catch (\MongoCursorException $e) {
  528. E($e->getMessage());
  529. }
  530. if ($result) {
  531. // 存在数据则分析字段
  532. $info = array();
  533. foreach ($result as $key => $val) {
  534. $info[$key] = array(
  535. 'name' => $key,
  536. 'type' => getType($val),
  537. );
  538. }
  539. return $info;
  540. }
  541. // 暂时没有数据 返回false
  542. return false;
  543. }
  544. /**
  545. * 取得当前数据库的collection信息
  546. * @access public
  547. */
  548. public function getTables()
  549. {
  550. if ($this->config['debug']) {
  551. $this->queryStr = $this->_dbName . '.getCollenctionNames()';
  552. }
  553. $this->queryTimes++;
  554. N('db_query', 1); // 兼容代码
  555. $this->debug(true);
  556. $list = $this->_mongo->listCollections();
  557. $this->debug(false);
  558. $info = array();
  559. foreach ($list as $collection) {
  560. $info[] = $collection->getName();
  561. }
  562. return $info;
  563. }
  564. /**
  565. * 取得当前数据库的对象
  566. * @access public
  567. * @return object mongoClient
  568. */
  569. public function getDB()
  570. {
  571. return $this->_mongo;
  572. }
  573. /**
  574. * 取得当前集合的对象
  575. * @access public
  576. * @return object MongoCollection
  577. */
  578. public function getCollection()
  579. {
  580. return $this->_collection;
  581. }
  582. /**
  583. * set分析
  584. * @access protected
  585. * @param array $data
  586. * @return string
  587. */
  588. protected function parseSet($data)
  589. {
  590. $result = array();
  591. foreach ($data as $key => $val) {
  592. if (is_array($val)) {
  593. switch ($val[0]) {
  594. case 'inc':
  595. $result['$inc'][$key] = (float) $val[1];
  596. break;
  597. case 'set':
  598. case 'unset':
  599. case 'push':
  600. case 'pushall':
  601. case 'addtoset':
  602. case 'pop':
  603. case 'pull':
  604. case 'pullall':
  605. $result['$' . $val[0]][$key] = $val[1];
  606. break;
  607. default:
  608. $result['$set'][$key] = $val;
  609. }
  610. } else {
  611. $result['$set'][$key] = $val;
  612. }
  613. }
  614. return $result;
  615. }
  616. /**
  617. * order分析
  618. * @access protected
  619. * @param mixed $order
  620. * @return array
  621. */
  622. protected function parseOrder($order)
  623. {
  624. if (is_string($order)) {
  625. $array = explode(',', $order);
  626. $order = array();
  627. foreach ($array as $key => $val) {
  628. $arr = explode(' ', trim($val));
  629. if (isset($arr[1])) {
  630. $arr[1] = 'asc' == $arr[1] ? 1 : -1;
  631. } else {
  632. $arr[1] = 1;
  633. }
  634. $order[$arr[0]] = $arr[1];
  635. }
  636. }
  637. return $order;
  638. }
  639. /**
  640. * limit分析
  641. * @access protected
  642. * @param mixed $limit
  643. * @return array
  644. */
  645. protected function parseLimit($limit)
  646. {
  647. if (strpos($limit, ',')) {
  648. $array = explode(',', $limit);
  649. } else {
  650. $array = array(0, $limit);
  651. }
  652. return $array;
  653. }
  654. /**
  655. * field分析
  656. * @access protected
  657. * @param mixed $fields
  658. * @return array
  659. */
  660. public function parseField($fields)
  661. {
  662. if (empty($fields)) {
  663. $fields = array();
  664. }
  665. if (is_string($fields)) {
  666. $_fields = explode(',', $fields);
  667. $fields = array();
  668. foreach ($_fields as $f) {
  669. $fields[$f] = true;
  670. }
  671. } elseif (is_array($fields)) {
  672. $_fields = $fields;
  673. $fields = array();
  674. foreach ($_fields as $f => $v) {
  675. if (is_numeric($f)) {
  676. $fields[$v] = true;
  677. } else {
  678. $fields[$f] = $v ? true : false;
  679. }
  680. }
  681. }
  682. return $fields;
  683. }
  684. /**
  685. * where分析
  686. * @access protected
  687. * @param mixed $where
  688. * @return array
  689. */
  690. public function parseWhere($where)
  691. {
  692. $query = array();
  693. $return = array();
  694. $_logic = '$and';
  695. if (isset($where['_logic'])) {
  696. $where['_logic'] = strtolower($where['_logic']);
  697. $_logic = in_array($where['_logic'], array('or', 'xor', 'nor', 'and')) ? '$' . $where['_logic'] : $_logic;
  698. unset($where['_logic']);
  699. }
  700. foreach ($where as $key => $val) {
  701. if ('_id' != $key && 0 === strpos($key, '_')) {
  702. // 解析特殊条件表达式
  703. $parse = $this->parseThinkWhere($key, $val);
  704. $query = array_merge($query, $parse);
  705. } else {
  706. // 查询字段的安全过滤
  707. if (!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/', trim($key))) {
  708. E(L('_ERROR_QUERY_') . ':' . $key);
  709. }
  710. $key = trim($key);
  711. if (strpos($key, '|')) {
  712. $array = explode('|', $key);
  713. $str = array();
  714. foreach ($array as $k) {
  715. $str[] = $this->parseWhereItem($k, $val);
  716. }
  717. $query['$or'] = $str;
  718. } elseif (strpos($key, '&')) {
  719. $array = explode('&', $key);
  720. $str = array();
  721. foreach ($array as $k) {
  722. $str[] = $this->parseWhereItem($k, $val);
  723. }
  724. $query = array_merge($query, $str);
  725. } else {
  726. $str = $this->parseWhereItem($key, $val);
  727. $query = array_merge($query, $str);
  728. }
  729. }
  730. }
  731. if ('$and' == $_logic) {
  732. return $query;
  733. }
  734. foreach ($query as $key => $val) {
  735. $return[$_logic][] = array($key => $val);
  736. }
  737. return $return;
  738. }
  739. /**
  740. * 特殊条件分析
  741. * @access protected
  742. * @param string $key
  743. * @param mixed $val
  744. * @return string
  745. */
  746. protected function parseThinkWhere($key, $val)
  747. {
  748. $query = array();
  749. $_logic = array('or', 'xor', 'nor', 'and');
  750. switch ($key) {
  751. case '_query': // 字符串模式查询条件
  752. parse_str($val, $query);
  753. if (isset($query['_logic']) && strtolower($query['_logic']) == 'or') {
  754. unset($query['_logic']);
  755. $query['$or'] = $query;
  756. }
  757. break;
  758. case '_complex': // 子查询模式查询条件
  759. $__logic = strtolower($val['_logic']);
  760. if (isset($val['_logic']) && in_array($__logic, $_logic)) {
  761. unset($val['_logic']);
  762. $query['$' . $__logic] = $val;
  763. }
  764. break;
  765. case '_string': // MongoCode查询
  766. $query['$where'] = new \MongoCode($val);
  767. break;
  768. }
  769. //兼容 MongoClient OR条件查询方法
  770. if (isset($query['$or']) && !is_array(current($query['$or']))) {
  771. $val = array();
  772. foreach ($query['$or'] as $k => $v) {
  773. $val[] = array($k => $v);
  774. }
  775. $query['$or'] = $val;
  776. }
  777. return $query;
  778. }
  779. /**
  780. * where子单元分析
  781. * @access protected
  782. * @param string $key
  783. * @param mixed $val
  784. * @return array
  785. */
  786. protected function parseWhereItem($key, $val)
  787. {
  788. $query = array();
  789. if (is_array($val)) {
  790. if (is_string($val[0])) {
  791. $con = strtolower($val[0]);
  792. if (in_array($con, array('neq', 'ne', 'gt', 'egt', 'gte', 'lt', 'lte', 'elt'))) {
  793. // 比较运算
  794. $k = '$' . $this->comparison[$con];
  795. $query[$key] = array($k => $val[1]);
  796. } elseif ('like' == $con) {
  797. // 模糊查询 采用正则方式
  798. $query[$key] = new \MongoRegex("/" . $val[1] . "/");
  799. } elseif ('mod' == $con) {
  800. // mod 查询
  801. $query[$key] = array('$mod' => $val[1]);
  802. } elseif ('regex' == $con) {
  803. // 正则查询
  804. $query[$key] = new \MongoRegex($val[1]);
  805. } elseif (in_array($con, array('in', 'nin', 'not in'))) {
  806. // IN NIN 运算
  807. $data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];
  808. $k = '$' . $this->comparison[$con];
  809. $query[$key] = array($k => $data);
  810. } elseif ('all' == $con) {
  811. // 满足所有指定条件
  812. $data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];
  813. $query[$key] = array('$all' => $data);
  814. } elseif ('between' == $con) {
  815. // BETWEEN运算
  816. $data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];
  817. $query[$key] = array('$gte' => $data[0], '$lte' => $data[1]);
  818. } elseif ('not between' == $con) {
  819. $data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];
  820. $query[$key] = array('$lt' => $data[0], '$gt' => $data[1]);
  821. } elseif ('exp' == $con) {
  822. // 表达式查询
  823. $query['$where'] = new \MongoCode($val[1]);
  824. } elseif ('exists' == $con) {
  825. // 字段是否存在
  826. $query[$key] = array('$exists' => (bool) $val[1]);
  827. } elseif ('size' == $con) {
  828. // 限制属性大小
  829. $query[$key] = array('$size' => intval($val[1]));
  830. } elseif ('type' == $con) {
  831. // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型
  832. $query[$key] = array('$type' => intval($val[1]));
  833. } else {
  834. $query[$key] = $val;
  835. }
  836. return $query;
  837. }
  838. }
  839. $query[$key] = $val;
  840. return $query;
  841. }
  842. }