mao.class.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. <?php
  2. /**
  3. * ZenTaoPHP的mao类。
  4. * The mao class file of ZenTaoPHP framework.
  5. *
  6. * The author disclaims copyright to this source code. In place of
  7. * a legal notice, here is a blessing:
  8. *
  9. * May you do good and not evil.
  10. * May you find forgiveness for yourself and forgive others.
  11. * May you share freely, never taking more than you give.
  12. */
  13. /**
  14. * Mao类。
  15. * Mao class.
  16. *
  17. * @package framework
  18. */
  19. class baseMao
  20. {
  21. /**
  22. * 全局对象$app
  23. * The global app object.
  24. *
  25. * @var object
  26. * @access public
  27. */
  28. public $app;
  29. /**
  30. * 全局对象$config
  31. * The global config object.
  32. *
  33. * @var object
  34. * @access public
  35. */
  36. public $config;
  37. /**
  38. * 全局对象$dao
  39. * The global dao object.
  40. *
  41. * @var object
  42. * @access protected
  43. */
  44. protected $dao;
  45. /**
  46. * 全局对象$cache
  47. * The global cache object.
  48. *
  49. * @var object
  50. * @access public
  51. */
  52. public $cache = null;
  53. /**
  54. * 正在使用的表。
  55. * The table of current query.
  56. *
  57. * @var string
  58. * @access public
  59. */
  60. public $table;
  61. /**
  62. * 查询的字段。
  63. * The fields will be returned.
  64. *
  65. * @var array
  66. * @access public
  67. */
  68. public $fields;
  69. /**
  70. * 查询条件。
  71. * Conditions.
  72. *
  73. * @var array
  74. * @access public
  75. */
  76. public $conditions;
  77. /**
  78. * 正在组装的查询条件。
  79. * Condition.
  80. *
  81. * @var array
  82. * @access public
  83. */
  84. public $condition;
  85. /**
  86. * 是否在判断条件成立。
  87. * Checking condition.
  88. *
  89. * @var bool
  90. * @access public
  91. */
  92. public $isConditionChecking;
  93. /**
  94. * 条件是否成立。
  95. * Condition is true.
  96. *
  97. * @var bool
  98. * @access public
  99. */
  100. public $conditionIsTrue;
  101. /**
  102. * 待处理的数据。
  103. * The data to be processed.
  104. *
  105. * @var array
  106. * @access public
  107. */
  108. public $data;
  109. /**
  110. * 待处理数据的column。
  111. * The column of data.
  112. *
  113. * @var string
  114. * @access public
  115. */
  116. public $dataColumn;
  117. /**
  118. * 构造方法。
  119. * The construct method.
  120. *
  121. * @access public
  122. * @param object $app
  123. * @return void
  124. */
  125. public function __construct($app)
  126. {
  127. global $config;
  128. $this->app = $app;
  129. $this->config = $config;
  130. $this->dao = $app->dao;
  131. $this->cache = $app->cache;
  132. $this->reset();
  133. }
  134. /**
  135. * 设置$table属性。
  136. * Set the $table property.
  137. *
  138. * @param string $table
  139. * @access public
  140. * @return void
  141. */
  142. public function setTable($table)
  143. {
  144. $this->table = $table;
  145. }
  146. /**
  147. * 设置$fields属性。
  148. * Set the $fields property.
  149. *
  150. * @param array $fields
  151. * @access public
  152. * @return void
  153. */
  154. public function setFields($fields)
  155. {
  156. $this->fields = $fields;
  157. }
  158. /**
  159. * 设置条件。
  160. * Set the $conditions property.
  161. *
  162. * @param array $conditions
  163. * @access public
  164. * @return void
  165. */
  166. public function setConditions($conditions)
  167. {
  168. $this->conditions = $conditions;
  169. $this->resetCondition();
  170. }
  171. /**
  172. * 重置组装条件。
  173. * Reset the $condition property.
  174. *
  175. * @access public
  176. * @return void
  177. */
  178. public function resetCondition()
  179. {
  180. $this->condition = array('field' => '', 'operator' => '', 'value' => null);
  181. }
  182. /**
  183. * 添加条件。
  184. * Add the $conditions property.
  185. *
  186. * @param string $condition
  187. * @access public
  188. * @return void
  189. */
  190. public function addCondition()
  191. {
  192. $this->conditions[] = $this->condition;
  193. }
  194. /**
  195. * 重置属性。
  196. * Reset the vars.
  197. *
  198. * @access public
  199. * @return void
  200. */
  201. public function reset()
  202. {
  203. $this->setFields(array());
  204. $this->setTable('');
  205. $this->setConditions([]);
  206. }
  207. /**
  208. * select方法,调用sql::select()。
  209. * The select method, call sql::select().
  210. *
  211. * @param string $fields
  212. * @access public
  213. * @return static|sql|baseDAO the dao object self.
  214. */
  215. public function select($fields = '*')
  216. {
  217. $this->conditions = [];
  218. $fields = explode(',', $fields);
  219. $alias = [];
  220. foreach($fields as $field)
  221. {
  222. $fieldInfo = explode(' ', trim($field));
  223. if(count($fieldInfo) == 1)
  224. {
  225. $alias[$fieldInfo[0]] = $fieldInfo[0];
  226. }
  227. elseif(count($fieldInfo) == 2)
  228. {
  229. $alias[$fieldInfo[0]] = $fieldInfo[1];
  230. }
  231. else
  232. {
  233. $alias[$fieldInfo[0]] = $fieldInfo[2];
  234. }
  235. }
  236. $this->setFields($alias);
  237. return $this;
  238. }
  239. /**
  240. * 设置要操作的表。
  241. * Set the from table.
  242. *
  243. * @param string $tableName
  244. * @access public
  245. * @return static|sql the dao object self.
  246. */
  247. public function from($tableName)
  248. {
  249. $this->setTable($tableName);
  250. return $this;
  251. }
  252. /**
  253. * 开始条件判断。
  254. * Begin condition judge.
  255. *
  256. * @param bool|string $condition
  257. * @access public
  258. * @return static|sql the sql object.
  259. * @param bool|string $conditionResult
  260. */
  261. public function beginIF($conditionResult)
  262. {
  263. $this->isConditionChecking = true;
  264. $this->conditionIsTrue = (bool)$conditionResult;
  265. return $this;
  266. }
  267. /**
  268. * 结束条件判断。
  269. * End the condition judge.
  270. *
  271. * @access public
  272. * @return static|sql the sql object.
  273. */
  274. public function fi()
  275. {
  276. $this->isConditionChecking = false;
  277. if(!$this->conditionIsTrue)
  278. {
  279. $this->resetCondition();
  280. return $this;
  281. }
  282. $this->addCondition();
  283. $this->resetCondition();
  284. return $this;
  285. }
  286. /**
  287. * 创建WHERE部分。
  288. * Create the where part.
  289. *
  290. * @param string $field the field name
  291. * @access public
  292. * @return static the dao object.
  293. */
  294. public function where($field)
  295. {
  296. $this->resetCondition();
  297. $this->condition['field'] = trim($field, '`');
  298. return $this;
  299. }
  300. /**
  301. * 创建andWHERE部分。
  302. * Create the andWhere part.
  303. *
  304. * @param string $field the field name
  305. * @access public
  306. * @return static the dao object.
  307. */
  308. public function andWhere($field)
  309. {
  310. $this->resetCondition();
  311. $this->condition['field'] = trim($field, '`');
  312. return $this;
  313. }
  314. /**
  315. * 创建eq部分。
  316. * Create the eq part.
  317. *
  318. * @param string $value
  319. * @access public
  320. * @return static the dao object.
  321. */
  322. public function eq($value)
  323. {
  324. $this->condition['operator'] = 'eq';
  325. $this->condition['value'] = $value;
  326. if(!$this->isConditionChecking)
  327. {
  328. $this->addCondition();
  329. $this->resetCondition();
  330. }
  331. return $this;
  332. }
  333. /**
  334. * 创建ne部分。
  335. * Create the ne part.
  336. *
  337. * @param string $value
  338. * @access public
  339. * @return static the dao object.
  340. */
  341. public function ne($value)
  342. {
  343. $this->condition['operator'] = 'ne';
  344. $this->condition['value'] = $value;
  345. if(!$this->isConditionChecking)
  346. {
  347. $this->addCondition();
  348. $this->resetCondition();
  349. }
  350. return $this;
  351. }
  352. /**
  353. * 创建in部分。
  354. * Create the in part.
  355. *
  356. * @param string|array $value
  357. * @access public
  358. * @return static the dao object.
  359. */
  360. public function in($value)
  361. {
  362. $this->condition['operator'] = 'in';
  363. $this->condition['value'] = is_string($value) ? explode(',', str_replace(' ', '', $value)) : $value;
  364. if(!$this->isConditionChecking)
  365. {
  366. $this->addCondition();
  367. $this->resetCondition();
  368. }
  369. return $this;
  370. }
  371. /**
  372. * 创建notin部分。
  373. * Create the in part.
  374. *
  375. * @param string|array $value
  376. * @access public
  377. * @return static the dao object.
  378. */
  379. public function notin($value)
  380. {
  381. $this->condition['operator'] = 'notin';
  382. $this->condition['value'] = is_string($value) ? explode(',', str_replace(' ', '', $value)) : $value;
  383. if(!$this->isConditionChecking)
  384. {
  385. $this->addCondition();
  386. $this->resetCondition();
  387. }
  388. return $this;
  389. }
  390. /**
  391. * 判断匹配条件。
  392. * Check condition is matched.
  393. *
  394. * @param object $object
  395. * @param array $conditions
  396. * @access public
  397. * @return bool
  398. */
  399. private function isConditionMatched($object, $conditions)
  400. {
  401. foreach($conditions as $condition)
  402. {
  403. $value = $object->{$condition['field']};
  404. if($condition['operator'] == 'eq')
  405. {
  406. if($condition['value'] != $value) return false;
  407. }
  408. elseif($condition['operator'] == 'ne')
  409. {
  410. if($condition['value'] == $value) return false;
  411. }
  412. elseif($condition['operator'] == 'in')
  413. {
  414. if(!in_array($value, $condition['value'])) return false;
  415. }
  416. elseif($condition['operator'] == 'notin')
  417. {
  418. if(in_array($value, $condition['value'])) return false;
  419. }
  420. else
  421. {
  422. return false;
  423. }
  424. }
  425. return true;
  426. }
  427. /**
  428. * 获取一个记录。
  429. * Fetch one record.
  430. *
  431. * @param string $keyField 如果已经设置获取的字段,则只返回这个字段的值,否则返回这个记录。
  432. * if the field is set, only return the value of this field, else return this record
  433. * @access public
  434. * @return object|mixed
  435. */
  436. public function fetch($keyField = '')
  437. {
  438. if(empty($this->cache) || empty($this->config->cache->raw[$this->table]) || empty($this->conditions)) return $this->fetchFromDB('fetch', $keyField);
  439. $rawResult = null;
  440. /* 如果查询条件中有主键字段,则尝试通过主键字段从缓存中获取数据。If the query condition contains the primary key field, try to get data from the cache by the primary key field. */
  441. $field = $this->config->cache->raw[$this->table];
  442. foreach($this->conditions as $condition)
  443. {
  444. if($condition['field'] == $field && $condition['operator'] == 'eq')
  445. {
  446. $rawResult = $this->cache->fetch($this->table, $condition['value']);
  447. if($rawResult)
  448. {
  449. $keyField = trim($keyField, '`');
  450. return $keyField ? $rawResult->$keyField : $rawResult;
  451. }
  452. break;
  453. }
  454. }
  455. return $this->fetchFromDB('fetch', $keyField);
  456. }
  457. /**
  458. * 获取所有记录。
  459. * Fetch all records.
  460. *
  461. * @param string $keyField 返回以该字段做键的记录
  462. * the key field, thus the return records is keyed by this field
  463. * @access public
  464. * @return array the records
  465. */
  466. public function fetchAll($keyField = '')
  467. {
  468. if(empty($this->cache) || empty($this->config->cache->raw[$this->table]) || empty($this->conditions)) return $this->fetchFromDB('fetchAll', $keyField, false);
  469. $rawResult = null;
  470. /* 如果查询条件匹配到主键字段,则通过主键字段从缓存中获取数据。If the query condition matches the primary key field, get data from the cache by the primary key field. */
  471. $field = $this->config->cache->raw[$this->table];
  472. foreach($this->conditions as $condition)
  473. {
  474. if($condition['field'] == $field && $condition['operator'] == 'in')
  475. {
  476. $value = $condition['value'];
  477. if(is_numeric($value)) $value = [$value];
  478. if(is_string($value)) $value = explode(',', str_replace(' ', '', $value));
  479. if(is_array($value))
  480. {
  481. $rawResult = $this->cache->fetchAll($this->table, array_filter($value));
  482. foreach($rawResult as $index => $row)
  483. {
  484. /* 根据主键字段获取数据后,需要逐一匹配查询条件。After getting the data according to the primary key field, you need to match the query conditions one by one. */
  485. if(!$this->isConditionMatched($row, $this->conditions)) unset($rawResult[$index]);
  486. }
  487. break;
  488. }
  489. }
  490. }
  491. /* 如果查询条件没有匹配到主键字段,则从计算结果缓存中获取数据。If the query condition does not match the primary key field, get data from the calculated result cache. */
  492. //if(is_null($rawResult)) $rawResult = $this->cache->fetchAutoCache($this->table, $this->conditions);
  493. /* 如果没有缓存,从数据库中获取数据。If there is no cache, get data from the database. */
  494. if(is_null($rawResult)) return $this->fetchFromDB('fetchAll', $keyField, false);
  495. if(!$rawResult) return [];
  496. /* 从缓存中获取到的是原始数据,需要根据查询字段和索引字段进行处理。The data obtained from the cache is raw data, which needs to be processed according to the query fields and index fields. */
  497. $result = [];
  498. foreach($rawResult as $row)
  499. {
  500. $data = new stdclass();
  501. foreach($this->fields as $field => $alias)
  502. {
  503. if($field == '*')
  504. {
  505. $data = $row;
  506. break;
  507. }
  508. $data->$alias = $row->$field;
  509. }
  510. empty($keyField) ? $result[] = $data : $result[$row->$keyField] = $data;
  511. }
  512. return $result;
  513. }
  514. /**
  515. * 获取的记录是以关联数组的形式
  516. * Fetch array like key=>value.
  517. *
  518. * 如果没有设置参数,用首末两键作为参数。
  519. * If the keyFiled and valueField not set, use the first and last in the record.
  520. *
  521. * @param string $keyField
  522. * @param string $valueField
  523. * @access public
  524. * @return array
  525. */
  526. public function fetchPairs($keyField = '', $valueField = '')
  527. {
  528. if(empty($this->cache) || empty($this->config->cache->raw[$this->table])) return $this->fetchFromDB('fetchPairs', $keyField, $valueField);
  529. $rows = $this->fetchAll();
  530. if(empty($rows)) return [];
  531. if(empty($keyField)) $keyField = $this->fields[0];
  532. if(empty($valueField)) $valueField = $this->fields[1];
  533. $pairs = [];
  534. foreach($rows as $row)
  535. {
  536. $pairs[$row->$keyField] = $row->$valueField;
  537. }
  538. return $pairs;
  539. }
  540. /**
  541. * 从数据库中获取数据。
  542. * Fetch data from database.
  543. *
  544. * @param string $fetchFunc fetch|fetchAll
  545. * @param string $keyField
  546. * @param string|bool $valueField
  547. * @access private
  548. * @return mixed
  549. */
  550. private function fetchFromDB($fetchFunc, $keyField, $valueField = '')
  551. {
  552. $fields = implode(',', $this->fields);
  553. $this->dao->select($fields)->from($this->table)->where('1=1');
  554. foreach($this->conditions as $condition)
  555. {
  556. $func = $condition['operator'];
  557. $this->dao->andWhere($condition['field'])->$func($condition['value']);
  558. }
  559. return $this->dao->$fetchFunc($keyField, $valueField);
  560. }
  561. /**
  562. * 把名为 findByXXX 的方法转换为 where 条件。
  563. * Convert the method findByXXX to where condition.
  564. *
  565. * @param string $method
  566. * @param array $args
  567. * @access private
  568. * @return object the mao object.
  569. */
  570. private function findBy($method, $args)
  571. {
  572. $field = str_replace('findby', '', $method);
  573. if(count($args) == 1)
  574. {
  575. $operator = 'eq';
  576. $value = $args[0];
  577. }
  578. else
  579. {
  580. $operator = $args[0];
  581. $value = $args[1];
  582. }
  583. $this->setFields(['*']);
  584. $this->conditions = [['field' => $field, 'operator' => $operator, 'value' => $value]];
  585. return $this;
  586. }
  587. /**
  588. * 获取缓存数据拼接到已有数据。
  589. * Append cache fields to data.
  590. *
  591. * @param array $data
  592. * @param string $keyField
  593. * @access public
  594. * @return void
  595. */
  596. public function into($data, $keyField)
  597. {
  598. if(empty($data) || empty($keyField)) return $data;
  599. /* Get data keys as conditions. */
  600. $keyList = [];
  601. foreach($data as $index => $row) $keyList[$index] = $row->$keyField;
  602. if(empty($this->cache))
  603. {
  604. /* 如果缓存关闭,从数据库中获取。If the cache is off, get from the database. */
  605. $primaryKey = $this->config->cache->raw[$this->table];
  606. $fields = $primaryKey . ',' . implode(',', array_keys($this->fields));
  607. $cacheResult = $this->dao->select($fields)->from($this->table)->where($primaryKey)->in(array_unique($keyList))->fetchAll($primaryKey);
  608. }
  609. else
  610. {
  611. $cacheResult = $this->cache->fetchAll($this->table, array_unique($keyList));
  612. }
  613. foreach($data as $index => $row)
  614. {
  615. $key = $keyList[$index];
  616. if(isset($cacheResult[$key]))
  617. {
  618. $cacheRow = $cacheResult[$key];
  619. foreach($this->fields as $field => $alias) $row->$alias = $cacheRow->$field;
  620. }
  621. else
  622. {
  623. foreach($this->fields as $field => $alias) $row->$alias = '';
  624. }
  625. }
  626. }
  627. /**
  628. * 清除缓存。
  629. * Clear cache.
  630. *
  631. * @access public
  632. * @return void
  633. */
  634. public function clearCache()
  635. {
  636. if(!empty($this->cache)) $this->cache->clear();
  637. }
  638. /**
  639. * 根据当前缓存键获取缓存。
  640. * Get cache according to the current cache key.
  641. *
  642. * @access public
  643. * @return mixed
  644. */
  645. public function get()
  646. {
  647. if(empty($this->cache)) return false;
  648. return $this->cache->get();
  649. }
  650. /**
  651. * 魔术方法。
  652. * 1. 转换 findByxxx 为 where 条件。
  653. * 2. 调用cache对象的方法。
  654. * Magic method.
  655. * 1. Convert findByxxx to where condition.
  656. * 2. Call the cache object method.
  657. *
  658. * @param string $method
  659. * @param array $args
  660. * @access public
  661. * @return mixed
  662. */
  663. public function __call($method, $args)
  664. {
  665. $method = strtolower($method);
  666. /*
  667. * 如果是findByxxx,转换为where条件语句。
  668. * findByxxx, xxx as will be in the where.
  669. **/
  670. if(strpos($method, 'findby') !== false) return $this->findBy($method, $args);
  671. if(empty($this->cache)) return $this;
  672. if(method_exists($this->cache, $method)) return call_user_func_array([$this->cache, $method], $args);
  673. $this->app->triggerError("Method $method not found in class baseMao.", __FILE__, __LINE__, $this->config->debug >= 2);
  674. }
  675. }