Base.php 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735
  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. /**
  12. * 配置信息
  13. *
  14. * @var array $config
  15. */
  16. public static $config;
  17. /**
  18. * 主键
  19. * @var mix $privateKeys null
  20. */
  21. public static $privateKeys = null;
  22. /**
  23. * 唯一字段
  24. *
  25. * @var array $uniqKeys
  26. */
  27. public static $uniqKeys = null;
  28. /**
  29. * 设置排除项
  30. *
  31. * @var array $exclude
  32. */
  33. public static $exclude = [];
  34. /**
  35. * @var string 表别名
  36. */
  37. private $alias;
  38. private $nullFields = [];
  39. /**
  40. * hooker for fields 查询字段/ where 查询条件 / order 排序 / cache 缓存 / with 关联查询
  41. * @var array $hooker
  42. */
  43. private $hooker = array();
  44. /**
  45. * 默认过期时间
  46. *
  47. * @var int $defaultExpired
  48. */
  49. private $defaultExpired = 600;
  50. /** 当前执行的sql
  51. *
  52. * @var string
  53. */
  54. private $calledSQL = "";
  55. public function __construct(){
  56. }
  57. /**
  58. * 默认值,仅在新增数据的时候支持,更新不支持
  59. *
  60. * @return array
  61. */
  62. public function defaultFieldsValue(){}
  63. /**
  64. * 返回 table 的名字,以便分库分表的时候指定使用
  65. *
  66. * @return mixed
  67. * @throws \Exception
  68. */
  69. public function getTable() {
  70. throw new \Exception('请先设置需要保存的数据表');
  71. }
  72. /**
  73. * 当前表名别名
  74. *
  75. * @param string $name
  76. * @return $this
  77. */
  78. public function alias($name) {
  79. $this->alias = $name;
  80. return $this;
  81. }
  82. /**
  83. * 预处理表名
  84. *
  85. * @return mixed|string
  86. * @throws \Exception
  87. */
  88. public function prepareTable() {
  89. if($this->alias == '') {
  90. return $this->getTable();
  91. }
  92. return $this->getTable() . ' ' . $this->alias;
  93. }
  94. /**
  95. * set hooker for method
  96. * 目前 where 和 order 及 fields 支持
  97. * @param $key
  98. * @param $hooker
  99. * @return $this
  100. */
  101. protected function setHooker($key, $hooker, $args) {
  102. $this->hooker[$key]['func'] = $hooker;
  103. $this->hooker[$key]['args'] = $args;
  104. return $this;
  105. }
  106. /**
  107. * Or Hooker
  108. * @param $hooker
  109. * @param $args
  110. * @return $this
  111. * @throws \Exception
  112. */
  113. public function setOrHooker($hooker, $args = null){
  114. $this->checkCallable($hooker);
  115. if(!isset($this->hooker['or'])) {
  116. $this->hooker['or'] = [];
  117. }
  118. $this->hooker['or'][] = ['func' => $hooker, 'args' => $args];
  119. return $this;
  120. }
  121. /**
  122. * 获取or条件
  123. *
  124. * @return array
  125. */
  126. public function getOrHooker() {
  127. $or = [];
  128. if(isset($this->hooker['or'])) {
  129. foreach ($this->hooker['or'] as $value) {
  130. if(is_callable($value['func'])) {
  131. $or[] = call_user_func($value['func'], [], $value['args']);
  132. }
  133. }
  134. }
  135. return $or;
  136. }
  137. /**
  138. * 设置where hooker
  139. * @param object $hooker
  140. * @return $this
  141. * @throws \Exception
  142. */
  143. public function setWhereHooker($hooker, $args = null) {
  144. $this->checkCallable($hooker);
  145. $this->setHooker('where', $hooker, $args);
  146. return $this;
  147. }
  148. /**
  149. * 获取where条件
  150. *
  151. * @return array|mixed
  152. */
  153. public function getWhereHooker() {
  154. $where = $this->properties();
  155. if(isset($this->hooker['where']) && is_callable($this->hooker['where']['func'])) {
  156. if($this->alias != ""){
  157. foreach ($where as $key => $value) {
  158. if(!preg_match("/{$this->alias}\.{$key}/", $key)) {
  159. $where[$this->alias .'.'. $key] = $value;
  160. unset($where[$key]);
  161. }
  162. }
  163. }
  164. $where = call_user_func($this->hooker['where']['func'], $where, $this->hooker['where']['args']);
  165. }
  166. return $where;
  167. }
  168. /**
  169. * join hooker
  170. * @param \Closure $hooker
  171. * @param mix $args
  172. * @return $this
  173. * @throws \Exception
  174. */
  175. public function setJoinHooker($hooker, $args = null) {
  176. $this->checkCallable($hooker);
  177. if(!isset($this->hooker['join'])) {
  178. $this->hooker['join'] = [];
  179. }
  180. $this->hooker['join'][] = ['func' => $hooker, 'args' => $args];
  181. return $this;
  182. }
  183. /**
  184. * 获取 join hooker
  185. * @return array
  186. */
  187. public function getJoinHooker() {
  188. $join = [];
  189. if(isset($this->hooker['join'])) {
  190. foreach ($this->hooker['join'] as $value) {
  191. if(is_callable($value['func'])) {
  192. $join[] = call_user_func($value['func'], [], $value['args']);
  193. }
  194. }
  195. }
  196. return $join;
  197. }
  198. /**
  199. * 设置order by hooker
  200. * @param object $hooker
  201. * @return $this
  202. * @throws \Exception
  203. */
  204. public function setOrderHooker($hooker, $args = null) {
  205. $this->checkCallable($hooker);
  206. $this->setHooker('order', $hooker, $args);
  207. return $this;
  208. }
  209. /**
  210. * 设置 limit hooker
  211. *
  212. * @param object $hooker
  213. * @return $this
  214. * @throws \Exception
  215. */
  216. public function setLimitHooker($hooker, $args = null) {
  217. $this->checkCallable($hooker);
  218. $this->setHooker('order', $hooker, $args);
  219. return $this;
  220. }
  221. /**
  222. * 获取limit
  223. * @return int|mixed
  224. */
  225. public function getLimitHooker() {
  226. if(isset($this->hooker['limit']) && is_callable($this->hooker['limit']['func'])) {
  227. return call_user_func($this->hooker['limit']['func'], [], $this->hooker['limit']['args']);
  228. }
  229. return [];
  230. }
  231. /**
  232. * 设置 cache hooker
  233. *
  234. * @param callable $hooker
  235. * @param array| mixed $args
  236. * @return $this
  237. * @throws \Exception
  238. */
  239. public function setCacheHooker($hooker, $args = null) {
  240. $this->checkCallable($hooker);
  241. $this->setHooker('cache', $hooker, $args);
  242. return $this;
  243. }
  244. /**
  245. * 获取Cache Hooker
  246. * @return mixed|null[]
  247. */
  248. public function getCacheHooker() {
  249. if(isset($this->hooker['cache']) && is_callable($this->hooker['cache']['func'])) {
  250. return call_user_func($this->hooker['cache']['func'], [], $this->hooker['cache']['args']);
  251. }
  252. return [null, null, null];
  253. }
  254. /**
  255. * 缓存设置
  256. *
  257. * @param array $config 缓存配置
  258. * @return void
  259. */
  260. public function setCacheConfig($config) {
  261. if(!is_array($config)) {
  262. return;
  263. }
  264. self::$config['cache'] = $config;
  265. }
  266. /**
  267. * 获取缓存的配置信息
  268. *
  269. * @return array
  270. */
  271. public function getCacheConfig() {
  272. if(is_array(self::$config) && isset(self::$config['cache']) && is_array(self::$config['cache'])) {
  273. return self::$config['cache'];
  274. }
  275. return array();
  276. }
  277. /**
  278. * 设置关联子查询
  279. *
  280. * @param $hooker [关联对象, 返回数据key, hasOne/hasMany, 主键, rel 主键]
  281. * @params $args
  282. * @return $this
  283. * @throws \Exception
  284. */
  285. public function setWith($hooker, $args = null){
  286. $this->checkCallable($hooker);
  287. if(!isset($this->hooker['with'])) {
  288. $this->hooker['with'] = [];
  289. }
  290. $this->hooker['with'][] = ['func' => $hooker, 'args' => $args];
  291. return $this;
  292. }
  293. /**
  294. * 获取with hooker
  295. *
  296. * @return array
  297. */
  298. public function getWithHooker() {
  299. $callback = [];
  300. if(isset($this->hooker['with'])) {
  301. foreach ($this->hooker['with'] AS $hooker) {
  302. if(is_callable($hooker['func'])) {
  303. $callback[] = call_user_func($hooker['func'], [], $hooker['args']);
  304. }
  305. }
  306. }
  307. return $callback;
  308. }
  309. /**
  310. * 如果hooker不可调用即抛出异常
  311. *
  312. * @param object $hooker
  313. * @return void
  314. * @throws \Exception
  315. */
  316. private function checkCallable($hooker) {
  317. if($hooker && !is_callable($hooker)) {
  318. throw new \Exception('Hooker is uncallable');
  319. }
  320. }
  321. /**
  322. * 设置order by hooker
  323. * @param object $hooker
  324. * @return void
  325. * @throws \Exception
  326. */
  327. public function setQueryFieldsHooker($hooker, $args = null) {
  328. if(!is_callable($hooker)) {
  329. throw new \Exception('Hooker is un callable');
  330. }
  331. $this->setHooker('fields', $hooker, $args);
  332. }
  333. /**
  334. * 通过field hooker返回查询的字段
  335. *
  336. * @return mixed|string
  337. */
  338. public function getFieldsHooker() {
  339. if(isset($this->hooker['fields']) && is_callable($this->hooker['fields']['func'])) {
  340. return call_user_func($this->hooker['fields']['func'], [], $this->hooker['fields']['args']);
  341. }
  342. return '*';
  343. }
  344. /**
  345. * 获取指定field的值
  346. * @param string $field
  347. * @return mixed
  348. */
  349. public function getFieldVal($field) {
  350. if(!preg_match('/^[a-zA-Z]/', $field)) {
  351. throw new \Exception('Field is illegal');
  352. }
  353. $property = $this->entity()->convertToProperty($field);
  354. return $this->{$property};
  355. }
  356. /**
  357. * 返回使用的db信息
  358. *
  359. * @return \Qii\Driver\Base
  360. */
  361. public function db() {
  362. return _loadClass('\Qii\Driver\Model');
  363. }
  364. /**
  365. * 返回 entity 信息
  366. * @return mixed
  367. */
  368. public function entity() {
  369. return _loadClass('\Qii\Driver\Entity\Entity');
  370. }
  371. /**
  372. * 返回所有 Fields
  373. * @return array
  374. */
  375. public function fields()
  376. {
  377. return [];
  378. }
  379. /**
  380. * 设置唯一字段
  381. *
  382. * @param mixed $uniqKeys 唯一字段
  383. * @return void
  384. */
  385. public function setUniqKeys($uniqKeys) {
  386. self::$uniqKeys = $uniqKeys;
  387. }
  388. /**
  389. * unique (unique 如果是 array 则表示 联合唯一,如果是string则是任意唯一,多个单独唯一使用字符串以逗号隔开, 主键除外)
  390. *
  391. * @return mixed
  392. * @throws \Exception
  393. */
  394. public function uniqueKey(){
  395. if(self::$uniqKeys !== null) {
  396. return self::$uniqKeys;
  397. }
  398. throw new \Exception('请设置唯一值');
  399. }
  400. /**
  401. * 设置主键
  402. *
  403. * @param mixed $privateKeys
  404. * @return void
  405. */
  406. public function setPricateKey($privateKeys){
  407. self::$privateKeys = $privateKeys;
  408. }
  409. /**
  410. * 主键
  411. *
  412. * @return mixed
  413. * @throws \Exception
  414. */
  415. public function primaryKey(){
  416. if(self::$privateKeys !== null) {
  417. return self::$privateKeys;
  418. }
  419. throw new \Exception('请设置主键');
  420. }
  421. /**
  422. * 设置排除项
  423. * @param array $exclude
  424. * @return void
  425. */
  426. public function setExclude($exclude) {
  427. if(!is_array($exclude)) {
  428. return;
  429. }
  430. self::$exclude = $exclude;
  431. }
  432. /**
  433. * 保存数据的时候,验证唯一需要排除的值,此处仅支持,单个或联合排除,不支持单个异或排除
  434. *
  435. * @return array
  436. */
  437. public function exclude(){
  438. if(self::$exclude !== null) {
  439. return self::$exclude;
  440. }
  441. return array();
  442. }
  443. /**
  444. * order by
  445. * @return string[]
  446. */
  447. public function orderBy() {
  448. return array();
  449. }
  450. /**
  451. * explode string
  452. * @param string $separator 分隔符
  453. * @param string $string 分割的字符串
  454. * @param int $limit 是否
  455. * @return array|false|string[]
  456. */
  457. public function explode($separator, $string, $limit = PHP_INT_MAX) {
  458. if($string == '') {
  459. return [];
  460. }
  461. return explode($separator, $string, $limit);
  462. }
  463. /**
  464. * 添加数据验证字段
  465. *
  466. * $fields = [];
  467. * return $this->valid($fields);
  468. *
  469. * @return mixed
  470. * @throws \Exception
  471. */
  472. public function validFieldsForAdd(){
  473. throw new \Exception('请设置插入数据验证的字段,格式如:["Id", "Title"],Id和Title为entity的属性');
  474. }
  475. /**
  476. * 更新数据验证字段
  477. *
  478. * $fields = [];
  479. * return $this->valid($fields);
  480. *
  481. * @return mixed
  482. * @throws \Exception
  483. */
  484. public function validFieldsForUpdate() {
  485. throw new \Exception('请设置更新数据验证的字段,格式如:["Id", "Title"],Id和Title为entity的属性');
  486. }
  487. /**
  488. * 设置需要更新为空的字段列表
  489. *
  490. * @param $fields
  491. * @return $this
  492. */
  493. public function setNull($fields) {
  494. $tableFields = $this->fields();
  495. foreach ($fields AS $field) {
  496. if(!in_array($field, $tableFields)) {
  497. continue;
  498. }
  499. $field = $this->entity()->convertToProperty($field);
  500. $this->nullFields[] = $field;
  501. }
  502. return $this;
  503. }
  504. /**
  505. * 获取不为空的属性
  506. *
  507. * @return array
  508. */
  509. public function properties() {
  510. $class = get_called_class();
  511. $method = new \ReflectionClass($class);
  512. $properties = $method->getproperties();
  513. $fields = [];
  514. foreach($properties as $property) {
  515. if($property->isPublic() && !$property->isStatic()) {
  516. $name = $property->getName();
  517. if(!isset($this->$name)) {
  518. continue;
  519. }
  520. $field = $this->entity()->convertToField($name);
  521. $fields[$field] = $this->$name;
  522. }
  523. }
  524. if(count($this->nullFields) > 0) {
  525. foreach ($this->nullFields AS $field) {
  526. $field = $this->entity()->convertToField($field);
  527. $fields[$field] = null;
  528. }
  529. }
  530. return $fields;
  531. }
  532. /**
  533. * 获取默认值
  534. *
  535. * @return array
  536. */
  537. public function getDefaultValue() {
  538. $default = [];
  539. $defaultValue = $this->defaultFieldsValue();
  540. if(!$defaultValue || !is_array($defaultValue) || count($defaultValue) == 0) {
  541. return $default;
  542. }
  543. foreach ($defaultValue as $key => $value) {
  544. $field = $this->entity()->convertToField($key);
  545. $default[$field] = $value;
  546. }
  547. return $default;
  548. }
  549. /**
  550. * 获取总行数
  551. *
  552. * @return mixed
  553. * @throws \Exception
  554. */
  555. public function count() {
  556. $query = $this->createQuery();
  557. $query->fields(' COUNT(1) as count');
  558. return $query->selectOne($this->prepareTable());
  559. }
  560. /**
  561. * 检查是否有对应的属性
  562. *
  563. * @param $key
  564. * @return bool
  565. * @throws \ReflectionException
  566. */
  567. public function hasProperty($key) {
  568. $class = get_called_class();
  569. $key = $this->entity()->convertToProperty($key);
  570. if(isset(self::$properties[$class])) {
  571. return isset(self::$properties[$class][$key]);
  572. }
  573. $method = new \ReflectionClass($class);
  574. $properties = $method->getproperties();
  575. $fields = array();
  576. foreach($properties as $property) {
  577. if($property->isPublic()) {
  578. $name = $property->getName();
  579. $fields[$name] = '';
  580. }
  581. }
  582. self::$properties[$class] = $fields;
  583. return isset($fields[$key]);
  584. }
  585. /**
  586. * bind value
  587. * @param $values
  588. * @return $this
  589. * @throws \ReflectionException
  590. */
  591. public function bindValues($values) {
  592. if(!is_array($values)) {
  593. return $this;
  594. }
  595. foreach ($values as $key => $value) {
  596. $property = $this->entity()->convertToProperty($key);
  597. if($this->hasProperty($key)) {
  598. $this->$property = $value;
  599. }
  600. }
  601. return $this;
  602. }
  603. /**
  604. * 回去当前执行的sql
  605. *
  606. * @return string
  607. */
  608. public function getCalledSQL() {
  609. return $this->calledSQL;
  610. }
  611. /**
  612. * 获取数据
  613. *
  614. * @return Object
  615. * @throws \Exception
  616. */
  617. public function get() {
  618. $class = get_called_class();
  619. $obj = new $class();
  620. $response = $this->info();
  621. if($response->isError()) {
  622. $obj->__Error = $response->getResult();
  623. return $obj;
  624. }
  625. $info = $response->getResult()['body'];
  626. if(!$info) {
  627. return $obj;
  628. }
  629. foreach ($info as $key => $val) {
  630. $key = $this->entity()->convertToProperty($key);
  631. $obj->$key = $val;
  632. }
  633. return $obj;
  634. }
  635. /**
  636. * get 是否返回了错误
  637. *
  638. * @return bool
  639. */
  640. public function isError() {
  641. if(isset($this->__Error)) {
  642. return true;
  643. }
  644. return false;
  645. }
  646. /**
  647. * get 返回的code
  648. *
  649. * @return int
  650. */
  651. public function getCode() {
  652. if(!$this->isError()) {
  653. return 0;
  654. }
  655. return isset($this->__Error['code']) ? $this->__Error['code'] : 0;
  656. }
  657. /**
  658. * get 返回的msg
  659. *
  660. * @return string
  661. */
  662. public function getMessage() {
  663. if(!$this->isError()) {
  664. return '';
  665. }
  666. return isset($this->__Error['msg']) ? $this->__Error['msg'] : '';
  667. }
  668. /**
  669. * 与get不同的这个返回的是Response
  670. *
  671. * @return mixed|Response
  672. */
  673. public function info() {
  674. try{
  675. $query = $this->createQuery();
  676. $info = $query->selectRow($this->prepareTable());
  677. $this->calledSQL = $query->modelSQL;
  678. if($info) $this->withRow($info);
  679. return Response::Success(static::class .'::'. __FUNCTION__,
  680. [
  681. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => '获取成功', 'body' => $info]
  682. ]
  683. );
  684. }catch (\Exception $e) {
  685. return Response::Fail(static::class .'::'. __FUNCTION__,
  686. [
  687. '_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' =>$e->getMessage(), 'body' => []],
  688. 'message' => $e->getMessage()
  689. ]
  690. );
  691. }
  692. }
  693. /**
  694. * 将表对象对应的字段转换成array
  695. *
  696. * @return array
  697. */
  698. public function toArray($returnFields = false)
  699. {
  700. $arr = [];
  701. $method = new \ReflectionClass($this);
  702. $vars = [];
  703. foreach ($this as $k => $t) {
  704. if(preg_match("/^[A-Z]+/", $k)) {
  705. $vars[] = $k;
  706. }
  707. }
  708. $fields = $this->fields();
  709. if(count($fields)) {
  710. if($returnFields) {
  711. foreach ($fields as $key => $value) {
  712. $arr['__fields__'][$key] = $value;
  713. }
  714. }
  715. foreach ($vars as $extra) {
  716. if(!isset($arr[$extra])) {
  717. $field = $this->entity()->convertToField($extra);
  718. if(isset($this->$extra)) $arr[$field] = $this->$extra;
  719. }
  720. }
  721. return $arr;
  722. }
  723. $properties = $method->getproperties();
  724. foreach($properties as $property) {
  725. if($property->isPublic() && !$property->isStatic()) {
  726. $name = $property->getName();
  727. $field = $this->entity()->convertToField($name);
  728. if(isset($this->$name)) $arr[$field] = $this->$name;
  729. continue;
  730. }
  731. //移除非public的变量
  732. $i = array_search($property->getName(), $vars);
  733. if($i !== false) {
  734. array_splice($vars, $i, 1);
  735. }
  736. }
  737. foreach ($vars as $extra) {
  738. if(!isset($arr[$extra])) {
  739. $field = $this->entity()->convertToField($extra);
  740. if(isset($this->$extra)) $arr[$field] = $this->$extra;
  741. }
  742. }
  743. return $arr;
  744. }
  745. /**
  746. * 是否相关数据存在
  747. *
  748. * @return bool
  749. */
  750. public function exist() {
  751. $where = $this->getWhereHooker();
  752. if(!$where) {
  753. return false;
  754. }
  755. return (bool) $this->db()->where($where)->selectOne($this->prepareTable());
  756. }
  757. /**
  758. * 保存数据
  759. *
  760. * @return mixed|Qii\Driver\Response
  761. * @throws \Exception
  762. */
  763. public function add() {
  764. $valid = $this->validFieldsForAdd();
  765. if($valid->isError()) {
  766. return $valid;
  767. }
  768. //如果设置了 unique 就先验证唯一性
  769. list($uniqueWhere, $uniqueOr, $exclude, $primary) = $this->condition();
  770. unset($exclude);
  771. //如果 $where $or 为空,看看主键是否有设置值,有设置值说明验证主键就可以,反之设置了主键,主键值设置了,只验证主键就可以了
  772. if(count($primary) > 0) {
  773. $exist = $this->db()->limit(1)->where($primary)->selectRow($this->prepareTable());
  774. if($exist) {
  775. return Response::Exist(static::class .'::'. __FUNCTION__,
  776. [
  777. '_result' => ['code' => Response::DOES_EXIST, 'msg' => '数据已经存在', 'body' => $exist],
  778. 'message' => '数据已经存在'
  779. ]
  780. );
  781. }
  782. }
  783. if(count($uniqueWhere) > 0 || count($uniqueOr) > 0) {
  784. $exist = $this->db()->limit(1)->where($uniqueWhere)->orTerms($uniqueOr)->selectRow($this->prepareTable());
  785. if($exist) {
  786. return Response::Exist(static::class .'::'. __FUNCTION__,
  787. [
  788. '_result' => ['code' => Response::DOES_EXIST, 'msg' => '数据已经存在', 'body' => $exist],
  789. 'message' => '数据已存在'
  790. ]
  791. );
  792. }
  793. }
  794. $values = array_merge($this->getDefaultValue(), $this->properties());
  795. $res = $this->db()->insertObject($this->prepareTable(), $values);
  796. if($this->db()->isError()) {
  797. return Response::FailSave(static::class .'::'. __FUNCTION__,
  798. [
  799. '_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => []],
  800. 'message' => $this->db()->getMessage()
  801. ]);
  802. }
  803. return Response::Success(static::class .'::'. __FUNCTION__,
  804. [
  805. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => '添加成功', 'body' => $res]
  806. ]
  807. );
  808. }
  809. /**
  810. * 删除指定数据
  811. *
  812. * @return false|Response
  813. */
  814. public function remove() {
  815. if(!$this->properties()) {
  816. return Response::Fail(static::class .'::'. __FUNCTION__,
  817. [
  818. '_result' => ['code' => Response::FAIL_FOR_VALIDATE, 'msg' => '未指定删除目标', 'body' => []],
  819. 'message' => '未指定删除目标'
  820. ]
  821. );
  822. }
  823. $properties = [];
  824. foreach ($this->properties() as $key => $val) {
  825. $properties[] = $this->entity()->convertToProperty($key);
  826. }
  827. $valid = $this->valid($properties);
  828. if($valid->isError()) {
  829. return $valid;
  830. }
  831. $query = $this->createQuery();
  832. $affectedRows = $query->delete($this->prepareTable());
  833. if($this->db()->isError()) {
  834. return Response::FailSave(static::class .'::'. __FUNCTION__,
  835. [
  836. '_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => []],
  837. 'message' => $this->db()->getMessage()
  838. ]
  839. );
  840. }
  841. return Response::Success(static::class .'::'. __FUNCTION__,
  842. [
  843. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => '删除成功,总共删除了'. $affectedRows . '条记录', 'body' => $affectedRows],
  844. 'message' => '删除成功,总共删除了'. $affectedRows . '条记录'
  845. ]
  846. );
  847. }
  848. /**
  849. * 更新
  850. *
  851. * @return mixed | Response
  852. * @throws \Exception
  853. */
  854. public function update(){
  855. $valid = $this->validFieldsForUpdate();
  856. if($valid->isError()) {
  857. return $valid;
  858. }
  859. //检查是否有重复的
  860. list($uniqueWhere, $uniqueOr, $exclude, $primaryKey) = $this->condition();
  861. // 检查 unique 是否已经存在相关数据
  862. $diffWhere = array_diff_assoc($uniqueWhere, $primaryKey);
  863. $diffOr = array_diff_assoc($uniqueOr, $primaryKey);
  864. /*print_r(
  865. [
  866. 'where' => $uniqueWhere,
  867. 'or' => $uniqueOr,
  868. 'exclude' => $exclude,
  869. 'primary' => $primaryKey
  870. ]
  871. );*/
  872. /*$diffExclude = array_diff_assoc($exclude, $primaryKey);
  873. print_r(
  874. [
  875. 'diffWhere' => $diffWhere,
  876. 'diffOr' => $diffOr,
  877. 'diffExclude' => $diffExclude
  878. ]
  879. );*/
  880. if(count($diffWhere) > 0 || count($diffOr) > 0) {
  881. $unique = $this->db()->limit(1)->where($diffWhere)->orTerms($diffOr)->exclude($exclude)->selectRow($this->prepareTable());
  882. if($unique) {
  883. return Response::Exist(static::class .'::'. __FUNCTION__,
  884. ['_result' => ['code' => Response::DOES_EXIST, 'msg' => '已经存在相关记录', 'body' => $unique]]
  885. );
  886. }
  887. }
  888. //检查更新的数据是否存在,以主键为主
  889. $exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->prepareTable());
  890. if($exit === null || $exit === false) {
  891. return Response::NotExist(static::class .'::'. __FUNCTION__,
  892. ['_result' => ['code' => Response::DOES_NOT_EXIST, 'msg' => '未找到相关记录', 'body' => []]]
  893. );
  894. }
  895. //获取默认值
  896. //更新的时候不使用默认值
  897. //$values = array_merge($this->getDefaultValue(), $this->properties());
  898. $affectedRows = $this->db()->updateObject($this->prepareTable(), $this->properties(), $primaryKey);
  899. if($this->db()->isError()) {
  900. return Response::FailUpdate(static::class .'::'. __FUNCTION__,
  901. [
  902. '_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []]
  903. ]
  904. );
  905. }
  906. return Response::Success(static::class .'::'. __FUNCTION__,
  907. [
  908. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => '数据更新成功,总共更新了'. $affectedRows . '条记录', 'body' => $affectedRows],
  909. 'message' => '数据更新成功,总共更新了'. $affectedRows . '条记录'
  910. ]
  911. );
  912. }
  913. /**
  914. * 更新字段
  915. *
  916. * @return mixed| Response
  917. * @throws \Exception
  918. */
  919. public function updateFields() {
  920. $properties = $this->properties();
  921. $fields = $this->entity()->convertToProperties(array_keys($properties));
  922. $valid = $this->valid($fields);
  923. if($valid->isError()) {
  924. return $valid;
  925. }
  926. list($uniqueWhere, $uniqueOr, $exclude, $primaryKey) = $this->condition();
  927. /*print_r(
  928. [
  929. 'where' => $uniqueWhere,
  930. 'or' => $uniqueOr,
  931. 'exclude' => $exclude,
  932. 'primary' => $primaryKey
  933. ]
  934. );*/
  935. // 检查 unique 是否已经存在相关数据
  936. $diffWhere = array_diff_assoc($uniqueWhere, $primaryKey);
  937. $diffOr = array_diff_assoc($uniqueOr, $primaryKey);
  938. /*$diffExclude = array_diff_assoc($exclude, $primaryKey);
  939. print_r(
  940. [
  941. 'diffWhere' => $diffWhere,
  942. 'diffOr' => $diffOr,
  943. 'diffExclude' => $diffExclude
  944. ]
  945. );*/
  946. if(count($diffWhere) > 0 || count($diffOr) > 0) {
  947. $unique = $this->db()->limit(1)->where($diffWhere)->orTerms($diffOr)->exclude($exclude)->selectRow($this->prepareTable());
  948. if($unique) {
  949. return Response::Exist(static::class .'::'. __FUNCTION__,
  950. ['_result' => ['code' => Response::DOES_EXIST, 'msg' => '已经存在相关记录', 'body' => $unique]]
  951. );
  952. }
  953. }
  954. //检查更新的数据是否存在,以主键为主
  955. $exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->prepareTable());
  956. if($exit === null || $exit === false) {
  957. return Response::NotExist(static::class .'::'. __FUNCTION__,
  958. [
  959. '_result' => ['code' => Response::DOES_NOT_EXIST, 'msg' => '未找到相关记录', 'body' => []],
  960. 'message' => '未找到相关记录'
  961. ]
  962. );
  963. }
  964. //获取默认值
  965. //更新的时候不使用默认值
  966. //$values = array_merge($this->getDefaultValue(), $this->properties());
  967. $affectedRows = $this->db()->updateObject($this->prepareTable(), $this->properties(), $primaryKey);
  968. if($this->db()->isError()) {
  969. return Response::FailUpdate(static::class .'::'. __FUNCTION__,
  970. [
  971. '_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []],
  972. 'message' => $this->db()->getMessage()
  973. ]
  974. );
  975. }
  976. return Response::Success(static::class .'::'. __FUNCTION__,
  977. [
  978. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => '数据更新成功', 'body' => $affectedRows]
  979. ]
  980. );
  981. }
  982. /**
  983. * 增加或减少某一个字段的值
  984. *
  985. * @return mixed|Response
  986. * @throws \Exception
  987. */
  988. public function incr() {
  989. list($where, $or, $exclude, $primary) = $this->condition();
  990. unset($where, $or, $exclude);
  991. $property = $this->properties();
  992. $incr = [];
  993. foreach ($property as $key => $value) {
  994. if(!is_numeric($value)) {
  995. continue;
  996. }
  997. $incr[$key] = $value;
  998. }
  999. $diff = array_diff_assoc($incr, $primary);
  1000. if(count($diff) == 0) {
  1001. return Response::Fail(self::class .'::'. __FUNCTION__,
  1002. [
  1003. '_result' => ['code' => Response::DO_FAIL, 'msg' => 'INCR 参数错误'],
  1004. 'message' => 'INCR 参数错误',
  1005. ]
  1006. );
  1007. }
  1008. $sets = [];
  1009. foreach ($diff as $key => $val) {
  1010. if($val == 0) {
  1011. $sets[$key] = $val;
  1012. }else if($val > 0) {
  1013. $sets[$key . ':plus'] = $val;
  1014. }else if($val < 0) {
  1015. $sets[$key . ':minus'] = $val * -1;
  1016. }
  1017. }
  1018. $affectedRows = $this->db()->set($sets)->where($primary)->update($this->prepareTable());
  1019. if($this->db()->isError()) {
  1020. return Response::FailUpdate(static::class .'::'. __FUNCTION__,
  1021. [
  1022. '_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []],
  1023. 'message' => $this->db()->getMessage()
  1024. ]
  1025. );
  1026. }
  1027. return Response::Success(static::class .'::'. __FUNCTION__,
  1028. [
  1029. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => 'INCR 成功', 'body' => $affectedRows]
  1030. ]
  1031. );
  1032. }
  1033. /**
  1034. * 获取fields
  1035. *
  1036. * @return false|mixed|string|string[]
  1037. */
  1038. public function getFields() {
  1039. $fields = $this->getFieldsHooker();
  1040. if(!is_array($fields)) {
  1041. $fields = explode(',', str_replace(" ", "", $fields));
  1042. }
  1043. return $fields;
  1044. }
  1045. /**
  1046. * 获取where及or条件并创建查询条件
  1047. *
  1048. * @return \Qii\Driver\Base
  1049. */
  1050. public function createQuery($fields = []) {
  1051. if(empty($fields)) {
  1052. $fields = $this->getFields();
  1053. }
  1054. $query = $this->db()->fields($fields)->where($this->getWhereHooker())->fetchSql($this->calledSQL);
  1055. $or = $this->getOrHooker();
  1056. foreach ($or as $v) {
  1057. $query = $query->orTerms($v);
  1058. }
  1059. $join = $this->getJoinHooker();
  1060. foreach ($join as $j) {
  1061. $query = $query->join($j);
  1062. }
  1063. return $query;
  1064. }
  1065. /**
  1066. * 获取第一条数据
  1067. *
  1068. * @return mixed|Response
  1069. * @throws \Exception
  1070. */
  1071. public function first() {
  1072. $orderBy = $this->getOrderBy();
  1073. foreach ($orderBy as $key => $value) {
  1074. $orderBy[$key] = 'ASC';
  1075. }
  1076. $query = $this->createQuery();
  1077. $row = $query->limit(1)->orderBy($orderBy)->selectRow($this->prepareTable());
  1078. if($this->db()->isError()) {
  1079. return Response::Fail(static::class .'::'. __FUNCTION__,
  1080. [
  1081. '_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => 'Query 失败' . $this->db()->getMessage(), 'body' => []],
  1082. 'message' => $this->db()->getMessage()
  1083. ]
  1084. );
  1085. }
  1086. if($row) {
  1087. $this->withRow($row);
  1088. }
  1089. return Response::Success(static::class .'::'. __FUNCTION__,
  1090. [
  1091. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => 'Query 成功', 'body' => $row]
  1092. ]
  1093. );
  1094. }
  1095. /**
  1096. * 获取第一条数据
  1097. *
  1098. * @return mixed|Response
  1099. * @throws \Exception
  1100. */
  1101. public function last() {
  1102. $orderBy = $this->getOrderBy();
  1103. foreach ($orderBy as $key => $value) {
  1104. $orderBy[$key] = 'DESC';
  1105. }
  1106. $query = $this->createQuery();
  1107. $row = $query->orderBy($orderBy)->limit(1)->selectRow($this->prepareTable());
  1108. $this->calledSQL = $query->modelSQL;
  1109. if($this->db()->isError()) {
  1110. return Response::Fail(static::class .'::'. __FUNCTION__,
  1111. [
  1112. '_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => 'Query 失败', 'body' => []],
  1113. 'messsage' => $this->db()->getMessage()
  1114. ]
  1115. );
  1116. }
  1117. if($row) {
  1118. $this->withRow($row);
  1119. }
  1120. return Response::Success(static::class .'::'. __FUNCTION__,
  1121. [
  1122. '_result' => ['code' => Response::DO_SUCCESS, 'msg' => 'Query 成功', 'body' => $row]
  1123. ]
  1124. );
  1125. }
  1126. /**
  1127. * 附带一行数据
  1128. *
  1129. * @param $row
  1130. * @return void
  1131. */
  1132. public function withRow(&$row) {
  1133. if(!is_array($row)) {
  1134. return;
  1135. }
  1136. $hooks = $this->getWithHooker();
  1137. foreach ($hooks as $with) {
  1138. if(!is_array($with) || count($with) < 5 || !is_object($with[0])) {
  1139. continue;
  1140. }
  1141. $callable = $with[0];
  1142. $relField = $with[1];
  1143. $method = $with[2];
  1144. $foreignKey = $with[3];
  1145. $associationForeignkey = $with[4];
  1146. $fields = [];
  1147. if(count($with) >= 6) {
  1148. $fields = $with[5];
  1149. }
  1150. $row[$relField] = [];
  1151. if(!isset($row[$foreignKey])) {
  1152. continue;
  1153. }
  1154. $params = [
  1155. $associationForeignkey,
  1156. [$associationForeignkey => $row[$foreignKey]],
  1157. $fields
  1158. ];
  1159. $res = call_user_func_array(array($callable, $method), $params);
  1160. if($res && isset($res[$row[$foreignKey]])) {
  1161. $row[$relField] = $res[$row[$foreignKey]];
  1162. }
  1163. }
  1164. }
  1165. /**
  1166. * 返回游标
  1167. *
  1168. * @param int | null $page 页码
  1169. * @param int | null $pageSize 页大小
  1170. * @return mixed
  1171. * @throws \Qii\Exceptions\InvalidParams
  1172. */
  1173. public function rs($page = null, $pageSize = null) {
  1174. $query = $this->createQuery()->orderBy($this->getOrderBy());
  1175. if($page && $pageSize) {
  1176. $query->limit($page, $pageSize);
  1177. }
  1178. return $query->rs($this->prepareTable());
  1179. }
  1180. /**
  1181. * listts
  1182. * @param int $page 页码
  1183. * @param int $pageSize 页大小
  1184. * @return array
  1185. * @throws \Exception
  1186. */
  1187. public function lists($page = 1, $pageSize = 20) {
  1188. $count = $this->count();
  1189. if(!$this->initPages($data, $count, $page, $pageSize)) {
  1190. return $data;
  1191. }
  1192. $query = $this->createQuery();
  1193. $lists = $query->orderBy($this->getOrderBy())->limit($data['pages']['limitStart'], $pageSize)->selectRows($this->prepareTable());
  1194. $this->withList($lists);
  1195. $data['lists'] = $lists;
  1196. return $data;
  1197. }
  1198. /**
  1199. * 附带一行数据
  1200. *
  1201. * @param array $lists
  1202. * @return void
  1203. */
  1204. public function withList(&$lists) {
  1205. if(!is_array($lists)) {
  1206. return;
  1207. }
  1208. $hooks = $this->getWithHooker();
  1209. foreach ($hooks as $with) {
  1210. if(!is_array($with) || count($with) < 5 || !is_object($with[0])) {
  1211. continue;
  1212. }
  1213. $callable = $with[0];
  1214. $relField = $with[1];
  1215. $method = $with[2];
  1216. $foreignKey = $with[3];
  1217. $associationForeignkey = $with[4];
  1218. $fields = [];
  1219. if(count($with) == 6) {
  1220. $fields = $with[5];
  1221. }
  1222. $rel = [];
  1223. foreach ($lists as $v1) {
  1224. if(isset($v1[$foreignKey])) {
  1225. $rel[] = $v1[$foreignKey];
  1226. }
  1227. }
  1228. // [rel key, where]
  1229. $params = [
  1230. $associationForeignkey,
  1231. [$associationForeignkey . ':in' => array_unique($rel)],
  1232. $fields
  1233. ];
  1234. $res = call_user_func_array(array($callable, $method), $params);
  1235. foreach ($lists as &$v) {
  1236. if(isset($res[$v[$foreignKey]])) {
  1237. $v[$relField] = $res[$v[$foreignKey]];
  1238. }
  1239. }
  1240. }
  1241. }
  1242. /**
  1243. * 关联查询 has one
  1244. * params[rel_key, where, fields]
  1245. *
  1246. * @return array
  1247. * @throws \Exception
  1248. */
  1249. public function hasOne() {
  1250. $args = func_get_args();
  1251. $relKey = $args[0];
  1252. $fields = [];
  1253. if(count($args) == 3 && !empty($args[2])) {
  1254. $fields = $args[2];
  1255. if(!in_array($relKey, $fields)) $fields[] = $relKey;
  1256. }
  1257. if(count($fields) == 0) {
  1258. $fields = $this->getFields();
  1259. }
  1260. if(count($this->getFields()) > 0 && !in_array($relKey, $this->getFields())) {
  1261. $fields[] = $relKey;
  1262. }
  1263. $fields = array_unique($fields);
  1264. $query = $this->createQuery($fields);
  1265. $res = $query->where($args[1])->rs($this->prepareTable());
  1266. $rows = [];
  1267. foreach($res as $v) {
  1268. $rows[$v[$relKey]] = $v;
  1269. }
  1270. return $rows;
  1271. }
  1272. /**
  1273. * 关联查询
  1274. * params[rel_key, where, fields]
  1275. *
  1276. * @return array
  1277. * @throws \Exception
  1278. */
  1279. public function hasMany()
  1280. {
  1281. $args = func_get_args();
  1282. $relKey = $args[0];
  1283. $fields = [];
  1284. if(count($args) == 3 && !empty($args[2])) {
  1285. $fields = $args[2];
  1286. if(!in_array($relKey, $fields)) $fields[] = $relKey;
  1287. }
  1288. if(count($fields) == 0) {
  1289. $fields = $this->getFields();
  1290. }
  1291. if(count($this->getFields()) > 0 && !in_array($relKey, $this->getFields())) {
  1292. $fields[] = $relKey;
  1293. }
  1294. if(array_search('*', $fields) !== false) {
  1295. $fields = ['*'];
  1296. }
  1297. $query = $this->createQuery($fields);
  1298. $res = $query->where($args[1])->rs($this->prepareTable());
  1299. $rows = [];
  1300. foreach($res as $v) {
  1301. $rows[$v[$relKey]][] = $v;
  1302. }
  1303. return $rows;
  1304. }
  1305. /**
  1306. * 获取所有数据,这里不分页,但支持限条数,通过 setLimitHooker来实现
  1307. * $this->setLimitHooker(function(){
  1308. * return [x,y];//从第x条开始获取y条; return [1];//获取一条 return [0];//获取所有的
  1309. * });
  1310. * @return mixed
  1311. * @throws \Exception
  1312. */
  1313. public function listAll() {
  1314. $limit = $this->getLimitHooker();
  1315. $query = $this->createQuery()->orderBy($this->getOrderBy());
  1316. if(empty($limit) || !is_array($limit)) {
  1317. $list = $query
  1318. ->selectRows($this->prepareTable());
  1319. $this->withList($list);
  1320. return $list;
  1321. }
  1322. if(count($limit) == 1) {
  1323. $list = $query->limit($limit[0])->selectRows($this->prepareTable());
  1324. $this->withList($list);
  1325. return $list;
  1326. }
  1327. $list = $query
  1328. ->limit($limit[0], $limit[1])->selectRows($this->prepareTable());
  1329. $this->withList($list);
  1330. return $list;
  1331. }
  1332. /**
  1333. * 验证相关字段
  1334. *
  1335. * @param array $fields 字段列表
  1336. * @return Response
  1337. */
  1338. public function valid($fields = array()) {
  1339. if(!is_array($fields)) {
  1340. return Response::FailValidate(static::class .'::'. __FUNCTION__,
  1341. [
  1342. '_result' => ['code' => Response::FAIL_FOR_VALIDATE, 'msg' => '字段必须是数组', 'fields' => []],
  1343. 'message' => '字段必须是数组'
  1344. ]
  1345. );
  1346. }
  1347. $rules = $this->rules();
  1348. $result = [];
  1349. $invalidKey = [];
  1350. $values = array_merge($this->getDefaultValue(), $this->properties());
  1351. foreach ($rules as $valid => $rule) {
  1352. foreach ($rule as $val) {
  1353. $key = $this->entity()->convertToProperty($val[0]);
  1354. if(!in_array($key, $fields)) {
  1355. continue;
  1356. }
  1357. $field = $this->entity()->convertToField($key);
  1358. $verify = new Verify($val[0], $values[$field] ?? null, strtolower($valid), $val[1], $val[2] ?? '');
  1359. $res = $verify->valid();
  1360. if($res->isError()) {
  1361. $result[] = $res->getResult() .',获取的是'. ($values[$field] ?? '空');
  1362. if(!in_array($field, $invalidKey)) {
  1363. $invalidKey[] = $field;
  1364. }
  1365. }
  1366. }
  1367. }
  1368. if(count($result) > 0) {
  1369. return Response::FailValidate(static::class .'::'. __FUNCTION__,
  1370. [
  1371. '_result' => ['code' => Response::FAIL_FOR_VALIDATE, 'msg' => $result, 'fields' => $invalidKey],
  1372. 'message' => join("\n", $result)
  1373. ]
  1374. );
  1375. }
  1376. return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
  1377. }
  1378. /**
  1379. * 合并多个 valid 结果 $this->valids($this->valid(['Uid']), $this->valid(['Nickname', 'Email']));
  1380. * @param ...
  1381. * @return mixed|Response
  1382. * @throws \Exception
  1383. */
  1384. public function valids() {
  1385. $validArr = func_get_args();
  1386. if(count($validArr) == 0) {
  1387. return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
  1388. }
  1389. if(count($validArr) == 1) {
  1390. return $validArr[0];
  1391. }
  1392. $invalid = array();
  1393. $invalid['message'] = array();
  1394. $invalid['fields'] = array();
  1395. foreach ($validArr as $valid) {
  1396. if(!($valid instanceof Response)) {
  1397. throw new \Exception('验证结果类型必须是\Qii\Driver\Response类型');
  1398. }
  1399. if($valid->isError()) {
  1400. $result = $valid->getResult();
  1401. $invalid['message'] = array_merge($invalid['message'], $result['message']);
  1402. $invalid['fields'] = array_merge($invalid['fields'], $result['fields']);;
  1403. }
  1404. }
  1405. if(count($invalid['message']) > 0) {
  1406. return Response::Fail(static::class .'::'. __FUNCTION__, [
  1407. '_result' => ['message' => $invalid['message'], 'fields' => $invalid['fields']],
  1408. 'message' => $invalid['message']
  1409. ]);
  1410. }
  1411. return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
  1412. }
  1413. /**
  1414. * unique 条件
  1415. *
  1416. * @return array[]
  1417. * @throws \Exception
  1418. */
  1419. protected function uniqueCondition() {
  1420. $uniqueWhere = [];
  1421. $uniqueOr = [];
  1422. $unique = $this->uniqueKey();
  1423. $useWhere = true;
  1424. if(!is_array($unique)) {
  1425. $unique = $this->explode(',', $unique);
  1426. $useWhere = false;
  1427. if(count($unique) == 1) {
  1428. $useWhere = true;
  1429. }
  1430. }
  1431. foreach ($unique as $key) {
  1432. $key = $this->entity()->convertToField($key);
  1433. $property = $this->entity()->convertToProperty($key);
  1434. if($useWhere) {
  1435. $uniqueWhere[$key] = $this->$property;
  1436. }else{
  1437. $uniqueOr[$key] = $this->$property;
  1438. }
  1439. }
  1440. return [$uniqueWhere, $uniqueOr];
  1441. }
  1442. /**
  1443. * exclude Condition
  1444. *
  1445. * @return array
  1446. */
  1447. protected function excludeCondition() {
  1448. if(is_array($this->exclude())) {
  1449. $exclude = $this->exclude();
  1450. }else{
  1451. $exclude = (array) $this->explode(',', $this->exclude());
  1452. }
  1453. $excludeCondition = [];
  1454. foreach ($exclude as $key) {
  1455. $field = $this->entity()->convertToField($key);
  1456. $property = $this->entity()->convertToProperty($key);
  1457. $excludeCondition[$field] = $this->$property;
  1458. }
  1459. return $excludeCondition;
  1460. }
  1461. /**
  1462. * 主键
  1463. *
  1464. * @return array
  1465. * @throws \Exception
  1466. */
  1467. protected function primaryCondition(){
  1468. $primary = array();
  1469. $primaryKey = $this->primaryKey();
  1470. if(!is_array($primaryKey)) {
  1471. $primaryKey = $this->explode(',', $primaryKey);
  1472. }
  1473. foreach ($primaryKey as $key) {
  1474. $key = $this->entity()->convertToProperty($key);
  1475. $field = $this->entity()->convertToField($key);
  1476. $value = $this->$key;
  1477. $primary[$field] = $value;
  1478. }
  1479. return $primary;
  1480. }
  1481. /**
  1482. * 获取查询条件
  1483. *
  1484. * @return array [$uniqueWhere, $uniqueOr, $excludeCondition, $primaryCondition]
  1485. */
  1486. public function condition() {
  1487. //如果设置了 unique 就先验证唯一性,保存的时候验证 uniqueKey,更新的时候验证uniqueKey并排primaryKey
  1488. //保存数据的时候验证uniqueKey;更新时验证 uniqueKey,并且排除 primaryKey,如果uniqueKey == primaryKey则不去做唯一性验证
  1489. list($uniqueWhere, $uniqueOr) = $this->uniqueCondition();
  1490. $excludeCondition = $this->excludeCondition();
  1491. $primaryCondition = $this->primaryCondition();
  1492. return [$uniqueWhere, $uniqueOr, $excludeCondition, $primaryCondition];
  1493. }
  1494. /**
  1495. * 获取order by
  1496. *
  1497. * @return array
  1498. */
  1499. public function getOrderBy() {
  1500. $order = array();
  1501. $orderBy = $this->orderBy();
  1502. if(isset($this->hooker['order']) && is_callable($this->hooker['order']['func'])) {
  1503. $orderBy = call_user_func($this->hooker['order']['func'], $order, $this->hooker['order']['args']);
  1504. }
  1505. foreach ($orderBy as $key => $val) {
  1506. $field = $this->entity()->convertToField($key);
  1507. if($this->alias != "" && strpos($field, '.') === false) {
  1508. $field = $this->alias . '.' . $field;
  1509. }
  1510. $val = strtoupper($val);
  1511. if(!in_array($val, array('DESC', 'ASC'))) {
  1512. continue;
  1513. }
  1514. $order[$field] = $val;
  1515. }
  1516. return $order;
  1517. }
  1518. /**
  1519. * 初始化page
  1520. * @param array $data 返回的数据
  1521. * @param int $count 总数量
  1522. * @param int $page 页码
  1523. * @param int $pageSize 显示数量
  1524. * @param int $pagination 分页显示最多页码
  1525. * @return bool
  1526. */
  1527. public function initPages(&$data, $count, $page, $pageSize = 20, $pagination = 5) {
  1528. $page = max(1, $page);
  1529. $pageSize = max(1, $pageSize);
  1530. $data['start'] = 0;
  1531. $data['pages'] = array('total' => 0, 'currentPage' => 0, 'totalPage' => 0);
  1532. $data['pages']['total'] = (int) ($count ? $count : 0);
  1533. $data['pages']['currentPage'] = $page;
  1534. $data['pages']['totalPage'] = ceil($data['pages']['total'] / $pageSize);
  1535. $data['lists'] = array();
  1536. if ($data['pages']['currentPage'] > $data['pages']['totalPage']) {
  1537. return false;
  1538. }
  1539. $pagination = min($pagination, $data['pages']['totalPage']);
  1540. if($data['pages']['currentPage'] - floor($pagination / 2) <= 0) {
  1541. $frames['left'] = 1;
  1542. $frames['right'] = $frames['left'] + $pagination - 1;
  1543. } else if($data['pages']['currentPage'] + floor($pagination / 2) >= $data['pages']['totalPage']) {
  1544. $frames['right'] = $data['pages']['totalPage'];
  1545. $frames['left'] = $frames['right'] - $pagination + 1;
  1546. } else {
  1547. $frames['left'] = $data['pages']['currentPage'] - floor($pagination / 2);
  1548. $frames['right'] = $data['pages']['currentPage'] + ceil($pagination / 2) - 1;
  1549. }
  1550. $data['start'] = $frames['left'];
  1551. $data['pages']['start'] = $data['start'];
  1552. $data['pages']['end'] = $frames['right'];
  1553. $data['pages']['pagination'] = $pagination;
  1554. $data['pages']['limitStart'] = (min($page, $data['pages']['totalPage']) - 1) * $pageSize;
  1555. $data['pages']['pageSize'] = (int) $pageSize;
  1556. return true;
  1557. }
  1558. /**
  1559. * response as object
  1560. *
  1561. * @return mixed|Response
  1562. */
  1563. public function response() {
  1564. $properties = $this->properties();
  1565. if(!$properties) {
  1566. return Response::Fail(static::class .'::'. __FUNCTION__,
  1567. ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => '未找到相关数据', 'body' => []]
  1568. ]
  1569. );
  1570. }
  1571. return Response::Success(static::class .'::'. __FUNCTION__,
  1572. ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '获取成功', 'body' => $properties]]
  1573. );
  1574. }
  1575. /**
  1576. * 方法名 + ByCache/ByRedis/ByMemcache/会将结果缓存,这里使用的缓存类是通过hooker设置的,否则使用对应的
  1577. * ByClean 则会移除当前缓存, 默认转发到 db model上
  1578. * @param string $method method
  1579. * @param array $args
  1580. * @return mixed
  1581. */
  1582. public function __call($method, $args) {
  1583. $cache = '';
  1584. preg_match("/(byredis|bymemcache|bycache|byclean)$/i", $method, $matches);
  1585. if($matches && count($matches) > 0) {
  1586. $cache = strtolower($matches[0]);
  1587. }
  1588. if($cache && in_array($cache, ['bymemcache', 'byredis', 'bycache', 'byclean'])){
  1589. list($func, $cacheID, $config) = $this->getCacheHooker();
  1590. $policy = $this->getCacheConfig();
  1591. if($func == null) {
  1592. $func = $cache == 'bymemcache' ? $this->db()->setCache('memcached', $policy) : $this->db()->setCache('redis', $policy);
  1593. }
  1594. $method = substr($method, 0, strlen($cache) * -1);
  1595. if (method_exists($this, $method)) {
  1596. $key = get_called_class() .':'. $method .':'. substr(md5(serialize($this->properties())), -16);
  1597. if($cache == 'byclean') {
  1598. return $func->del($key);
  1599. }
  1600. if(is_object($func) && method_exists($func, 'get')) {
  1601. $res = $func->get($key);
  1602. if ($res) {
  1603. return unserialize($res);
  1604. }
  1605. }
  1606. $expiredAt = isset($config['life_time']) ? (int) $config['life_time'] :
  1607. ($policy['life_time'] ?? $this->defaultExpired);
  1608. $res = call_user_func_array(array($this, $method), $args);
  1609. $str = serialize($res);
  1610. $func->set($key, $str, ['life_time' => $expiredAt]);
  1611. return $res;
  1612. }
  1613. }
  1614. return call_user_func_array(array($this->db(), $method), $args);
  1615. }
  1616. /**
  1617. * 开始事务
  1618. *
  1619. * @return mixed
  1620. */
  1621. public function startTrans() {
  1622. return $this->db()->transaction();
  1623. }
  1624. /**
  1625. * 提交事务
  1626. *
  1627. * @return mixed
  1628. */
  1629. public function commit() {
  1630. return $this->db()->commit();
  1631. }
  1632. /**
  1633. * 回退
  1634. *
  1635. * @return mixed
  1636. */
  1637. public function rollback() {
  1638. return $this->db()->rollback();
  1639. }
  1640. /**
  1641. * 验证规则,由子类继承去修改
  1642. *
  1643. * @return array
  1644. */
  1645. public function rules()
  1646. {
  1647. return [];
  1648. }
  1649. }