Model.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace think;
  12. use InvalidArgumentException;
  13. use think\db\Query;
  14. /**
  15. * Class Model
  16. * @package think
  17. * @mixin Query
  18. */
  19. abstract class Model implements \JsonSerializable, \ArrayAccess
  20. {
  21. use model\concern\Attribute;
  22. use model\concern\RelationShip;
  23. use model\concern\ModelEvent;
  24. use model\concern\TimeStamp;
  25. use model\concern\Conversion;
  26. /**
  27. * 是否存在数据
  28. * @var bool
  29. */
  30. private $exists = false;
  31. /**
  32. * 是否Replace
  33. * @var bool
  34. */
  35. private $replace = false;
  36. /**
  37. * 是否强制更新所有数据
  38. * @var bool
  39. */
  40. private $force = false;
  41. /**
  42. * 更新条件
  43. * @var array
  44. */
  45. private $updateWhere;
  46. /**
  47. * 数据库配置信息
  48. * @var array|string
  49. */
  50. protected $connection = [];
  51. /**
  52. * 数据库查询对象类名
  53. * @var string
  54. */
  55. protected $query;
  56. /**
  57. * 模型名称
  58. * @var string
  59. */
  60. protected $name;
  61. /**
  62. * 数据表名称
  63. * @var string
  64. */
  65. protected $table;
  66. /**
  67. * 写入自动完成定义
  68. * @var array
  69. */
  70. protected $auto = [];
  71. /**
  72. * 新增自动完成定义
  73. * @var array
  74. */
  75. protected $insert = [];
  76. /**
  77. * 更新自动完成定义
  78. * @var array
  79. */
  80. protected $update = [];
  81. /**
  82. * 初始化过的模型.
  83. * @var array
  84. */
  85. protected static $initialized = [];
  86. /**
  87. * 是否从主库读取(主从分布式有效)
  88. * @var array
  89. */
  90. protected static $readMaster;
  91. /**
  92. * 查询对象实例
  93. * @var Query
  94. */
  95. protected $queryInstance;
  96. /**
  97. * 错误信息
  98. * @var mixed
  99. */
  100. protected $error;
  101. /**
  102. * 软删除字段默认值
  103. * @var mixed
  104. */
  105. protected $defaultSoftDelete;
  106. /**
  107. * 架构函数
  108. * @access public
  109. * @param array|object $data 数据
  110. */
  111. public function __construct($data = [])
  112. {
  113. if (is_object($data)) {
  114. $this->data = get_object_vars($data);
  115. } else {
  116. $this->data = $data;
  117. }
  118. if ($this->disuse) {
  119. // 废弃字段
  120. foreach ((array) $this->disuse as $key) {
  121. if (array_key_exists($key, $this->data)) {
  122. unset($this->data[$key]);
  123. }
  124. }
  125. }
  126. // 记录原始数据
  127. $this->origin = $this->data;
  128. $config = Db::getConfig();
  129. if (empty($this->name)) {
  130. // 当前模型名
  131. $name = str_replace('\\', '/', static::class);
  132. $this->name = basename($name);
  133. if (Container::get('config')->get('class_suffix')) {
  134. $suffix = basename(dirname($name));
  135. $this->name = substr($this->name, 0, -strlen($suffix));
  136. }
  137. }
  138. if (is_null($this->autoWriteTimestamp)) {
  139. // 自动写入时间戳
  140. $this->autoWriteTimestamp = $config['auto_timestamp'];
  141. }
  142. if (is_null($this->dateFormat)) {
  143. // 设置时间戳格式
  144. $this->dateFormat = $config['datetime_format'];
  145. }
  146. if (is_null($this->resultSetType)) {
  147. $this->resultSetType = $config['resultset_type'];
  148. }
  149. if (!empty($this->connection) && is_array($this->connection)) {
  150. // 设置模型的数据库连接
  151. $this->connection = array_merge($config, $this->connection);
  152. }
  153. if ($this->observerClass) {
  154. // 注册模型观察者
  155. static::observe($this->observerClass);
  156. }
  157. // 执行初始化操作
  158. $this->initialize();
  159. }
  160. /**
  161. * 获取当前模型名称
  162. * @access public
  163. * @return string
  164. */
  165. public function getName()
  166. {
  167. return $this->name;
  168. }
  169. /**
  170. * 是否从主库读取数据(主从分布有效)
  171. * @access public
  172. * @param bool $all 是否所有模型有效
  173. * @return $this
  174. */
  175. public function readMaster($all = false)
  176. {
  177. $model = $all ? '*' : static::class;
  178. static::$readMaster[$model] = true;
  179. return $this;
  180. }
  181. /**
  182. * 创建新的模型实例
  183. * @access public
  184. * @param array|object $data 数据
  185. * @param bool $isUpdate 是否为更新
  186. * @param mixed $where 更新条件
  187. * @return Model
  188. */
  189. public function newInstance($data = [], $isUpdate = false, $where = null)
  190. {
  191. return (new static($data))->isUpdate($isUpdate, $where);
  192. }
  193. /**
  194. * 创建模型的查询对象
  195. * @access protected
  196. * @return Query
  197. */
  198. protected function buildQuery()
  199. {
  200. // 设置当前模型 确保查询返回模型对象
  201. $query = Db::connect($this->connection, false, $this->query);
  202. $query->model($this)
  203. ->json($this->json)
  204. ->setJsonFieldType($this->jsonType);
  205. if (isset(static::$readMaster['*']) || isset(static::$readMaster[static::class])) {
  206. $query->master(true);
  207. }
  208. // 设置当前数据表和模型名
  209. if (!empty($this->table)) {
  210. $query->table($this->table);
  211. } else {
  212. $query->name($this->name);
  213. }
  214. if (!empty($this->pk)) {
  215. $query->pk($this->pk);
  216. }
  217. return $query;
  218. }
  219. /**
  220. * 获取当前模型的数据库查询对象
  221. * @access public
  222. * @param Query $query 查询对象实例
  223. * @return $this
  224. */
  225. public function setQuery($query)
  226. {
  227. $this->queryInstance = $query;
  228. return $this;
  229. }
  230. /**
  231. * 获取当前模型的数据库查询对象
  232. * @access public
  233. * @param bool $useBaseQuery 是否调用全局查询范围
  234. * @return Query
  235. */
  236. public function db($useBaseQuery = true)
  237. {
  238. if ($this->queryInstance) {
  239. return $this->queryInstance;
  240. }
  241. $query = $this->buildQuery();
  242. // 软删除
  243. if (method_exists($this, 'withNoTrashed')) {
  244. $this->withNoTrashed($query);
  245. }
  246. // 全局作用域
  247. if ($useBaseQuery && method_exists($this, 'base')) {
  248. call_user_func_array([$this, 'base'], [ & $query]);
  249. }
  250. // 返回当前模型的数据库查询对象
  251. return $query;
  252. }
  253. /**
  254. * 初始化模型
  255. * @access protected
  256. * @return void
  257. */
  258. protected function initialize()
  259. {
  260. if (!isset(static::$initialized[static::class])) {
  261. static::$initialized[static::class] = true;
  262. static::init();
  263. }
  264. }
  265. /**
  266. * 初始化处理
  267. * @access protected
  268. * @return void
  269. */
  270. protected static function init()
  271. {}
  272. /**
  273. * 数据自动完成
  274. * @access protected
  275. * @param array $auto 要自动更新的字段列表
  276. * @return void
  277. */
  278. protected function autoCompleteData($auto = [])
  279. {
  280. foreach ($auto as $field => $value) {
  281. if (is_integer($field)) {
  282. $field = $value;
  283. $value = null;
  284. }
  285. if (!isset($this->data[$field])) {
  286. $default = null;
  287. } else {
  288. $default = $this->data[$field];
  289. }
  290. $this->setAttr($field, !is_null($value) ? $value : $default);
  291. }
  292. }
  293. /**
  294. * 更新是否强制写入数据 而不做比较
  295. * @access public
  296. * @param bool $force
  297. * @return $this
  298. */
  299. public function force($force = true)
  300. {
  301. $this->force = $force;
  302. return $this;
  303. }
  304. /**
  305. * 判断force
  306. * @access public
  307. * @return bool
  308. */
  309. public function isForce()
  310. {
  311. return $this->force;
  312. }
  313. /**
  314. * 新增数据是否使用Replace
  315. * @access public
  316. * @param bool $replace
  317. * @return $this
  318. */
  319. public function replace($replace = true)
  320. {
  321. $this->replace = $replace;
  322. return $this;
  323. }
  324. /**
  325. * 设置数据是否存在
  326. * @access public
  327. * @param bool $exists
  328. * @return void
  329. */
  330. public function exists($exists)
  331. {
  332. $this->exists = $exists;
  333. }
  334. /**
  335. * 判断数据是否存在数据库
  336. * @access public
  337. * @return bool
  338. */
  339. public function isExists()
  340. {
  341. return $this->exists;
  342. }
  343. /**
  344. * 保存当前数据对象
  345. * @access public
  346. * @param array $data 数据
  347. * @param array $where 更新条件
  348. * @param string $sequence 自增序列名
  349. * @return bool
  350. */
  351. public function save($data = [], $where = [], $sequence = null)
  352. {
  353. if (is_string($data)) {
  354. $sequence = $data;
  355. $data = [];
  356. }
  357. if (!$this->checkBeforeSave($data, $where)) {
  358. return false;
  359. }
  360. $result = $this->exists ? $this->updateData($where) : $this->insertData($sequence);
  361. if (false === $result) {
  362. return false;
  363. }
  364. // 写入回调
  365. $this->trigger('after_write');
  366. // 重新记录原始数据
  367. $this->origin = $this->data;
  368. return true;
  369. }
  370. /**
  371. * 写入之前检查数据
  372. * @access protected
  373. * @param array $data 数据
  374. * @param array $where 保存条件
  375. * @return bool
  376. */
  377. protected function checkBeforeSave($data, $where)
  378. {
  379. if (!empty($data)) {
  380. // 数据对象赋值
  381. foreach ($data as $key => $value) {
  382. $this->setAttr($key, $value, $data);
  383. }
  384. if (!empty($where)) {
  385. $this->exists = true;
  386. $this->updateWhere = $where;
  387. }
  388. }
  389. // 数据自动完成
  390. $this->autoCompleteData($this->auto);
  391. // 事件回调
  392. if (false === $this->trigger('before_write')) {
  393. return false;
  394. }
  395. return true;
  396. }
  397. /**
  398. * 检查数据是否允许写入
  399. * @access protected
  400. * @param array $append 自动完成的字段列表
  401. * @return array
  402. */
  403. protected function checkAllowFields(array $append = [])
  404. {
  405. // 检测字段
  406. if (empty($this->field) || true === $this->field) {
  407. $query = $this->db(false);
  408. $table = $this->table ?: $query->getTable();
  409. $this->field = $query->getConnection()->getTableFields($table);
  410. $field = $this->field;
  411. } else {
  412. $field = array_merge($this->field, $append);
  413. if ($this->autoWriteTimestamp) {
  414. array_push($field, $this->createTime, $this->updateTime);
  415. }
  416. }
  417. if ($this->disuse) {
  418. // 废弃字段
  419. $field = array_diff($field, (array) $this->disuse);
  420. }
  421. return $field;
  422. }
  423. /**
  424. * 更新写入数据
  425. * @access protected
  426. * @param mixed $where 更新条件
  427. * @return bool
  428. */
  429. protected function updateData($where)
  430. {
  431. // 自动更新
  432. $this->autoCompleteData($this->update);
  433. // 事件回调
  434. if (false === $this->trigger('before_update')) {
  435. return false;
  436. }
  437. // 获取有更新的数据
  438. $data = $this->getChangedData();
  439. if (empty($data)) {
  440. // 关联更新
  441. if (!empty($this->relationWrite)) {
  442. $this->autoRelationUpdate();
  443. }
  444. return false;
  445. } elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
  446. // 自动写入更新时间
  447. $data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
  448. $this->data[$this->updateTime] = $data[$this->updateTime];
  449. }
  450. if (empty($where) && !empty($this->updateWhere)) {
  451. $where = $this->updateWhere;
  452. }
  453. // 检查允许字段
  454. $allowFields = $this->checkAllowFields(array_merge($this->auto, $this->update));
  455. // 保留主键数据
  456. foreach ($this->data as $key => $val) {
  457. if ($this->isPk($key)) {
  458. $data[$key] = $val;
  459. }
  460. }
  461. $pk = $this->getPk();
  462. $array = [];
  463. foreach ((array) $pk as $key) {
  464. if (isset($data[$key])) {
  465. $array[] = [$key, '=', $data[$key]];
  466. unset($data[$key]);
  467. }
  468. }
  469. if (!empty($array)) {
  470. $where = $array;
  471. }
  472. foreach ((array) $this->relationWrite as $name => $val) {
  473. if (is_array($val)) {
  474. foreach ($val as $key) {
  475. if (isset($data[$key])) {
  476. unset($data[$key]);
  477. }
  478. }
  479. }
  480. }
  481. // 模型更新
  482. $db = $this->db(false);
  483. $db->startTrans();
  484. try {
  485. $db->where($where)
  486. ->strict(false)
  487. ->field($allowFields)
  488. ->update($data);
  489. // 关联更新
  490. if (!empty($this->relationWrite)) {
  491. $this->autoRelationUpdate();
  492. }
  493. $db->commit();
  494. // 更新回调
  495. $this->trigger('after_update');
  496. return true;
  497. } catch (\Exception $e) {
  498. $db->rollback();
  499. throw $e;
  500. }
  501. }
  502. /**
  503. * 新增写入数据
  504. * @access protected
  505. * @param string $sequence 自增序列名
  506. * @return bool
  507. */
  508. protected function insertData($sequence)
  509. {
  510. // 自动写入
  511. $this->autoCompleteData($this->insert);
  512. // 时间戳自动写入
  513. $this->checkTimeStampWrite();
  514. if (false === $this->trigger('before_insert')) {
  515. return false;
  516. }
  517. // 检查允许字段
  518. $allowFields = $this->checkAllowFields(array_merge($this->auto, $this->insert));
  519. $db = $this->db(false);
  520. $db->startTrans();
  521. try {
  522. $result = $db->strict(false)
  523. ->field($allowFields)
  524. ->insert($this->data, $this->replace, false, $sequence);
  525. // 获取自动增长主键
  526. if ($result && $insertId = $db->getLastInsID($sequence)) {
  527. $pk = $this->getPk();
  528. foreach ((array) $pk as $key) {
  529. if (!isset($this->data[$key]) || '' == $this->data[$key]) {
  530. $this->data[$key] = $insertId;
  531. }
  532. }
  533. }
  534. // 关联写入
  535. if (!empty($this->relationWrite)) {
  536. $this->autoRelationInsert();
  537. }
  538. $db->commit();
  539. // 标记为更新
  540. $this->exists = true;
  541. // 新增回调
  542. $this->trigger('after_insert');
  543. return true;
  544. } catch (\Exception $e) {
  545. $db->rollback();
  546. throw $e;
  547. }
  548. }
  549. /**
  550. * 字段值(延迟)增长
  551. * @access public
  552. * @param string $field 字段名
  553. * @param integer $step 增长值
  554. * @param integer $lazyTime 延时时间(s)
  555. * @return bool
  556. * @throws Exception
  557. */
  558. public function setInc($field, $step = 1, $lazyTime = 0)
  559. {
  560. // 读取更新条件
  561. $where = $this->getWhere();
  562. // 事件回调
  563. if (false === $this->trigger('before_update')) {
  564. return false;
  565. }
  566. $result = $this->db(false)
  567. ->where($where)
  568. ->setInc($field, $step, $lazyTime);
  569. if (true !== $result) {
  570. $this->data[$field] += $step;
  571. }
  572. // 更新回调
  573. $this->trigger('after_update');
  574. return true;
  575. }
  576. /**
  577. * 字段值(延迟)减少
  578. * @access public
  579. * @param string $field 字段名
  580. * @param integer $step 减少值
  581. * @param integer $lazyTime 延时时间(s)
  582. * @return bool
  583. * @throws Exception
  584. */
  585. public function setDec($field, $step = 1, $lazyTime = 0)
  586. {
  587. // 读取更新条件
  588. $where = $this->getWhere();
  589. // 事件回调
  590. if (false === $this->trigger('before_update')) {
  591. return false;
  592. }
  593. $result = $this->db(false)
  594. ->where($where)
  595. ->setDec($field, $step, $lazyTime);
  596. if (true !== $result) {
  597. $this->data[$field] -= $step;
  598. }
  599. // 更新回调
  600. $this->trigger('after_update');
  601. return true;
  602. }
  603. /**
  604. * 获取当前的更新条件
  605. * @access protected
  606. * @return mixed
  607. */
  608. protected function getWhere()
  609. {
  610. // 删除条件
  611. $pk = $this->getPk();
  612. if (is_string($pk) && isset($this->data[$pk])) {
  613. $where[] = [$pk, '=', $this->data[$pk]];
  614. } elseif (!empty($this->updateWhere)) {
  615. $where = $this->updateWhere;
  616. } else {
  617. $where = null;
  618. }
  619. return $where;
  620. }
  621. /**
  622. * 保存多个数据到当前数据对象
  623. * @access public
  624. * @param array $dataSet 数据
  625. * @param boolean $replace 是否自动识别更新和写入
  626. * @return Collection
  627. * @throws \Exception
  628. */
  629. public function saveAll($dataSet, $replace = true)
  630. {
  631. $result = [];
  632. $db = $this->db(false);
  633. $db->startTrans();
  634. try {
  635. $pk = $this->getPk();
  636. if (is_string($pk) && $replace) {
  637. $auto = true;
  638. }
  639. foreach ($dataSet as $key => $data) {
  640. if ($this->exists || (!empty($auto) && isset($data[$pk]))) {
  641. $result[$key] = self::update($data, [], $this->field);
  642. } else {
  643. $result[$key] = self::create($data, $this->field);
  644. }
  645. }
  646. $db->commit();
  647. return $this->toCollection($result);
  648. } catch (\Exception $e) {
  649. $db->rollback();
  650. throw $e;
  651. }
  652. }
  653. /**
  654. * 是否为更新数据
  655. * @access public
  656. * @param mixed $update
  657. * @param mixed $where
  658. * @return $this
  659. */
  660. public function isUpdate($update = true, $where = null)
  661. {
  662. if (is_bool($update)) {
  663. $this->exists = $update;
  664. if (!empty($where)) {
  665. $this->updateWhere = $where;
  666. }
  667. } else {
  668. $this->exists = true;
  669. $this->updateWhere = $update;
  670. }
  671. return $this;
  672. }
  673. /**
  674. * 删除当前的记录
  675. * @access public
  676. * @return bool
  677. */
  678. public function delete()
  679. {
  680. if (!$this->exists || false === $this->trigger('before_delete')) {
  681. return false;
  682. }
  683. // 读取更新条件
  684. $where = $this->getWhere();
  685. $db = $this->db(false);
  686. $db->startTrans();
  687. try {
  688. // 删除当前模型数据
  689. $result = $db->where($where)->delete();
  690. // 关联删除
  691. if (!empty($this->relationWrite)) {
  692. $this->autoRelationDelete();
  693. }
  694. $db->commit();
  695. $this->trigger('after_delete');
  696. $this->exists = false;
  697. return true;
  698. } catch (\Exception $e) {
  699. $db->rollback();
  700. throw $e;
  701. }
  702. }
  703. /**
  704. * 设置自动完成的字段( 规则通过修改器定义)
  705. * @access public
  706. * @param array $fields 需要自动完成的字段
  707. * @return $this
  708. */
  709. public function auto($fields)
  710. {
  711. $this->auto = $fields;
  712. return $this;
  713. }
  714. /**
  715. * 写入数据
  716. * @access public
  717. * @param array $data 数据数组
  718. * @param array|true $field 允许字段
  719. * @param bool $replace 使用Replace
  720. * @return static
  721. */
  722. public static function create($data = [], $field = null, $replace = false)
  723. {
  724. $model = new static();
  725. if (!empty($field)) {
  726. $model->allowField($field);
  727. }
  728. $model->isUpdate(false)->replace($replace)->save($data, []);
  729. return $model;
  730. }
  731. /**
  732. * 更新数据
  733. * @access public
  734. * @param array $data 数据数组
  735. * @param array $where 更新条件
  736. * @param array|true $field 允许字段
  737. * @return static
  738. */
  739. public static function update($data = [], $where = [], $field = null)
  740. {
  741. $model = new static();
  742. if (!empty($field)) {
  743. $model->allowField($field);
  744. }
  745. $model->isUpdate(true)->save($data, $where);
  746. return $model;
  747. }
  748. /**
  749. * 查找单条记录
  750. * @access public
  751. * @param mixed $data 主键值或者查询条件(闭包)
  752. * @param mixed $with 关联预查询
  753. * @param bool $cache 是否缓存
  754. * @param bool $failException 是否抛出异常
  755. * @return static|null
  756. * @throws exception\DbException
  757. */
  758. public static function get($data, $with = [], $cache = false, $failException = false)
  759. {
  760. if (is_null($data)) {
  761. return;
  762. }
  763. if (true === $with || is_int($with)) {
  764. $cache = $with;
  765. $with = [];
  766. }
  767. $query = static::parseQuery($data, $with, $cache);
  768. return $query->failException($failException)->find($data);
  769. }
  770. /**
  771. * 查找单条记录 如果不存在直接抛出异常
  772. * @access public
  773. * @param mixed $data 主键值或者查询条件(闭包)
  774. * @param mixed $with 关联预查询
  775. * @param bool $cache 是否缓存
  776. * @return static|null
  777. * @throws exception\DbException
  778. */
  779. public static function getOrFail($data, $with = [], $cache = false)
  780. {
  781. return self::get($data, $with, $cache, true);
  782. }
  783. /**
  784. * 查找所有记录
  785. * @access public
  786. * @param mixed $data 主键列表或者查询条件(闭包)
  787. * @param array|string $with 关联预查询
  788. * @param bool $cache 是否缓存
  789. * @return static[]|false
  790. * @throws exception\DbException
  791. */
  792. public static function all($data = null, $with = [], $cache = false)
  793. {
  794. if (true === $with || is_int($with)) {
  795. $cache = $with;
  796. $with = [];
  797. }
  798. $query = static::parseQuery($data, $with, $cache);
  799. return $query->select($data);
  800. }
  801. /**
  802. * 分析查询表达式
  803. * @access public
  804. * @param mixed $data 主键列表或者查询条件(闭包)
  805. * @param string $with 关联预查询
  806. * @param bool $cache 是否缓存
  807. * @return Query
  808. */
  809. protected static function parseQuery(&$data, $with, $cache)
  810. {
  811. $result = self::with($with)->cache($cache);
  812. if (is_array($data) && key($data) !== 0) {
  813. $result = $result->where($data);
  814. $data = null;
  815. } elseif ($data instanceof \Closure) {
  816. $data($result);
  817. $data = null;
  818. } elseif ($data instanceof Query) {
  819. $result = $data->with($with)->cache($cache);
  820. $data = null;
  821. }
  822. return $result;
  823. }
  824. /**
  825. * 删除记录
  826. * @access public
  827. * @param mixed $data 主键列表 支持闭包查询条件
  828. * @return bool
  829. */
  830. public static function destroy($data)
  831. {
  832. if (empty($data) && 0 !== $data) {
  833. return false;
  834. }
  835. $model = new static();
  836. $query = $model->db();
  837. if (is_array($data) && key($data) !== 0) {
  838. $query->where($data);
  839. $data = null;
  840. } elseif ($data instanceof \Closure) {
  841. $data($query);
  842. $data = null;
  843. }
  844. $resultSet = $query->select($data);
  845. if ($resultSet) {
  846. foreach ($resultSet as $data) {
  847. $data->delete();
  848. }
  849. }
  850. return true;
  851. }
  852. /**
  853. * 获取错误信息
  854. * @access public
  855. * @return mixed
  856. */
  857. public function getError()
  858. {
  859. return $this->error;
  860. }
  861. /**
  862. * 解序列化后处理
  863. */
  864. public function __wakeup()
  865. {
  866. $this->initialize();
  867. }
  868. public function __debugInfo()
  869. {
  870. return [
  871. 'data' => $this->data,
  872. 'relation' => $this->relation,
  873. ];
  874. }
  875. /**
  876. * 修改器 设置数据对象的值
  877. * @access public
  878. * @param string $name 名称
  879. * @param mixed $value 值
  880. * @return void
  881. */
  882. public function __set($name, $value)
  883. {
  884. $this->setAttr($name, $value);
  885. }
  886. /**
  887. * 获取器 获取数据对象的值
  888. * @access public
  889. * @param string $name 名称
  890. * @return mixed
  891. */
  892. public function __get($name)
  893. {
  894. return $this->getAttr($name);
  895. }
  896. /**
  897. * 检测数据对象的值
  898. * @access public
  899. * @param string $name 名称
  900. * @return boolean
  901. */
  902. public function __isset($name)
  903. {
  904. try {
  905. return !is_null($this->getAttr($name));
  906. } catch (InvalidArgumentException $e) {
  907. return false;
  908. }
  909. }
  910. /**
  911. * 销毁数据对象的值
  912. * @access public
  913. * @param string $name 名称
  914. * @return void
  915. */
  916. public function __unset($name)
  917. {
  918. unset($this->data[$name], $this->relation[$name]);
  919. }
  920. // ArrayAccess
  921. public function offsetSet($name, $value)
  922. {
  923. $this->setAttr($name, $value);
  924. }
  925. public function offsetExists($name)
  926. {
  927. return $this->__isset($name);
  928. }
  929. public function offsetUnset($name)
  930. {
  931. $this->__unset($name);
  932. }
  933. public function offsetGet($name)
  934. {
  935. return $this->getAttr($name);
  936. }
  937. /**
  938. * 设置是否使用全局查询范围
  939. * @access public
  940. * @param bool $use 是否启用全局查询范围
  941. * @return Query
  942. */
  943. public static function useGlobalScope($use)
  944. {
  945. $model = new static();
  946. return $model->db($use);
  947. }
  948. public function __call($method, $args)
  949. {
  950. return call_user_func_array([$this->db(), $method], $args);
  951. }
  952. public static function __callStatic($method, $args)
  953. {
  954. $model = new static();
  955. return call_user_func_array([$model->db(), $method], $args);
  956. }
  957. }