Base.php 59 KB

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