Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

894 linhas
24 KiB

  1. <?php
  2. namespace Kuxin;
  3. use Kuxin\Helper\Json;
  4. /**
  5. * Class Model
  6. *
  7. * @package Kuxin
  8. * @author Pakey <pakey@qq.com>
  9. */
  10. class Model
  11. {
  12. /**
  13. * 数据库节点信息
  14. *
  15. * @var string
  16. */
  17. protected $connection = 'common';
  18. /**
  19. * 数据表名
  20. *
  21. * @var string
  22. */
  23. protected $table = null;
  24. /**
  25. * 数据表的主键信息
  26. *
  27. * @var string
  28. */
  29. protected $pk = 'id';
  30. /**
  31. * model所对应的数据表名的前缀
  32. *
  33. * @var string
  34. */
  35. protected $prefix = '';
  36. /**
  37. * SQL语句容器,用于存放SQL语句,为SQL语句组装函数提供SQL语句片段的存放空间。
  38. *
  39. * @var array
  40. */
  41. protected $data = [];
  42. /**
  43. * SQL语句容器,用于存放SQL语句,为SQL语句组装函数提供SQL语句片段的存放空间。
  44. *
  45. * @var array
  46. */
  47. protected $bindParams = [];
  48. /**
  49. * 错误信息
  50. *
  51. * @var string
  52. */
  53. protected $errorinfo = null;
  54. /**
  55. * @var \Kuxin\Db\Mysql
  56. */
  57. protected $db = null;
  58. /**
  59. * Model constructor.
  60. */
  61. public function __construct()
  62. {
  63. $this->prefix = Config::get('database.prefix');
  64. }
  65. /**
  66. * 实例化 单例
  67. *
  68. * @param ...
  69. * @return static
  70. */
  71. public static function I()
  72. {
  73. return Loader::instance(static::class, func_get_args());
  74. }
  75. /**
  76. * @return \Kuxin\Db\Mysql
  77. */
  78. public function db(): \Kuxin\Db\Mysql
  79. {
  80. if (!$this->db) {
  81. $this->db = DI::DB($this->connection);
  82. }
  83. return $this->db;
  84. }
  85. public function __call($method, $args)
  86. {
  87. trigger_error('不具备的Model操作' . $method);
  88. }
  89. /**
  90. * 求和
  91. * @param string $value
  92. * @return string
  93. */
  94. public function sum(string $value): string
  95. {
  96. $this->data['field'] = "sum({$value}) as kx_num";
  97. return $this->getField('kx_num') ?: 0;
  98. }
  99. /**
  100. * 平均数
  101. * @param string $value
  102. * @return string
  103. */
  104. public function avg(string $value): string
  105. {
  106. $this->data['field'] = "avg({$value}) as kx_num";
  107. return $this->getField('kx_num');
  108. }
  109. /**
  110. * @param string $value
  111. * @return string
  112. */
  113. public function min(string $value): string
  114. {
  115. $this->data['field'] = "min({$value}) as kx_num";
  116. return $this->getField('kx_num');
  117. }
  118. /**
  119. * @param string $value
  120. * @return string
  121. */
  122. public function max(string $value)
  123. {
  124. $this->data['field'] = "max({$value}) as kx_num";
  125. return (int)$this->getField('kx_num');
  126. }
  127. /**
  128. * @param string $value
  129. * @return int
  130. */
  131. public function count(string $value = '*'): int
  132. {
  133. $this->data['field'] = "count({$value}) as kx_num";
  134. return (int)$this->getField('kx_num');
  135. }
  136. /**
  137. * @param $data
  138. * @param array $option
  139. * @return $this
  140. */
  141. public function where($data, array $option = [])
  142. {
  143. if (is_string($data)) {
  144. $this->data['where'][] = ['_string' => $data];
  145. $this->bindParams = array_merge($this->bindParams, $option);
  146. } elseif (is_array($data)) {
  147. foreach ($data as $field => $var) {
  148. //where条件
  149. $this->data['where'][] = [$field => $var];
  150. }
  151. }
  152. return $this;
  153. }
  154. /**
  155. * @param $value
  156. * @return $this
  157. */
  158. public function database(string $value)
  159. {
  160. $this->data['database'] = $value;
  161. return $this;
  162. }
  163. /**
  164. * @param $value
  165. * @return $this
  166. */
  167. public function config(string $value)
  168. {
  169. $this->data['config'] = $value;
  170. return $this;
  171. }
  172. public function distinct(string $value)
  173. {
  174. $this->data['distinct'] = $value;
  175. return $this;
  176. }
  177. public function table(string $value)
  178. {
  179. $this->data['table'] = $value;
  180. return $this;
  181. }
  182. public function having(string $value)
  183. {
  184. if (is_string($value)) {
  185. $this->data['having'][] = ['_string' => $value];
  186. } else {
  187. $this->data['having'] = $value;
  188. }
  189. return $this;
  190. }
  191. public function group($value)
  192. {
  193. $this->data['group'] = $value;
  194. return $this;
  195. }
  196. public function page($value)
  197. {
  198. $this->data['page'] = $value;
  199. return $this;
  200. }
  201. public function limit($value)
  202. {
  203. $this->data['limit'] = $value;
  204. return $this;
  205. }
  206. public function index($value)
  207. {
  208. $this->data['index'] = $value;
  209. return $this;
  210. }
  211. public function order($value)
  212. {
  213. $this->data['order'] = $value;
  214. return $this;
  215. }
  216. public function field($value)
  217. {
  218. $this->data['field'] = $value;
  219. return $this;
  220. }
  221. public function join(string $table, string $on = '', string $type = 'left')
  222. {
  223. if (is_array($table)) {
  224. $this->data['join'][] = $table;
  225. } else {
  226. $this->data['join'][] = ['table' => $table, 'on' => $on, 'type' => $type];
  227. }
  228. return $this;
  229. }
  230. public function getTableName()
  231. {
  232. if (!$this->table) {
  233. trigger_error('请设置表名', E_USER_ERROR);
  234. }
  235. return $this->prefix . $this->table;
  236. }
  237. public function getTableField(string $tablename)
  238. {
  239. if (!($tablename = trim($tablename, ' '))) {
  240. trigger_error('您必须设置表名后才可以使用该方法');
  241. }
  242. if (($offset = stripos($tablename, ' as ')) !== false) {
  243. $tablename = substr($tablename, 0, $offset);
  244. } elseif (($offset = stripos($tablename, ' ')) !== false) {
  245. $tablename = substr($tablename, 0, $offset);
  246. }
  247. return Registry::get('tablefield_' . $tablename, function () use ($tablename) {
  248. $fields = DI::Cache()->debugGet('tablefield_' . $tablename, function () use ($tablename) {
  249. $fields = [];
  250. if ($tableInfo = $this->db()->fetchAll("SHOW FIELDS FROM {$tablename}")) {
  251. foreach ($tableInfo as $v) {
  252. if ($v['Key'] == 'PRI')
  253. $pks[] = strtolower($v['Field']);
  254. $fields[strtolower($v['Field'])] = strpos($v['Type'], 'int') !== false;
  255. }
  256. DI::Cache()->set('tablefield_' . $tablename, $fields);
  257. return $fields;
  258. } else {
  259. trigger_error('获取表' . $tablename . '信息发生错误 ', E_USER_ERROR);
  260. return false;
  261. }
  262. });
  263. Registry::set('tablefield_' . $tablename, $fields);
  264. return $fields;
  265. });
  266. }
  267. public function getPk(): string
  268. {
  269. return $this->pk;
  270. }
  271. /**
  272. * @param array $data
  273. * @param bool $replace
  274. * @return mixed
  275. */
  276. public function insert(array $data, bool $replace = false)
  277. {
  278. if ($data) {
  279. $insertData = [];
  280. $tablename = $this->parseTable();
  281. $fields = $this->getTableField($tablename);
  282. foreach ($data as $k => $v) { // 过滤参数
  283. if (isset($fields[$k])) {
  284. //写入数据
  285. $insertData[$this->parseKey($k)] = ':' . $k;
  286. //参数绑定
  287. $this->bindParams[':' . $k] = $this->parseBindValue($v);
  288. }
  289. }
  290. $sql = ($replace ? 'REPLACE' : 'INSERT') . ' INTO ' . $tablename . ' (' . implode(',', array_keys($insertData)) . ') VALUES (' . implode(',', $insertData) . ');';
  291. $result = $this->db()->execute($sql, $this->bindParams);
  292. $this->free();
  293. if (true === $result) {
  294. return $this->db()->lastInsertId();
  295. } else {
  296. return false;
  297. }
  298. } else {
  299. trigger_error('你的数据呢?', E_USER_WARNING);
  300. return false;
  301. }
  302. }
  303. /**
  304. * 插入记录
  305. *
  306. * @access public
  307. * @param mixed $datas 数据
  308. * @param boolean $replace 是否replace
  309. * @return false | integer
  310. */
  311. public function insertAll(array $datas, bool $replace = false)
  312. {
  313. if ($datas) {
  314. $values = [];
  315. $tablename = $this->parseTable();
  316. $fields = $this->getTableField($tablename);
  317. foreach ($datas as $data) {
  318. $value = [];
  319. foreach ($data as $key => $val) {
  320. if (isset($fields[$key])) {
  321. $value[$key] = $this->parseValue($val);
  322. }
  323. }
  324. $values[] = '(' . implode(',', $value) . ')';
  325. }
  326. $fields = array_map([$this, 'parseKey'], array_keys($datas[0]));
  327. $sql = ($replace ? 'REPLACE' : 'INSERT') . ' INTO ' . $this->parseTable() . ' (' . implode(',', $fields) . ') VALUES ' . implode(',', $values);
  328. $result = $this->db()->execute($sql);
  329. $this->free();
  330. if (true === $result) {
  331. return intval($this->db()->lastInsertId()) + count($datas) - 1;
  332. } else {
  333. return false;
  334. }
  335. } else {
  336. trigger_error('你的数据呢?', E_USER_WARNING);
  337. return false;
  338. }
  339. }
  340. /**
  341. * @param array $data
  342. * @return bool|int
  343. */
  344. public function update(array $data)
  345. {
  346. if ($data) {
  347. $sets = [];
  348. $tablename = $this->parseTable();
  349. $fields = $this->getTableField($tablename);
  350. if (isset($data[$this->pk])) {
  351. $this->where([$this->pk => $data[$this->pk]]);
  352. unset($data[$this->pk]);
  353. }
  354. foreach ($data as $k => $v) { // 数据解析
  355. if (isset($fields[$k])) {
  356. if (is_array($v) && isset($v[0]) && is_string($v[0]) && strtolower($v[0]) == 'exp') {
  357. $sets[] = $this->parseKey($k) . '= ' . $v['1'];
  358. } else {
  359. $sets[] = $this->parseKey($k) . '= :' . $k;
  360. //参数绑定
  361. $this->bindParams[':' . $k] = $this->parseBindValue($v);
  362. }
  363. }
  364. }
  365. $sql = 'UPDATE ' . $this->parseTable() . ' SET ' . implode(',', $sets)
  366. . $this->parseWhere()
  367. . $this->parseOrder()
  368. . $this->parseLimit();
  369. $result = $this->db()->execute($sql, $this->bindParams);
  370. $this->free();
  371. if (true === $result) {
  372. return $this->db()->rowCount();
  373. } else {
  374. return false;
  375. }
  376. } else {
  377. trigger_error('你的数据呢?', E_USER_WARNING);
  378. return false;
  379. }
  380. }
  381. public function delete()
  382. {
  383. if (empty($this->data['where'])) {
  384. trigger_error('删除语句必须制定where条件');
  385. }
  386. $sql = 'DELETE' . ' FROM ' . $this->parseTable()
  387. . $this->parseWhere()
  388. . $this->parseOrder()
  389. . $this->parseLimit();
  390. $this->data = [];
  391. $result = $this->db()->execute($sql, $this->bindParams);
  392. $this->free();
  393. if (true === $result) {
  394. return $this->db()->rowCount();
  395. } else {
  396. return false;
  397. }
  398. }
  399. public function find($id = null)
  400. {
  401. if ($id) {
  402. $this->data['where'][] = [$this->pk => $id];
  403. }
  404. $this->data['limit'] = 1;
  405. $sql = "SELECT " . $this->parseField() . ' FROM '
  406. . $this->parseTable()
  407. . $this->parseIndex()
  408. . $this->parseJoin()
  409. . $this->parseWhere()
  410. . $this->parseGroup()
  411. . $this->parseHaving()
  412. . $this->parseOrder()
  413. . $this->parseLimit()
  414. . $this->parseUnion();
  415. //清空存储
  416. $this->data = [];
  417. return $this->fetch($sql, $this->bindParams);
  418. }
  419. /**
  420. * @return array|bool
  421. */
  422. public function select()
  423. {
  424. $sql = "SELECT " . $this->parseField() . ' FROM '
  425. . $this->parseTable()
  426. . $this->parseIndex()
  427. . $this->parseJoin()
  428. . $this->parseWhere()
  429. . $this->parseGroup()
  430. . $this->parseHaving()
  431. . $this->parseOrder()
  432. . $this->parseLimit()
  433. . $this->parseUnion();
  434. $this->data = [];
  435. $this->errorinfo = ''; //清空存储
  436. return $this->fetchAll($sql, $this->bindParams);
  437. }
  438. /**
  439. * 获取具体字段的值
  440. *
  441. * @param $field
  442. * @param bool $multi 是否返回数组
  443. * @return mixed|null|string
  444. */
  445. public function getField($field, $multi = false)
  446. {
  447. if (empty($this->data['field'])) {
  448. $this->data['field'] = $field;
  449. }
  450. if ($multi) {
  451. $result = $this->select();
  452. if ($result === false) {
  453. return false;
  454. } elseif ($result) {
  455. if (strpos($field, ',')) {
  456. $field = explode(',', $field, 2)[0];
  457. return array_column($result, null, $field);
  458. } else {
  459. return array_column($result, $field);
  460. }
  461. } else {
  462. return [];
  463. }
  464. } else {
  465. $result = $this->find();
  466. if ($result === false) {
  467. return false;
  468. } elseif (isset($result[$field])) {
  469. return $result[$field];
  470. } else {
  471. return null;
  472. }
  473. }
  474. }
  475. /**
  476. * 设置某个字段的值
  477. *
  478. * @param $field
  479. * @param $data
  480. * @return bool|int
  481. */
  482. public function setField(string $field, $data)
  483. {
  484. return $this->update([$field => $data]);
  485. }
  486. /**
  487. * 增加数据库中某个字段值
  488. *
  489. * @param $field
  490. * @param int $step
  491. * @return bool|int
  492. */
  493. public function setInc(string $field, int $step = 1)
  494. {
  495. return $this->setField($field, ['exp', "`{$field}` + {$step}"]);
  496. }
  497. /**
  498. * 减少数据库中某个字段值
  499. *
  500. * @param $field
  501. * @param int $step
  502. * @return bool|int
  503. */
  504. public function setDec(string $field, int $step = 1)
  505. {
  506. return $this->setField($field, ['exp', "`{$field}` - {$step}"]);
  507. }
  508. public function getLastSql(): string
  509. {
  510. return $this->db()->lastSql();
  511. }
  512. public function getError()
  513. {
  514. return $this->db()->errorInfo();
  515. }
  516. public function startTrans()
  517. {
  518. $this->db()->startTrans();
  519. }
  520. public function commit()
  521. {
  522. $this->db()->commit();
  523. }
  524. public function rollback()
  525. {
  526. $this->db()->rollback();
  527. }
  528. public function fetch(string $sql, array $bindParams = [])
  529. {
  530. $result = $this->db()->fetch($sql, $bindParams);
  531. $this->free();
  532. return $result;
  533. }
  534. public function fetchAll(string $sql, array $bindParams = [])
  535. {
  536. $result = $this->db()->fetchAll($sql, $bindParams);
  537. $this->free();
  538. return $result;
  539. }
  540. public function execute(string $sql, array $bindParams = [])
  541. {
  542. $result = $this->db()->execute($sql, $bindParams);
  543. $this->free();
  544. return $result;
  545. }
  546. public function parseCount(string $method)
  547. {
  548. $this->data['field'] = "{$method}({$this->data['field']}) as kx_num";
  549. return $this->getField('kx_num');
  550. }
  551. /**
  552. * 字段和表名处理添加`
  553. *
  554. * @access protected
  555. * @param string $key
  556. * @return string
  557. */
  558. protected function parseKey(string $key): string
  559. {
  560. $key = trim($key);
  561. if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
  562. $key = '`' . $key . '`';
  563. }
  564. return $key;
  565. }
  566. /**
  567. * value分析
  568. *
  569. * @access protected
  570. * @param mixed $value
  571. * @return mixed
  572. */
  573. protected function parseBindValue($value)
  574. {
  575. if (is_array($value)) {
  576. $value = Json::encode($value);
  577. } elseif (is_bool($value)) {
  578. $value = $value ? 1 : 0;
  579. } elseif (is_null($value)) {
  580. $value = null;
  581. }
  582. return $value;
  583. }
  584. /**
  585. * value分析
  586. *
  587. * @access protected
  588. * @param mixed $value
  589. * @return string
  590. */
  591. protected function parseValue($value)
  592. {
  593. if (is_string($value)) {
  594. $value = $this->db()->quote($value);
  595. }
  596. if (isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp') {
  597. $value = $value[1];
  598. } elseif (is_array($value)) {
  599. $value = $this->db()->quote(Json::encode($value));
  600. } elseif (is_bool($value)) {
  601. $value = $value ? '1' : '0';
  602. } elseif (is_null($value)) {
  603. $value = 'null';
  604. }
  605. return $value;
  606. }
  607. protected function parseWhere()
  608. {
  609. if (empty($this->data['where'])) {
  610. return ' WHERE 1';
  611. } else {
  612. return ' WHERE ' . $this->parseWhereCondition($this->data['where']);
  613. }
  614. }
  615. protected function parseWhereCondition(array $condition, $logic = 'AND')
  616. {
  617. $wheres = [];
  618. $tablename = $this->parseTable();
  619. $fields = $this->getTableField($tablename);
  620. foreach ($condition as $var) {
  621. $k = key($var);
  622. if (($offset = strpos($k, '.')) !== false) {
  623. $k = substr($k, $offset + 1);
  624. }
  625. $v = current($var);
  626. if (isset($fields[$k])) {
  627. if (empty($this->data['join'])) {
  628. $wheres[] = '(' . $this->parseWhereItem($k, $v) . ')';
  629. } else {
  630. $wheres[] = '(' . $this->parseWhereItem($this->parseKey($tablename) . '.' . $k, $v) . ')';
  631. }
  632. } elseif (is_array($v) && in_array(strtolower($k), ['or', 'and', 'xor'])) {
  633. $where[] = $this->parseWhereCondition($v, $k);
  634. } elseif ($k == '_logic' && in_array(strtolower($v), ['or', 'and', 'xor'])) {
  635. $logic = ' ' . strtoupper($v) . ' ';
  636. } elseif ($k == '_string') {
  637. $wheres[] = '(' . $v . ')';
  638. }
  639. }
  640. return ($wheres === []) ? 1 : implode(" {$logic} ", $wheres);
  641. }
  642. /**
  643. * @param $field
  644. * @param $var
  645. * @return mixed
  646. */
  647. protected function parseWhereItem(string $field, $var)
  648. {
  649. //参数绑定key
  650. $bindkey = ':' . $field . '_' . count($this->bindParams);
  651. $field = $this->parseKey($field);
  652. if (is_array($var)) {
  653. switch (strtolower($var['0'])) {
  654. case '>':
  655. case '<':
  656. case '>=':
  657. case '<=':
  658. case '=':
  659. case '<>':
  660. case 'like':
  661. case 'not like':
  662. //参数绑定存储
  663. $this->bindParams[$bindkey] = $this->parseBindValue($var['1']);
  664. return $field . ' ' . $var['0'] . ' ' . $bindkey;
  665. case 'in':
  666. case 'not in':
  667. if (empty($var['1']))
  668. return '1';
  669. if (is_array($var['1'])) {
  670. $inBindVar = [];
  671. foreach ($var['1'] as $num => $inval) {
  672. $inBindKey = $bindkey . '_' . $num;
  673. $inBindVar[] = $inBindKey;
  674. //
  675. $this->bindParams[$inBindKey] = $this->parseBindValue($inval);
  676. }
  677. $var['1'] = implode(',', $inBindVar);
  678. }
  679. return "{$field} {$var['0']} ( {$var['1']} )";
  680. case 'between':
  681. case 'not between':
  682. if (is_string($var['1'])) {
  683. $var['1'] = explode(',', $var['1']);
  684. }
  685. $this->bindParams[$bindkey . '_0'] = $this->parseBindValue($var['1']['0']);
  686. $this->bindParams[$bindkey . '_1'] = $this->parseBindValue($var['1']['1']);
  687. return "{$field} {$var['0']} {$bindkey}_0 and {$bindkey}_1";
  688. case 'exp':
  689. return "{$var['1']}";
  690. default:
  691. return '1';
  692. }
  693. } else {
  694. //参数绑定存储
  695. $this->bindParams[$bindkey] = $this->parseBindValue($var);
  696. return $field . ' = ' . $bindkey;
  697. }
  698. }
  699. protected function parseOrder()
  700. {
  701. if (!empty($this->data['order'])) {
  702. if (is_string($this->data['order'])) {
  703. return ' ORDER BY ' . $this->data['order'];
  704. }
  705. }
  706. return '';
  707. }
  708. protected function parseGroup()
  709. {
  710. if (!empty($this->data['group'])) {
  711. if (is_string($this->data['group'])) {
  712. return ' GROUP BY ' . $this->parseKey($this->data['group']);
  713. } elseif (is_array($this->data['group'])) {
  714. $this->data['group'] = array_map($this->data['group'], [$this, 'parseKey']);
  715. return ' GROUP BY ' . implode(',', $this->data['group']);
  716. }
  717. }
  718. return '';
  719. }
  720. protected function parseHaving()
  721. {
  722. if (empty($this->data['having'])) {
  723. return '';
  724. }
  725. return ' HAVING ' . $this->parseWhereCondition($this->data['having']);
  726. }
  727. protected function parseLimit()
  728. {
  729. if (isset($this->data['page'])) {
  730. // 根据页数计算limit
  731. if (strpos($this->data['page'], ',')) {
  732. list($page, $listRows) = explode(',', $this->data['page']);
  733. } else {
  734. $page = $this->data['page'];
  735. }
  736. $page = $page ? $page : 1;
  737. $listRows = isset($listRows) ? $listRows : (is_numeric($this->data['limit']) ? $this->data['limit'] : 20);
  738. $offset = $listRows * ((int)$page - 1);
  739. return ' LIMIT ' . $offset . ',' . $listRows;
  740. } elseif (!empty($this->data['limit'])) {
  741. return ' LIMIT ' . $this->data['limit'];
  742. } else {
  743. return '';
  744. }
  745. }
  746. protected function parseUnion()
  747. {
  748. }
  749. protected function parseJoin()
  750. {
  751. if (empty($this->data['join']))
  752. return '';
  753. $str = '';
  754. foreach ($this->data['join'] as $join) {
  755. $table = $join['table'];
  756. $type = $join['type'];
  757. $on = $join['on'];
  758. if (empty($table)) {
  759. return '';
  760. } elseif (strpos($table, $this->prefix) === false) {
  761. $table = $this->prefix . $table;
  762. }
  763. $str .= ' ' . $type . ' JOIN ' . $table . ' ON ' . $on;
  764. }
  765. return $str;
  766. }
  767. protected function parseField()
  768. {
  769. if (empty($this->data['field'])) {
  770. return '*';
  771. } else {
  772. if (is_string($this->data['field'])) {
  773. $this->data['field'] = explode(',', $this->data['field']);
  774. }
  775. $this->data['field'] = array_map([self::class, 'parseKey'], $this->data['field']);
  776. return implode(',', $this->data['field']);
  777. }
  778. }
  779. protected function parseTable()
  780. {
  781. if (empty($this->data['table'])) {
  782. return $this->getTableName();
  783. } else {
  784. $table = strtolower(strpos($this->data['table'], $this->prefix) === false) ? $this->prefix . $this->data['table'] : $this->data['table'];
  785. }
  786. $table = $this->parseKey($table);
  787. //判断是否带数据库
  788. return ((empty($this->data['database'])) ? $table : $this->parseKey($this->data['db']) . '.' . $table);
  789. }
  790. protected function parseIndex()
  791. {
  792. if (empty($this->data['index'])) {
  793. return '';
  794. } else {
  795. return 'force index (' . $this->data['index'] . ')';
  796. }
  797. }
  798. protected function parseDistinct()
  799. {
  800. return $this->data['distinct'] ? ' DISTINCT ' : '';
  801. }
  802. protected function free()
  803. {
  804. $this->data = [];
  805. $this->bindParams = [];
  806. $this->attribute = [];
  807. }
  808. }