Base.php 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  1. <?php
  2. namespace Qii\Driver\Entity;
  3. use \Qii\Driver\Response;
  4. class Base {
  5. /**
  6. * 字段及值
  7. *
  8. * @var array $properties
  9. */
  10. public static $properties;
  11. public static $config;
  12. /**
  13. * hooker for fields 查询字段/ where 查询条件 / order 排序 / cache 缓存
  14. * @var array $hooker
  15. */
  16. private $hooker = [];
  17. /**
  18. * 默认过期时间
  19. *
  20. * @var int $defaultExpired
  21. */
  22. private $defaultExpired = 600;
  23. public function __construct(){
  24. }
  25. /**
  26. * 默认值,仅在新增数据的时候支持,更新不支持
  27. *
  28. * @return array
  29. */
  30. public function defaultFieldsValue(){
  31. return array();
  32. }
  33. /**
  34. * 返回 table 的名字,以便分库分表的时候指定使用
  35. *
  36. * @return mixed
  37. * @throws \Exception
  38. */
  39. public function getTable() {
  40. throw new \Exception('请先设置需要保存的数据表');
  41. }
  42. /**
  43. * set hooker for method
  44. * 目前 where 和 order 及 fields 支持
  45. * @param $key
  46. * @param $hooker
  47. * @param $args
  48. * @return $this
  49. */
  50. protected function setHooker($key, $hooker, $args) {
  51. $this->hooker[$key]['func'] = $hooker;
  52. $this->hooker[$key]['args'] = $args;
  53. return $this;
  54. }
  55. /**
  56. * 设置where hooker
  57. * @param object $hooker
  58. * @return $this
  59. * @throws \Exception
  60. */
  61. final public function setWhereHooker($hooker, $args = null) {
  62. $this->checkCallable($hooker);
  63. $this->setHooker('where', $hooker, $args);
  64. return $this;
  65. }
  66. /**
  67. * 获取where条件
  68. *
  69. * @return array|mixed
  70. */
  71. public function getWhereHooker() {
  72. $where = $this->properties();
  73. if(isset($this->hooker['where']) && $this->hooker['where'] && is_callable($this->hooker['where']['func'])) {
  74. $where = call_user_func($this->hooker['where']['func'], $this->properties(), $this->hooker['where']['args']);
  75. }
  76. return $where;
  77. }
  78. /**
  79. * 设置order by hooker
  80. * @param object $hooker
  81. * @return $this
  82. * @throws \Exception
  83. */
  84. final public function setOrderHooker($hooker, $args = null) {
  85. $this->checkCallable($hooker);
  86. $this->setHooker('order', $hooker, $args);
  87. return $this;
  88. }
  89. /**
  90. * 设置 limit hooker
  91. *
  92. * @param object $hooker
  93. * @return $this
  94. * @throws \Exception
  95. */
  96. final public function setLimitHooker($hooker, $args = null) {
  97. $this->checkCallable($hooker);
  98. $this->setHooker('limit', $hooker, $args);
  99. return $this;
  100. }
  101. /**
  102. * 获取limit
  103. * @return int|mixed
  104. */
  105. final public function getLimitHooker() {
  106. if(isset($this->hooker['limit']) && $this->hooker['limit'] && is_callable($this->hooker['limit']['func'])) {
  107. return call_user_func($this->hooker['limit']['func'], [], $this->hooker['limit']['args']);
  108. }
  109. return [];
  110. }
  111. /**
  112. * 设置 cache hooker
  113. *
  114. * @param callable $hooker
  115. * @param array| mixed $args
  116. * @return $this
  117. * @throws \Exception
  118. */
  119. final public function setCacheHooker($hooker, $args = null) {
  120. $this->checkCallable($hooker);
  121. $this->setHooker('cache', $hooker, $args);
  122. return $this;
  123. }
  124. /**
  125. * 获取Cache Hooker
  126. * @return mixed|null[]
  127. */
  128. final public function getCacheHooker() {
  129. if(isset($this->hooker['cache']) && $this->hooker['cache'] && is_callable($this->hooker['cache']['func'])) {
  130. return call_user_func($this->hooker['cache']['func'], [], $this->hooker['cache']['args']);
  131. }
  132. return [null, null, null];
  133. }
  134. /**
  135. * 缓存设置
  136. *
  137. * @param array $config 缓存配置
  138. * @return void
  139. */
  140. final public function setCacheConfig($config) {
  141. if(!is_array($config)) {
  142. return;
  143. }
  144. self::$config['cache'] = $config;
  145. }
  146. /**
  147. * 获取缓存的配置信息
  148. *
  149. * @return array
  150. */
  151. final public function getCacheConfig() {
  152. if(is_array(self::$config) && isset(self::$config['cache']) && is_array(self::$config['cache'])) {
  153. return self::$config['cache'];
  154. }
  155. return array();
  156. }
  157. /**
  158. * 如果hooker不可调用即抛出异常
  159. *
  160. * @param object $hooker
  161. * @return void
  162. * @throws \Exception
  163. */
  164. private function checkCallable($hooker) {
  165. if($hooker && !is_callable($hooker)) {
  166. throw new \Exception('Hooker is uncallable');
  167. }
  168. }
  169. /**
  170. * 设置order by hooker
  171. * @param object $hooker
  172. * @return $this
  173. * @throws \Exception
  174. */
  175. final public function setQueryFieldsHooker($hooker, $args = null) {
  176. if(!is_callable($hooker)) {
  177. throw new \Exception('Hooker is un callable');
  178. }
  179. $this->setHooker('fields', $hooker, $args);
  180. return $this;
  181. }
  182. /**
  183. * 通过field hooker返回查询的字段
  184. *
  185. * @return mixed|string
  186. */
  187. final public function getFieldsHooker() {
  188. if(isset($this->hooker['fields']) && $this->hooker['fields'] && is_callable($this->hooker['fields']['func'])) {
  189. return call_user_func($this->hooker['fields']['func'], [], $this->hooker['fields']['args']);
  190. }
  191. return '*';
  192. }
  193. /**
  194. * 获取指定field的值
  195. * @param string $field
  196. * @return mixed
  197. */
  198. final public function getFieldVal($field) {
  199. if(!preg_match('/^[a-zA-Z]/', $field)) {
  200. throw new \Exception('Field is illegal');
  201. }
  202. $property = $this->entity()->convertToProperty($field);
  203. return $this->{$property};
  204. }
  205. /**
  206. * 返回使用的db信息
  207. *
  208. * @return \Qii\Driver\Base
  209. */
  210. final public function db() {
  211. return _loadClass('\Qii\Driver\Model');
  212. }
  213. /**
  214. * 返回 entity 信息
  215. * @return mixed
  216. */
  217. final public function entity() {
  218. return _loadClass('\Qii\Driver\Entity\Entity');
  219. }
  220. /**
  221. * unique (unique 如果是 array 则表示 联合唯一,如果是string则是任意唯一,多个单独唯一使用字符串以逗号隔开, 主键除外)
  222. *
  223. * @return mixed
  224. * @throws \Exception
  225. */
  226. public function uniqueKey(){
  227. throw new \Exception('请设置唯一值');
  228. }
  229. /**
  230. * 主键
  231. *
  232. * @return mixed
  233. * @throws \Exception
  234. */
  235. public function primaryKey(){
  236. throw new \Exception('请设置主键');
  237. }
  238. /**
  239. * 保存数据的时候,验证唯一需要排除的值,此处仅支持,单个或联合排除,不支持单个排除
  240. *
  241. * @return array
  242. */
  243. public function exclude(){
  244. return array();
  245. }
  246. /**
  247. * order by
  248. * @return string[]
  249. */
  250. public function orderBy() {
  251. return array();
  252. }
  253. /**
  254. * explode string
  255. * @param string $separator 分隔符
  256. * @param string $string 分割的字符串
  257. * @param int $limit 是否
  258. * @return array|false|string[]
  259. */
  260. public function explode($separator, $string, $limit = PHP_INT_MAX) {
  261. if($string == '') {
  262. return [];
  263. }
  264. return explode($separator, $string, $limit);
  265. }
  266. /**
  267. * 添加数据验证字段
  268. *
  269. * $fields = [];
  270. * return $this->valid($fields);
  271. *
  272. * @return mixed
  273. * @throws \Exception
  274. */
  275. public function validFieldsForAdd(){
  276. throw new \Exception('请设置插入数据验证的字段,格式如:["Id", "Title"],Id和Title为entity的属性');
  277. }
  278. /**
  279. * 更新数据验证字段
  280. *
  281. * $fields = [];
  282. * return $this->valid($fields);
  283. *
  284. * @return mixed
  285. * @throws \Exception
  286. */
  287. public function validFieldsForUpdate() {
  288. throw new \Exception('请设置更新数据验证的字段,格式如:["Id", "Title"],Id和Title为entity的属性');
  289. }
  290. /**
  291. * 获取不为空的属性
  292. *
  293. * @return array
  294. */
  295. final public function properties() {
  296. $class = get_called_class();
  297. $method = new \ReflectionClass($class);
  298. $properties = $method->getproperties();
  299. $fields = [];
  300. foreach($properties as $property) {
  301. if($property->isPublic()) {
  302. $name = $property->getName();
  303. if(!isset($this->$name)) {
  304. continue;
  305. }
  306. $field = $this->entity()->convertToField($name);
  307. $fields[$field] = $this->$name;
  308. }
  309. }
  310. return $fields;
  311. }
  312. /**
  313. * 清除变量内容
  314. * @return $this
  315. */
  316. final public function clear() {
  317. $class = get_called_class();
  318. $method = new \ReflectionClass($class);
  319. $properties = $method->getproperties();
  320. $fields = [];
  321. foreach($properties as $property) {
  322. if($property->isPublic()) {
  323. $name = $property->getName();
  324. if(!isset($this->$name)) {
  325. continue;
  326. }
  327. $this->$name = null;
  328. }
  329. }
  330. return $this;
  331. }
  332. /**
  333. * 获取默认值
  334. *
  335. * @return array
  336. */
  337. final public function getDefaultValue() {
  338. $default = [];
  339. $defaultValue = $this->defaultFieldsValue();
  340. if(!$defaultValue || !is_array($defaultValue) || count($defaultValue) == 0) {
  341. return $default;
  342. }
  343. foreach ($defaultValue as $key => $value) {
  344. $field = $this->entity()->convertToField($key);
  345. $default[$field] = $value;
  346. }
  347. return $default;
  348. }
  349. /**
  350. * 获取总行数
  351. *
  352. * @return mixed
  353. * @throws \Exception
  354. */
  355. final public function count() {
  356. return $this->db()->fields(' COUNT(1) as count')->where($this->getWhereHooker())->selectOne($this->getTable());
  357. }
  358. /**
  359. * 检查是否有对应的属性
  360. *
  361. * @param $key
  362. * @return bool
  363. */
  364. final public function hasProperty($key) {
  365. $class = get_called_class();
  366. $key = $this->entity()->convertToProperty($key);
  367. if(isset(self::$properties[$class])) {
  368. return isset(self::$properties[$class][$key]);
  369. }
  370. $method = new \ReflectionClass($class);
  371. $properties = $method->getproperties();
  372. $fields = array();
  373. foreach($properties as $property) {
  374. if($property->isPublic()) {
  375. $name = $property->getName();
  376. $fields[$name] = '';
  377. }
  378. }
  379. self::$properties[$class] = $fields;
  380. return isset($fields[$key]);
  381. }
  382. /**
  383. * bind value
  384. * @param $values
  385. * @return $this
  386. */
  387. final public function bindValues($values) {
  388. if(!is_array($values)) {
  389. return $this;
  390. }
  391. foreach ($values as $key => $value) {
  392. $property = $this->entity()->convertToProperty($key);
  393. if($this->hasProperty($key)) {
  394. $this->$property = $value;
  395. }
  396. }
  397. return $this;
  398. }
  399. /**
  400. * 获取数据
  401. *
  402. * @return Object
  403. * @throws \Exception
  404. */
  405. final public function get() {
  406. $class = get_called_class();
  407. $obj = new $class();
  408. $response = $this->info();
  409. if($response->isError()) {
  410. return $obj;
  411. }
  412. $info = $response->getResult()['body'];
  413. if(!$info) {
  414. return $obj;
  415. }
  416. foreach ($info as $key => $val) {
  417. $key = $this->entity()->convertToProperty($key);
  418. $obj->$key = $val;
  419. }
  420. return $obj;
  421. }
  422. /**
  423. * 与get不同的这个返回的是Response
  424. * @return mixed|\Qii\Driver\Qii\Driver\Response
  425. */
  426. final public function info() {
  427. try{
  428. $info = $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->selectRow($this->getTable());
  429. return Response::Success(
  430. static::class .'::'. __FUNCTION__,
  431. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '获取成功', 'body' => $info]]
  432. );
  433. }catch (\Exception $e) {
  434. return Response::Fail(static::class .'::'. __FUNCTION__,
  435. ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => $this->db()->getMessage(), 'body' => []]
  436. ]);
  437. }
  438. }
  439. /**
  440. * 是否相关数据存在
  441. *
  442. * @return bool
  443. */
  444. final public function exist() {
  445. $where = $this->getWhereHooker();
  446. if(!$where) {
  447. return false;
  448. }
  449. return (bool) $this->db()->where($where)->selectOne($this->getTable());
  450. }
  451. /**
  452. * 保存数据
  453. *
  454. * @return mixed|Response
  455. * @throws \Exception
  456. */
  457. final public function add() {
  458. $valid = $this->validFieldsForAdd();
  459. if($valid->isError()) {
  460. return $valid;
  461. }
  462. //如果设置了 unique 就先验证唯一性
  463. list($uniqueWhere, $exclude, $primary) = $this->condition();
  464. unset($exclude);
  465. //如果 $where $or 为空,看看主键是否有设置值,有设置值说明验证主键就可以,反之设置了主键,主键值设置了,只验证主键就可以了
  466. if(count($primary) > 0) {
  467. $exist = $this->db()->limit(1)->where($primary)->selectRow($this->getTable());
  468. if($exist) {
  469. return Response::Exist(static::class .'::'. __FUNCTION__,
  470. ['_result' => ['code' => Response::DOES_EXIST, 'msg' => '数据已经存在', 'body' => $exist]]
  471. );
  472. }
  473. }
  474. if(count($uniqueWhere) > 0) {
  475. $exist = $this->db()->limit(1)->where($uniqueWhere)->selectRow($this->getTable());
  476. if($exist) {
  477. return Response::Exist(static::class .'::'. __FUNCTION__,
  478. ['_result' => ['code' => Response::DOES_EXIST, 'msg' => '数据已经存在', 'body' => $exist]]
  479. );
  480. }
  481. }
  482. $values = array_merge($this->getDefaultValue(), $this->properties());
  483. $res = $this->db()->insertObject($this->getTable(), $values);
  484. if($this->db()->isError()) {
  485. return Response::FailSave(static::class .'::'. __FUNCTION__,
  486. ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => []]
  487. ]);
  488. }
  489. return Response::Success(static::class .'::'. __FUNCTION__,
  490. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '添加成功', 'body' => $res]]
  491. );
  492. }
  493. /**
  494. * 删除指定数据
  495. *
  496. * @return false|Response
  497. */
  498. public function remove() {
  499. if(!$this->properties()) {
  500. return Response::FailRemove(static::class .'::'. __FUNCTION__,
  501. ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => '未指定删除属性,不允许删除', 'body' => 0]
  502. ]);
  503. }
  504. $properties = [];
  505. foreach ($this->properties() as $key => $val) {
  506. $properties[] = $this->entity()->convertToProperty($key);
  507. }
  508. $valid = $this->valid($properties);
  509. if($valid->isError()) {
  510. return $valid;
  511. }
  512. $affectedRows = $this->db()->where($this->getWhereHooker())->delete($this->getTable());
  513. if($this->db()->isError()) {
  514. return Response::FailRemove(static::class .'::'. __FUNCTION__,
  515. ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => 0]
  516. ]);
  517. }
  518. return Response::Success(static::class .'::'. __FUNCTION__,
  519. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '删除成功,总共删除了'. $affectedRows . '条记录', 'body' => $affectedRows]]
  520. );
  521. }
  522. /**
  523. * 更新
  524. *
  525. * @return mixed | Response
  526. * @throws \Exception
  527. */
  528. final public function update(){
  529. $valid = $this->validFieldsForUpdate();
  530. if($valid->isError()) {
  531. return $valid;
  532. }
  533. //检查是否有重复的
  534. list($uniqueWhere, $exclude, $primaryKey) = $this->condition();
  535. // 检查 unique 是否已经存在相关数据
  536. $diffWhere = array_diff_assoc($uniqueWhere, $primaryKey);
  537. if(count($diffWhere) > 0) {
  538. $unique = $this->db()->limit(1)->where($diffWhere)->exclude($exclude)->selectRow($this->getTable());
  539. if($unique) {
  540. return Response::Exist(static::class .'::'. __FUNCTION__,
  541. ['_result' => ['code' => Response::DOES_EXIST, 'msg' => '已经存在相关记录', 'body' => $unique]]
  542. );
  543. }
  544. }
  545. $where = [];
  546. $whereHooker = $this->getWhereHooker();
  547. foreach ($whereHooker as $key => $val) {
  548. $keyArr = explode(':', $key);
  549. if(isset($primaryKey[$keyArr[0]])) {
  550. unset($primaryKey[$keyArr[0]]);
  551. $where[$key] = $val;
  552. }
  553. }
  554. if(count($where) > 0) {
  555. $primaryKey = $where;
  556. }
  557. //检查更新的数据是否存在,以主键为主
  558. $exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->getTable());
  559. if($exit === null || $exit === false) {
  560. return Response::NotExist(static::class .'::'. __FUNCTION__,
  561. ['_result' => ['code' => Response::DOES_NOT_EXIST, 'msg' => '未找到相关记录', 'body' => []]]
  562. );
  563. }
  564. //获取默认值
  565. //更新的时候不使用默认值
  566. //$values = array_merge($this->getDefaultValue(), $this->properties());
  567. $affectedRows = $this->db()->updateObject($this->getTable(), $this->properties(), $primaryKey);
  568. if($this->db()->isError()) {
  569. return Response::FailUpdate(static::class .'::'. __FUNCTION__,
  570. ['_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []]]
  571. );
  572. }
  573. return Response::Success(static::class .'::'. __FUNCTION__,
  574. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '数据更新成功', 'body' => $affectedRows]]
  575. );
  576. }
  577. /**
  578. * 更新字段
  579. *
  580. * @return mixed|Response
  581. * @throws \Exception
  582. */
  583. final public function updateFields() {
  584. $properties = $this->properties();
  585. $fields = $this->entity()->convertToProperties(array_keys($properties));
  586. $valid = $this->valid($fields);
  587. if($valid->isError()) {
  588. return $valid;
  589. }
  590. list($uniqueWhere, $exclude, $primaryKey) = $this->condition();
  591. // 检查 unique 是否已经存在相关数据
  592. $diffWhere = array_diff_assoc($uniqueWhere, $primaryKey);
  593. if(count($diffWhere) > 0) {
  594. $unique = $this->db()->limit(1)->where($diffWhere)->exclude($exclude)->selectRow($this->getTable());
  595. if($unique) {
  596. return Response::Exist(static::class .'::'. __FUNCTION__,
  597. ['_result' => ['code' => Response::DOES_EXIST, 'msg' => '已经存在相关记录', 'body' => $unique]]
  598. );
  599. }
  600. }
  601. /*$whereHooker = $this->getWhereHooker();
  602. if(!empty($whereHooker)) {
  603. $primaryKey = $whereHooker;
  604. }*/
  605. $where = [];
  606. $whereHooker = $this->getWhereHooker();
  607. foreach ($whereHooker as $key => $val) {
  608. $keyArr = explode(':', $key);
  609. if(isset($primaryKey[$keyArr[0]])) {
  610. unset($primaryKey[$keyArr[0]]);
  611. $where[$key] = $val;
  612. }
  613. }
  614. if(count($where) > 0) {
  615. $primaryKey = $where;
  616. }
  617. //检查更新的数据是否存在,以主键为主
  618. $exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->getTable());
  619. if($exit === null || $exit === false) {
  620. return Response::NotExist(static::class .'::'. __FUNCTION__,
  621. ['_result' => ['code' => Response::DOES_NOT_EXIST, 'msg' => '未找到相关记录', 'body' => []]]
  622. );
  623. }
  624. //获取默认值
  625. //更新的时候不使用默认值
  626. //$values = array_merge($this->getDefaultValue(), $this->properties());
  627. $affectedRows = $this->db()->updateObject($this->getTable(), $this->properties(), $primaryKey);
  628. if($this->db()->isError()) {
  629. return Response::FailUpdate(static::class .'::'. __FUNCTION__,
  630. ['_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []]]
  631. );
  632. }
  633. return Response::Success(static::class .'::'. __FUNCTION__,
  634. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '数据更新成功', 'body' => $affectedRows]]
  635. );
  636. }
  637. /**
  638. * 增加或减少某一个字段的值
  639. *
  640. * @return mixed|Response
  641. * @throws \Exception
  642. */
  643. final public function incr() {
  644. list($where, $exclude, $primary) = $this->condition();
  645. unset($where, $exclude);
  646. $property = $this->properties();
  647. $incr = [];
  648. foreach ($property as $key => $value) {
  649. if(!is_numeric($value)) {
  650. continue;
  651. }
  652. $incr[$key] = $value;
  653. }
  654. $diff = array_diff_assoc($incr, $primary);
  655. if(count($diff) == 0) {
  656. return Response::Fail(self::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::DO_FAIL, 'msg' => 'INCR 参数错误']]);
  657. }
  658. $sets = [];
  659. foreach ($diff as $key => $val) {
  660. if($val == 0) {
  661. $sets[$key] = $val;
  662. }else if($val > 0) {
  663. $sets[$key . ':plus'] = $val;
  664. }else if($val < 0) {
  665. $sets[$key . ':minus'] = $val * -1;
  666. }
  667. }
  668. $whereHooker = $this->getWhereHooker();
  669. if(!empty($whereHooker)) {
  670. foreach ($whereHooker as $key => $where) {
  671. //去掉where条件里边的sets的值
  672. $keys = $this->explode(":", $key);
  673. if(isset($diff[$keys[0]])) {
  674. unset($whereHooker[$key]);
  675. }
  676. }
  677. $primary = $whereHooker;
  678. }
  679. $affectedRows = $this->db()->set($sets)->where($primary)->update($this->getTable());
  680. if($this->db()->isError()) {
  681. return Response::FailUpdate(static::class .'::'. __FUNCTION__,
  682. ['_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []]]
  683. );
  684. }
  685. return Response::Success(static::class .'::'. __FUNCTION__,
  686. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => 'INCR 成功', 'body' => $affectedRows]]
  687. );
  688. }
  689. /**
  690. * 获取第一条数据
  691. *
  692. * @return mixed|Response
  693. * @throws \Exception
  694. */
  695. final public function first() {
  696. $orderBy = $this->getOrderBy();
  697. //未设置order by 就以主键为准
  698. if(empty($orderBy)) {
  699. $orderBy = $this->primaryCondition();
  700. }
  701. foreach ($orderBy as $key => $value) {
  702. $orderBy[$key] = 'ASC';
  703. }
  704. $row = $this->db()->orderBy($orderBy)->limit(1)->selectRow($this->getTable());
  705. if($this->db()->isError()) {
  706. return Response::Fail(static::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => 'Query 失败', 'body' => []]]);
  707. }
  708. return Response::Success(static::class .'::'. __FUNCTION__,
  709. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => 'Query 成功', 'body' => $row]]
  710. );
  711. }
  712. /**
  713. * 获取第一条数据
  714. *
  715. * @return mixed|Response
  716. * @throws \Exception
  717. */
  718. final public function last() {
  719. $orderBy = $this->getOrderBy();
  720. //未设置order by 就以主键为准
  721. if(empty($orderBy)) {
  722. $orderBy = $this->primaryCondition();
  723. }
  724. foreach ($orderBy as $key => $value) {
  725. $orderBy[$key] = 'DESC';
  726. }
  727. $row = $this->db()->fields($this->getFieldsHooker())->orderBy($orderBy)->limit(1)->selectRow($this->getTable());
  728. if($this->db()->isError()) {
  729. return Response::Fail(static::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => 'Query 失败', 'body' => []]]);
  730. }
  731. return Response::Success(static::class .'::'. __FUNCTION__,
  732. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => 'Query 成功', 'body' => $row]]
  733. );
  734. }
  735. /**
  736. * listts
  737. * @param int $page 页码
  738. * @param int $pageSize 页大小
  739. * @return array
  740. * @throws \Exception
  741. */
  742. final public function lists($page = 1, $pageSize = 20) {
  743. $count = $this->count();
  744. if(!$this->initPages($data, $count, $page, $pageSize)) {
  745. return $data;
  746. }
  747. $data['lists'] = $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($data['pages']['limitStart'], $pageSize)->selectRows($this->getTable());
  748. return $data;
  749. }
  750. /**
  751. * 获取所有数据,这里不分页,但支持限条数,通过 setLimitHooker来实现
  752. * $this->setLimitHooker(function(){
  753. * return [x,y];//从第x条开始获取y条; return [1];//获取一条 return [0];//获取所有的
  754. * });
  755. * @return mixed
  756. * @throws \Exception
  757. */
  758. final public function listAll() {
  759. return $this->rsCondition()->selectRows($this->getTable());
  760. }
  761. /**
  762. * 返回指针
  763. * @return mixed
  764. * @throws \Exception
  765. */
  766. final public function rs() {
  767. return $this->rsCondition()->rs($this->getTable());
  768. }
  769. /**
  770. * 通过此方法获取 rs
  771. * @return mixed
  772. */
  773. private function rsCondition() {
  774. $limit = $this->getLimitHooker();
  775. if(empty($limit) || !is_array($limit)) {
  776. return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy());
  777. }
  778. if(count($limit) == 1) {
  779. return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0]);
  780. }
  781. return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0], $limit[1]);
  782. }
  783. /**
  784. * 验证相关字段
  785. *
  786. * @param array $fields 字段列表
  787. * @return Response
  788. */
  789. final public function valid($fields = array()) {
  790. if(!is_array($fields)) {
  791. return Response::FailValidate(static::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::FAIL_FOR_VALIDATE, 'msg' => '字段必须是数组', 'fields' => []]]);
  792. }
  793. $rules = $this->rules();
  794. $result = [];
  795. $invalidKey = [];
  796. $values = array_merge($this->getDefaultValue(), $this->properties());
  797. foreach ($rules as $valid => $rule) {
  798. foreach ($rule as $val) {
  799. $key = $this->entity()->convertToProperty($val[0]);
  800. if(!in_array($key, $fields)) {
  801. continue;
  802. }
  803. $field = $this->entity()->convertToField($key);
  804. $value = isset($values[$field]) ? $values[$field] : null;
  805. $limit = isset($val[2]) ? $val[2]: '';
  806. $verify = new Verify($val[0], $value, strtolower($valid), $val[1], $limit);
  807. $res = $verify->valid();
  808. if($res->isError()) {
  809. $result[] = $res->getResult() .',获取的是 '. $values[$field];
  810. if(!in_array($field, $invalidKey)) {
  811. $invalidKey[] = $field;
  812. }
  813. }
  814. }
  815. }
  816. if(count($result) > 0) {
  817. return Response::FailValidate(static::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::FAIL_FOR_VALIDATE, 'msg' => $result, 'fields' => $invalidKey]]);
  818. }
  819. return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
  820. }
  821. /**
  822. * 合并多个 valid 结果 $this->>valids($this->valid(['Uid']), $this->valid(['Nickname', 'Email']));
  823. * @param ...
  824. * @return mixed|Response
  825. * @throws \Exception
  826. */
  827. final public function valids() {
  828. $validArr = func_get_args();
  829. if(count($validArr) == 0) {
  830. return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
  831. }
  832. if(count($validArr) == 1) {
  833. return $validArr[0];
  834. }
  835. $invalid = array();
  836. $invalid['message'] = array();
  837. $invalid['fields'] = array();
  838. foreach ($validArr as $valid) {
  839. if(!($valid instanceof Response)) {
  840. throw new \Exception('验证结果类型必须是\Qii\Drive\Response类型');
  841. }
  842. if($valid->isError()) {
  843. $result = $valid->getResult();
  844. $invalid['message'] = array_merge($invalid['message'], $result['message']);
  845. $invalid['fields'] = array_merge($invalid['fields'], $result['fields']);;
  846. }
  847. }
  848. if(count($invalid['message']) > 0) {
  849. return Response::Fail(static::class .'::'. __FUNCTION__, ['_result' => ['message' => $invalid['message'], 'fields' => $invalid['fields']]]);
  850. }
  851. return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
  852. }
  853. /**
  854. * unique 条件
  855. *
  856. * @return array[]
  857. * @throws \Exception
  858. */
  859. protected function uniqueCondition() {
  860. $uniqueWhere = [];
  861. $unique = $this->uniqueKey();
  862. $useWhere = true;
  863. $condition = [];
  864. if(empty($unique)) {
  865. return $condition;
  866. }
  867. if(!is_array($unique)) {
  868. $unique = $this->explode(',', $unique);
  869. foreach ($unique as $val) {
  870. $condition[] = $val;
  871. }
  872. }else{
  873. //检查是否是一维数组,一维数组联合唯一
  874. if(count($unique) == count($unique, 1)) {
  875. $condition[] = $unique;
  876. }else{
  877. $condition = $unique;
  878. }
  879. }
  880. foreach ($condition as $item) {
  881. $uniqueWhere[] = "OR";
  882. $arr = [];
  883. foreach ($item as $key) {
  884. $key = $this->entity()->convertToField($key);
  885. $property = $this->entity()->convertToProperty($key);
  886. $arr[$key] = $this->$property;
  887. }
  888. $uniqueWhere[] = $arr;
  889. }
  890. return $uniqueWhere;
  891. }
  892. /**
  893. * exclude Condition
  894. *
  895. * @return array
  896. */
  897. protected function excludeCondition() {
  898. if(is_array($this->exclude())) {
  899. $exclude = $this->exclude();
  900. }else{
  901. $exclude = (array) $this->explode(',', $this->exclude());
  902. }
  903. $excludeCondition = [];
  904. foreach ($exclude as $key) {
  905. $field = $this->entity()->convertToField($key);
  906. $property = $this->entity()->convertToProperty($key);
  907. $excludeCondition[$field] = $this->$property;
  908. }
  909. return $excludeCondition;
  910. }
  911. /**
  912. * 主键
  913. *
  914. * @return array
  915. * @throws \Exception
  916. */
  917. protected function primaryCondition(){
  918. $primary = array();
  919. $primaryKey = $this->primaryKey();
  920. if(!is_array($primaryKey)) {
  921. $primaryKey = $this->explode(',', $primaryKey);
  922. }
  923. foreach ($primaryKey as $key) {
  924. $key = $this->entity()->convertToProperty($key);
  925. $field = $this->entity()->convertToField($key);
  926. $value = $this->$key;
  927. $primary[$field] = $value;
  928. }
  929. return $primary;
  930. }
  931. /**
  932. * 获取查询条件
  933. *
  934. * @return array [$uniqueWhere, $uniqueOr, $excludeCondition, $primaryCondition]
  935. */
  936. final public function condition() {
  937. //如果设置了 unique 就先验证唯一性,保存的时候验证 uniqueKey,更新的时候验证uniqueKey并排primaryKey
  938. //保存数据的时候验证uniqueKey;更新时验证 uniqueKey,并且排除 primaryKey,如果uniqueKey == primaryKey则不去做唯一性验证
  939. $uniqueWhere = $this->uniqueCondition();
  940. $excludeCondition = $this->excludeCondition();
  941. $primaryCondition = $this->primaryCondition();
  942. return [$uniqueWhere, $excludeCondition, $primaryCondition];
  943. }
  944. /**
  945. * 获取order by
  946. *
  947. * @return array
  948. */
  949. final public function getOrderBy() {
  950. $order = array();
  951. $orderBy = (array) $this->orderBy();
  952. if(isset($this->hooker['order']) && is_callable($this->hooker['order']['func'])) {
  953. $orderBy = (array) call_user_func($this->hooker['order']['func'], $order, $this->hooker['order']['args']);
  954. }
  955. foreach ($orderBy as $key => $val) {
  956. $field = $this->entity()->convertToField($key);
  957. $val = strtoupper($val);
  958. if(!in_array($val, array('DESC', 'ASC'))) {
  959. continue;
  960. }
  961. $order[$field] = $val;
  962. }
  963. return (array) $order;
  964. }
  965. /**
  966. * 初始化page
  967. * @param array $data 返回的数据
  968. * @param int $count 总数量
  969. * @param int $page 页码
  970. * @param int $pageSize 显示数量
  971. * @param int $pagination 分页显示最多页码
  972. * @return bool
  973. */
  974. public function initPages(&$data, $count, $page, $pageSize = 20, $pagination = 5) {
  975. $page = max(1, $page);
  976. $pageSize = max(1, $pageSize);
  977. $data['start'] = 0;
  978. $data['pages'] = array('total' => 0, 'currentPage' => 0, 'totalPage' => 0);
  979. $data['pages']['total'] = (int) ($count ? $count : 0);
  980. $data['pages']['currentPage'] = $page;
  981. $data['pages']['totalPage'] = ceil($data['pages']['total'] / $pageSize);
  982. $data['lists'] = array();
  983. if ($data['pages']['currentPage'] > $data['pages']['totalPage']) {
  984. return false;
  985. }
  986. $frames = array(
  987. 'left' => 0,
  988. 'right' => 0
  989. );
  990. $pagination = $pagination < $data['pages']['totalPage'] ? $pagination : $data['pages']['totalPage'];
  991. if($data['pages']['currentPage'] - floor($pagination / 2) <= 0) {
  992. $frames['left'] = 1;
  993. $frames['right'] = $frames['left'] + $pagination - 1;
  994. } else if($data['pages']['currentPage'] + floor($pagination / 2) >= $data['pages']['totalPage']) {
  995. $frames['right'] = $data['pages']['totalPage'];
  996. $frames['left'] = $frames['right'] - $pagination + 1;
  997. } else {
  998. $frames['left'] = $data['pages']['currentPage'] - floor($pagination / 2);
  999. $frames['right'] = $data['pages']['currentPage'] + ceil($pagination / 2) - 1;
  1000. }
  1001. $data['start'] = $frames['left'];
  1002. $data['pages']['start'] = $data['start'];
  1003. $data['pages']['end'] = $frames['right'];
  1004. $data['pages']['pagination'] = $pagination;
  1005. $data['pages']['limitStart'] = (min($page, $data['pages']['totalPage']) - 1) * $pageSize;
  1006. $data['pages']['pageSize'] = (int) $pageSize;
  1007. return true;
  1008. }
  1009. /**
  1010. * response as object
  1011. *
  1012. * @return mixed|\Qii\Driver\Qii\Driver\Response
  1013. */
  1014. final public function response() {
  1015. $properties = $this->properties();
  1016. if(!$properties) {
  1017. return Response::Fail(static::class .'::'. __FUNCTION__,
  1018. ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => '未找到相关数据', 'body' => []]
  1019. ]
  1020. );
  1021. }
  1022. return Response::Success(static::class .'::'. __FUNCTION__,
  1023. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '获取成功', 'body' => $properties]]
  1024. );
  1025. }
  1026. /**
  1027. * 方法名 + ByCache/ByRedis/ByMemcache/会将结果缓存,这里使用的缓存类是通过hooker设置的,否则使用对应的
  1028. * ByClean 则会移除当前缓存, 默认转发到 db model上
  1029. * @param string $method method
  1030. * @param array $args
  1031. * @return mixed
  1032. */
  1033. public function __call($method, $args) {
  1034. $cache = '';
  1035. preg_match("/(byredis|bymemcache|bycache|byclean)$/i", $method, $matches);
  1036. if($matches && count($matches) > 0) {
  1037. $cache = strtolower($matches[0]);
  1038. }
  1039. if($cache && in_array($cache, ['bymemcache', 'byredis', 'bycache', 'byclean'])){
  1040. list($func, $cacheID, $config) = $this->getCacheHooker();
  1041. $policy = $this->getCacheConfig();
  1042. if($func == null) {
  1043. $func = $cache == 'bymemcache' ? $this->db()->setCache('memcached', $policy) : $this->db()->setCache('redis', $policy);
  1044. }
  1045. $method = substr($method, 0, strlen($cache) * -1);
  1046. if (method_exists($this, $method)) {
  1047. $key = get_called_class() .':'. $method .':'. substr(md5(serialize($this->properties())), -16);
  1048. if($cache == 'byclean') {
  1049. return $func->del($key);
  1050. }
  1051. if(is_object($func) && method_exists($func, 'get')) {
  1052. $res = $func->get($key);
  1053. if ($res) {
  1054. return unserialize($res);
  1055. }
  1056. }
  1057. $expiredAt = isset($config['life_time']) ? (int) $config['life_time'] :
  1058. (isset($policy['life_time']) ? $policy['life_time'] : $this->defaultExpired);
  1059. $res = call_user_func_array(array($this, $method), $args);
  1060. $str = serialize($res);
  1061. $func->set($key, $str, ['life_time' => $expiredAt]);
  1062. return $res;
  1063. }
  1064. }
  1065. return call_user_func_array(array($this->db(), $method), $args);
  1066. }
  1067. }