Model.php 27 KB

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