Model.php 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293
  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 BadMethodCallException;
  13. use InvalidArgumentException;
  14. use think\db\Query;
  15. use think\exception\ValidateException;
  16. use think\model\Collection as ModelCollection;
  17. use think\model\Relation;
  18. use think\model\relation\BelongsTo;
  19. use think\model\relation\BelongsToMany;
  20. use think\model\relation\HasMany;
  21. use think\model\relation\HasManyThrough;
  22. use think\model\relation\HasOne;
  23. use think\model\relation\MorphMany;
  24. use think\model\relation\MorphOne;
  25. use think\model\relation\MorphTo;
  26. /**
  27. * Class Model
  28. * @package think
  29. * @mixin Query
  30. */
  31. abstract class Model implements \JsonSerializable, \ArrayAccess
  32. {
  33. // 数据库查询对象池
  34. protected static $links = [];
  35. // 数据库配置
  36. protected $connection = [];
  37. // 父关联模型对象
  38. protected $parent;
  39. // 数据库查询对象
  40. protected $query;
  41. // 当前模型名称
  42. protected $name;
  43. // 数据表名称
  44. protected $table;
  45. // 当前类名称
  46. protected $class;
  47. // 回调事件
  48. private static $event = [];
  49. // 错误信息
  50. protected $error;
  51. // 字段验证规则
  52. protected $validate;
  53. // 数据表主键 复合主键使用数组定义 不设置则自动获取
  54. protected $pk;
  55. // 数据表字段信息 留空则自动获取
  56. protected $field = [];
  57. // 数据排除字段
  58. protected $except = [];
  59. // 数据废弃字段
  60. protected $disuse = [];
  61. // 只读字段
  62. protected $readonly = [];
  63. // 显示属性
  64. protected $visible = [];
  65. // 隐藏属性
  66. protected $hidden = [];
  67. // 追加属性
  68. protected $append = [];
  69. // 数据信息
  70. protected $data = [];
  71. // 原始数据
  72. protected $origin = [];
  73. // 关联模型
  74. protected $relation = [];
  75. // 保存自动完成列表
  76. protected $auto = [];
  77. // 新增自动完成列表
  78. protected $insert = [];
  79. // 更新自动完成列表
  80. protected $update = [];
  81. // 是否需要自动写入时间戳 如果设置为字符串 则表示时间字段的类型
  82. protected $autoWriteTimestamp;
  83. // 创建时间字段
  84. protected $createTime = 'create_time';
  85. // 更新时间字段
  86. protected $updateTime = 'update_time';
  87. // 时间字段取出后的默认时间格式
  88. protected $dateFormat;
  89. // 字段类型或者格式转换
  90. protected $type = [];
  91. // 是否为更新数据
  92. protected $isUpdate = false;
  93. // 是否强制更新所有数据
  94. protected $force = false;
  95. // 更新条件
  96. protected $updateWhere;
  97. // 验证失败是否抛出异常
  98. protected $failException = false;
  99. // 全局查询范围
  100. protected $useGlobalScope = true;
  101. // 是否采用批量验证
  102. protected $batchValidate = false;
  103. // 查询数据集对象
  104. protected $resultSetType;
  105. // 关联自动写入
  106. protected $relationWrite;
  107. /**
  108. * 初始化过的模型.
  109. *
  110. * @var array
  111. */
  112. protected static $initialized = [];
  113. /**
  114. * 构造方法
  115. * @access public
  116. * @param array|object $data 数据
  117. */
  118. public function __construct($data = [])
  119. {
  120. if (is_object($data)) {
  121. $this->data = get_object_vars($data);
  122. } else {
  123. $this->data = $data;
  124. }
  125. if ($this->disuse) {
  126. // 废弃字段
  127. foreach ((array) $this->disuse as $key) {
  128. if (array_key_exists($key, $this->data)) {
  129. unset($this->data[$key]);
  130. }
  131. }
  132. }
  133. // 记录原始数据
  134. $this->origin = $this->data;
  135. // 当前类名
  136. $this->class = get_called_class();
  137. if (empty($this->name)) {
  138. // 当前模型名
  139. $name = str_replace('\\', '/', $this->class);
  140. $this->name = basename($name);
  141. if (Config::get('class_suffix')) {
  142. $suffix = basename(dirname($name));
  143. $this->name = substr($this->name, 0, -strlen($suffix));
  144. }
  145. }
  146. if (is_null($this->autoWriteTimestamp)) {
  147. // 自动写入时间戳
  148. $this->autoWriteTimestamp = $this->getQuery()->getConfig('auto_timestamp');
  149. }
  150. if (is_null($this->dateFormat)) {
  151. // 设置时间戳格式
  152. $this->dateFormat = $this->getQuery()->getConfig('datetime_format');
  153. }
  154. if (is_null($this->resultSetType)) {
  155. $this->resultSetType = $this->getQuery()->getConfig('resultset_type');
  156. }
  157. // 执行初始化操作
  158. $this->initialize();
  159. }
  160. /**
  161. * 创建模型的查询对象
  162. * @access protected
  163. * @return Query
  164. */
  165. protected function buildQuery()
  166. {
  167. // 合并数据库配置
  168. if (!empty($this->connection)) {
  169. if (is_array($this->connection)) {
  170. $connection = array_merge(Config::get('database'), $this->connection);
  171. } else {
  172. $connection = $this->connection;
  173. }
  174. } else {
  175. $connection = [];
  176. }
  177. $con = Db::connect($connection);
  178. // 设置当前模型 确保查询返回模型对象
  179. $queryClass = $this->query ?: $con->getConfig('query');
  180. $query = new $queryClass($con, $this->class);
  181. // 设置当前数据表和模型名
  182. if (!empty($this->table)) {
  183. $query->setTable($this->table);
  184. } else {
  185. $query->name($this->name);
  186. }
  187. if (!empty($this->pk)) {
  188. $query->pk($this->pk);
  189. }
  190. return $query;
  191. }
  192. /**
  193. * 获取当前模型的查询对象
  194. * @access public
  195. * @param bool $buildNewQuery 创建新的查询对象
  196. * @return Query
  197. */
  198. public function getQuery($buildNewQuery = false)
  199. {
  200. if ($buildNewQuery) {
  201. return $this->buildQuery();
  202. } elseif (!isset(self::$links[$this->class])) {
  203. // 创建模型查询对象
  204. self::$links[$this->class] = $this->buildQuery();
  205. }
  206. return self::$links[$this->class];
  207. }
  208. /**
  209. * 获取当前模型的数据库查询对象
  210. * @access public
  211. * @param bool $useBaseQuery 是否调用全局查询范围
  212. * @param bool $buildNewQuery 创建新的查询对象
  213. * @return Query
  214. */
  215. public function db($useBaseQuery = true, $buildNewQuery = true)
  216. {
  217. $query = $this->getQuery($buildNewQuery);
  218. // 全局作用域
  219. if ($useBaseQuery && method_exists($this, 'base')) {
  220. call_user_func_array([$this, 'base'], [ & $query]);
  221. }
  222. // 返回当前模型的数据库查询对象
  223. return $query;
  224. }
  225. /**
  226. * 初始化模型
  227. * @access protected
  228. * @return void
  229. */
  230. protected function initialize()
  231. {
  232. $class = get_class($this);
  233. if (!isset(static::$initialized[$class])) {
  234. static::$initialized[$class] = true;
  235. static::init();
  236. }
  237. }
  238. /**
  239. * 初始化处理
  240. * @access protected
  241. * @return void
  242. */
  243. protected static function init()
  244. {
  245. }
  246. /**
  247. * 设置父关联对象
  248. * @access public
  249. * @param Model $model 模型对象
  250. * @return $this
  251. */
  252. public function setParent($model)
  253. {
  254. $this->parent = $model;
  255. return $this;
  256. }
  257. /**
  258. * 获取父关联对象
  259. * @access public
  260. * @return Model
  261. */
  262. public function getParent()
  263. {
  264. return $this->parent;
  265. }
  266. /**
  267. * 设置数据对象值
  268. * @access public
  269. * @param mixed $data 数据或者属性名
  270. * @param mixed $value 值
  271. * @return $this
  272. */
  273. public function data($data, $value = null)
  274. {
  275. if (is_string($data)) {
  276. $this->data[$data] = $value;
  277. } else {
  278. // 清空数据
  279. $this->data = [];
  280. if (is_object($data)) {
  281. $data = get_object_vars($data);
  282. }
  283. if (true === $value) {
  284. // 数据对象赋值
  285. foreach ($data as $key => $value) {
  286. $this->setAttr($key, $value, $data);
  287. }
  288. } else {
  289. $this->data = $data;
  290. }
  291. }
  292. return $this;
  293. }
  294. /**
  295. * 获取对象原始数据 如果不存在指定字段返回false
  296. * @access public
  297. * @param string $name 字段名 留空获取全部
  298. * @return mixed
  299. * @throws InvalidArgumentException
  300. */
  301. public function getData($name = null)
  302. {
  303. if (is_null($name)) {
  304. return $this->data;
  305. } elseif (array_key_exists($name, $this->data)) {
  306. return $this->data[$name];
  307. } elseif (array_key_exists($name, $this->relation)) {
  308. return $this->relation[$name];
  309. } else {
  310. throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
  311. }
  312. }
  313. /**
  314. * 是否需要自动写入时间字段
  315. * @access public
  316. * @param bool $auto
  317. * @return $this
  318. */
  319. public function isAutoWriteTimestamp($auto)
  320. {
  321. $this->autoWriteTimestamp = $auto;
  322. return $this;
  323. }
  324. /**
  325. * 更新是否强制写入数据 而不做比较
  326. * @access public
  327. * @param bool $force
  328. * @return $this
  329. */
  330. public function force($force = true)
  331. {
  332. $this->force = $force;
  333. return $this;
  334. }
  335. /**
  336. * 修改器 设置数据对象值
  337. * @access public
  338. * @param string $name 属性名
  339. * @param mixed $value 属性值
  340. * @param array $data 数据
  341. * @return $this
  342. */
  343. public function setAttr($name, $value, $data = [])
  344. {
  345. if (is_null($value) && $this->autoWriteTimestamp && in_array($name, [$this->createTime, $this->updateTime])) {
  346. // 自动写入的时间戳字段
  347. $value = $this->autoWriteTimestamp($name);
  348. } else {
  349. // 检测修改器
  350. $method = 'set' . Loader::parseName($name, 1) . 'Attr';
  351. if (method_exists($this, $method)) {
  352. $value = $this->$method($value, array_merge($this->data, $data), $this->relation);
  353. } elseif (isset($this->type[$name])) {
  354. // 类型转换
  355. $value = $this->writeTransform($value, $this->type[$name]);
  356. }
  357. }
  358. // 设置数据对象属性
  359. $this->data[$name] = $value;
  360. return $this;
  361. }
  362. /**
  363. * 获取当前模型的关联模型数据
  364. * @access public
  365. * @param string $name 关联方法名
  366. * @return mixed
  367. */
  368. public function getRelation($name = null)
  369. {
  370. if (is_null($name)) {
  371. return $this->relation;
  372. } elseif (array_key_exists($name, $this->relation)) {
  373. return $this->relation[$name];
  374. } else {
  375. return;
  376. }
  377. }
  378. /**
  379. * 设置关联数据对象值
  380. * @access public
  381. * @param string $name 属性名
  382. * @param mixed $value 属性值
  383. * @return $this
  384. */
  385. public function setRelation($name, $value)
  386. {
  387. $this->relation[$name] = $value;
  388. return $this;
  389. }
  390. /**
  391. * 自动写入时间戳
  392. * @access public
  393. * @param string $name 时间戳字段
  394. * @return mixed
  395. */
  396. protected function autoWriteTimestamp($name)
  397. {
  398. if (isset($this->type[$name])) {
  399. $type = $this->type[$name];
  400. if (strpos($type, ':')) {
  401. list($type, $param) = explode(':', $type, 2);
  402. }
  403. switch ($type) {
  404. case 'datetime':
  405. case 'date':
  406. $format = !empty($param) ? $param : $this->dateFormat;
  407. $value = $this->formatDateTime(time(), $format);
  408. break;
  409. case 'timestamp':
  410. case 'integer':
  411. default:
  412. $value = time();
  413. break;
  414. }
  415. } elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
  416. 'datetime',
  417. 'date',
  418. 'timestamp',
  419. ])
  420. ) {
  421. $value = $this->formatDateTime(time(), $this->dateFormat);
  422. } else {
  423. $value = $this->formatDateTime(time(), $this->dateFormat, true);
  424. }
  425. return $value;
  426. }
  427. /**
  428. * 时间日期字段格式化处理
  429. * @access public
  430. * @param mixed $time 时间日期表达式
  431. * @param mixed $format 日期格式
  432. * @param bool $timestamp 是否进行时间戳转换
  433. * @return mixed
  434. */
  435. protected function formatDateTime($time, $format, $timestamp = false)
  436. {
  437. if (false !== strpos($format, '\\')) {
  438. $time = new $format($time);
  439. } elseif (!$timestamp && false !== $format) {
  440. $time = date($format, $time);
  441. }
  442. return $time;
  443. }
  444. /**
  445. * 数据写入 类型转换
  446. * @access public
  447. * @param mixed $value 值
  448. * @param string|array $type 要转换的类型
  449. * @return mixed
  450. */
  451. protected function writeTransform($value, $type)
  452. {
  453. if (is_null($value)) {
  454. return;
  455. }
  456. if (is_array($type)) {
  457. list($type, $param) = $type;
  458. } elseif (strpos($type, ':')) {
  459. list($type, $param) = explode(':', $type, 2);
  460. }
  461. switch ($type) {
  462. case 'integer':
  463. $value = (int) $value;
  464. break;
  465. case 'float':
  466. if (empty($param)) {
  467. $value = (float) $value;
  468. } else {
  469. $value = (float) number_format($value, $param, '.', '');
  470. }
  471. break;
  472. case 'boolean':
  473. $value = (bool) $value;
  474. break;
  475. case 'timestamp':
  476. if (!is_numeric($value)) {
  477. $value = strtotime($value);
  478. }
  479. break;
  480. case 'datetime':
  481. $format = !empty($param) ? $param : $this->dateFormat;
  482. $value = is_numeric($value) ? $value : strtotime($value);
  483. $value = $this->formatDateTime($value, $format);
  484. break;
  485. case 'object':
  486. if (is_object($value)) {
  487. $value = json_encode($value, JSON_FORCE_OBJECT);
  488. }
  489. break;
  490. case 'array':
  491. $value = (array) $value;
  492. case 'json':
  493. $option = !empty($param) ? (int) $param : JSON_UNESCAPED_UNICODE;
  494. $value = json_encode($value, $option);
  495. break;
  496. case 'serialize':
  497. $value = serialize($value);
  498. break;
  499. }
  500. return $value;
  501. }
  502. /**
  503. * 获取器 获取数据对象的值
  504. * @access public
  505. * @param string $name 名称
  506. * @return mixed
  507. * @throws InvalidArgumentException
  508. */
  509. public function getAttr($name)
  510. {
  511. try {
  512. $notFound = false;
  513. $value = $this->getData($name);
  514. } catch (InvalidArgumentException $e) {
  515. $notFound = true;
  516. $value = null;
  517. }
  518. // 检测属性获取器
  519. $method = 'get' . Loader::parseName($name, 1) . 'Attr';
  520. if (method_exists($this, $method)) {
  521. $value = $this->$method($value, $this->data, $this->relation);
  522. } elseif (isset($this->type[$name])) {
  523. // 类型转换
  524. $value = $this->readTransform($value, $this->type[$name]);
  525. } elseif (in_array($name, [$this->createTime, $this->updateTime])) {
  526. if (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
  527. 'datetime',
  528. 'date',
  529. 'timestamp',
  530. ])
  531. ) {
  532. $value = $this->formatDateTime(strtotime($value), $this->dateFormat);
  533. } else {
  534. $value = $this->formatDateTime($value, $this->dateFormat);
  535. }
  536. } elseif ($notFound) {
  537. $relation = Loader::parseName($name, 1, false);
  538. if (method_exists($this, $relation)) {
  539. $modelRelation = $this->$relation();
  540. // 不存在该字段 获取关联数据
  541. $value = $this->getRelationData($modelRelation);
  542. // 保存关联对象值
  543. $this->relation[$name] = $value;
  544. } else {
  545. throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
  546. }
  547. }
  548. return $value;
  549. }
  550. /**
  551. * 获取关联模型数据
  552. * @access public
  553. * @param Relation $modelRelation 模型关联对象
  554. * @return mixed
  555. * @throws BadMethodCallException
  556. */
  557. protected function getRelationData(Relation $modelRelation)
  558. {
  559. if ($this->parent && get_class($this->parent) == $modelRelation->getModel()) {
  560. $value = $this->parent;
  561. } else {
  562. // 首先获取关联数据
  563. if (method_exists($modelRelation, 'getRelation')) {
  564. $value = $modelRelation->getRelation();
  565. } else {
  566. throw new BadMethodCallException('method not exists:' . get_class($modelRelation) . '-> getRelation');
  567. }
  568. }
  569. return $value;
  570. }
  571. /**
  572. * 数据读取 类型转换
  573. * @access public
  574. * @param mixed $value 值
  575. * @param string|array $type 要转换的类型
  576. * @return mixed
  577. */
  578. protected function readTransform($value, $type)
  579. {
  580. if (is_null($value)) {
  581. return;
  582. }
  583. if (is_array($type)) {
  584. list($type, $param) = $type;
  585. } elseif (strpos($type, ':')) {
  586. list($type, $param) = explode(':', $type, 2);
  587. }
  588. switch ($type) {
  589. case 'integer':
  590. $value = (int) $value;
  591. break;
  592. case 'float':
  593. if (empty($param)) {
  594. $value = (float) $value;
  595. } else {
  596. $value = (float) number_format($value, $param, '.', '');
  597. }
  598. break;
  599. case 'boolean':
  600. $value = (bool) $value;
  601. break;
  602. case 'timestamp':
  603. if (!is_null($value)) {
  604. $format = !empty($param) ? $param : $this->dateFormat;
  605. $value = $this->formatDateTime($value, $format);
  606. }
  607. break;
  608. case 'datetime':
  609. if (!is_null($value)) {
  610. $format = !empty($param) ? $param : $this->dateFormat;
  611. $value = $this->formatDateTime(strtotime($value), $format);
  612. }
  613. break;
  614. case 'json':
  615. $value = json_decode($value, true);
  616. break;
  617. case 'array':
  618. $value = empty($value) ? [] : json_decode($value, true);
  619. break;
  620. case 'object':
  621. $value = empty($value) ? new \stdClass() : json_decode($value);
  622. break;
  623. case 'serialize':
  624. $value = unserialize($value);
  625. break;
  626. default:
  627. if (false !== strpos($type, '\\')) {
  628. // 对象类型
  629. $value = new $type($value);
  630. }
  631. }
  632. return $value;
  633. }
  634. /**
  635. * 设置需要追加的输出属性
  636. * @access public
  637. * @param array $append 属性列表
  638. * @param bool $override 是否覆盖
  639. * @return $this
  640. */
  641. public function append($append = [], $override = false)
  642. {
  643. $this->append = $override ? $append : array_merge($this->append, $append);
  644. return $this;
  645. }
  646. /**
  647. * 设置附加关联对象的属性
  648. * @access public
  649. * @param string $relation 关联方法
  650. * @param string|array $append 追加属性名
  651. * @return $this
  652. * @throws Exception
  653. */
  654. public function appendRelationAttr($relation, $append)
  655. {
  656. if (is_string($append)) {
  657. $append = explode(',', $append);
  658. }
  659. $relation = Loader::parseName($relation, 1, false);
  660. // 获取关联数据
  661. if (isset($this->relation[$relation])) {
  662. $model = $this->relation[$relation];
  663. } else {
  664. $model = $this->getRelationData($this->$relation());
  665. }
  666. if ($model instanceof Model) {
  667. foreach ($append as $key => $attr) {
  668. $key = is_numeric($key) ? $attr : $key;
  669. if (isset($this->data[$key])) {
  670. throw new Exception('bind attr has exists:' . $key);
  671. } else {
  672. $this->data[$key] = $model->getAttr($attr);
  673. }
  674. }
  675. }
  676. return $this;
  677. }
  678. /**
  679. * 设置需要隐藏的输出属性
  680. * @access public
  681. * @param array $hidden 属性列表
  682. * @param bool $override 是否覆盖
  683. * @return $this
  684. */
  685. public function hidden($hidden = [], $override = false)
  686. {
  687. $this->hidden = $override ? $hidden : array_merge($this->hidden, $hidden);
  688. return $this;
  689. }
  690. /**
  691. * 设置需要输出的属性
  692. * @access public
  693. * @param array $visible
  694. * @param bool $override 是否覆盖
  695. * @return $this
  696. */
  697. public function visible($visible = [], $override = false)
  698. {
  699. $this->visible = $override ? $visible : array_merge($this->visible, $visible);
  700. return $this;
  701. }
  702. /**
  703. * 解析隐藏及显示属性
  704. * @access protected
  705. * @param array $attrs 属性
  706. * @param array $result 结果集
  707. * @param bool $visible
  708. * @return array
  709. */
  710. protected function parseAttr($attrs, &$result, $visible = true)
  711. {
  712. $array = [];
  713. foreach ($attrs as $key => $val) {
  714. if (is_array($val)) {
  715. if ($visible) {
  716. $array[] = $key;
  717. }
  718. $result[$key] = $val;
  719. } elseif (strpos($val, '.')) {
  720. list($key, $name) = explode('.', $val);
  721. if ($visible) {
  722. $array[] = $key;
  723. }
  724. $result[$key][] = $name;
  725. } else {
  726. $array[] = $val;
  727. }
  728. }
  729. return $array;
  730. }
  731. /**
  732. * 转换子模型对象
  733. * @access protected
  734. * @param Model|ModelCollection $model
  735. * @param $visible
  736. * @param $hidden
  737. * @param $key
  738. * @return array
  739. */
  740. protected function subToArray($model, $visible, $hidden, $key)
  741. {
  742. // 关联模型对象
  743. if (isset($visible[$key])) {
  744. $model->visible($visible[$key]);
  745. } elseif (isset($hidden[$key])) {
  746. $model->hidden($hidden[$key]);
  747. }
  748. return $model->toArray();
  749. }
  750. /**
  751. * 转换当前模型对象为数组
  752. * @access public
  753. * @return array
  754. */
  755. public function toArray()
  756. {
  757. $item = [];
  758. $visible = [];
  759. $hidden = [];
  760. $data = array_merge($this->data, $this->relation);
  761. // 过滤属性
  762. if (!empty($this->visible)) {
  763. $array = $this->parseAttr($this->visible, $visible);
  764. $data = array_intersect_key($data, array_flip($array));
  765. } elseif (!empty($this->hidden)) {
  766. $array = $this->parseAttr($this->hidden, $hidden, false);
  767. $data = array_diff_key($data, array_flip($array));
  768. }
  769. foreach ($data as $key => $val) {
  770. if ($val instanceof Model || $val instanceof ModelCollection) {
  771. // 关联模型对象
  772. $item[$key] = $this->subToArray($val, $visible, $hidden, $key);
  773. } elseif (is_array($val) && reset($val) instanceof Model) {
  774. // 关联模型数据集
  775. $arr = [];
  776. foreach ($val as $k => $value) {
  777. $arr[$k] = $this->subToArray($value, $visible, $hidden, $key);
  778. }
  779. $item[$key] = $arr;
  780. } else {
  781. // 模型属性
  782. $item[$key] = $this->getAttr($key);
  783. }
  784. }
  785. // 追加属性(必须定义获取器)
  786. if (!empty($this->append)) {
  787. foreach ($this->append as $key => $name) {
  788. if (is_array($name)) {
  789. // 追加关联对象属性
  790. $relation = $this->getAttr($key);
  791. $item[$key] = $relation->append($name)->toArray();
  792. } elseif (strpos($name, '.')) {
  793. list($key, $attr) = explode('.', $name);
  794. // 追加关联对象属性
  795. $relation = $this->getAttr($key);
  796. $item[$key] = $relation->append([$attr])->toArray();
  797. } else {
  798. $relation = Loader::parseName($name, 1, false);
  799. if (method_exists($this, $relation)) {
  800. $modelRelation = $this->$relation();
  801. $value = $this->getRelationData($modelRelation);
  802. if (method_exists($modelRelation, 'getBindAttr')) {
  803. $bindAttr = $modelRelation->getBindAttr();
  804. if ($bindAttr) {
  805. foreach ($bindAttr as $key => $attr) {
  806. $key = is_numeric($key) ? $attr : $key;
  807. if (isset($this->data[$key])) {
  808. throw new Exception('bind attr has exists:' . $key);
  809. } else {
  810. $item[$key] = $value ? $value->getAttr($attr) : null;
  811. }
  812. }
  813. continue;
  814. }
  815. }
  816. $item[$name] = $value;
  817. } else {
  818. $item[$name] = $this->getAttr($name);
  819. }
  820. }
  821. }
  822. }
  823. return !empty($item) ? $item : [];
  824. }
  825. /**
  826. * 转换当前模型对象为JSON字符串
  827. * @access public
  828. * @param integer $options json参数
  829. * @return string
  830. */
  831. public function toJson($options = JSON_UNESCAPED_UNICODE)
  832. {
  833. return json_encode($this->toArray(), $options);
  834. }
  835. /**
  836. * 移除当前模型的关联属性
  837. * @access public
  838. * @return $this
  839. */
  840. public function removeRelation()
  841. {
  842. $this->relation = [];
  843. return $this;
  844. }
  845. /**
  846. * 转换当前模型数据集为数据集对象
  847. * @access public
  848. * @param array|\think\Collection $collection 数据集
  849. * @return \think\Collection
  850. */
  851. public function toCollection($collection)
  852. {
  853. if ($this->resultSetType) {
  854. if ('collection' == $this->resultSetType) {
  855. $collection = new ModelCollection($collection);
  856. } elseif (false !== strpos($this->resultSetType, '\\')) {
  857. $class = $this->resultSetType;
  858. $collection = new $class($collection);
  859. }
  860. }
  861. return $collection;
  862. }
  863. /**
  864. * 关联数据一起更新
  865. * @access public
  866. * @param mixed $relation 关联
  867. * @return $this
  868. */
  869. public function together($relation)
  870. {
  871. if (is_string($relation)) {
  872. $relation = explode(',', $relation);
  873. }
  874. $this->relationWrite = $relation;
  875. return $this;
  876. }
  877. /**
  878. * 获取模型对象的主键
  879. * @access public
  880. * @param string $name 模型名
  881. * @return mixed
  882. */
  883. public function getPk($name = '')
  884. {
  885. if (!empty($name)) {
  886. $table = $this->getQuery()->getTable($name);
  887. return $this->getQuery()->getPk($table);
  888. } elseif (empty($this->pk)) {
  889. $this->pk = $this->getQuery()->getPk();
  890. }
  891. return $this->pk;
  892. }
  893. /**
  894. * 判断一个字段名是否为主键字段
  895. * @access public
  896. * @param string $key 名称
  897. * @return bool
  898. */
  899. protected function isPk($key)
  900. {
  901. $pk = $this->getPk();
  902. if (is_string($pk) && $pk == $key) {
  903. return true;
  904. } elseif (is_array($pk) && in_array($key, $pk)) {
  905. return true;
  906. }
  907. return false;
  908. }
  909. /**
  910. * 保存当前数据对象
  911. * @access public
  912. * @param array $data 数据
  913. * @param array $where 更新条件
  914. * @param string $sequence 自增序列名
  915. * @return integer|false
  916. */
  917. public function save($data = [], $where = [], $sequence = null)
  918. {
  919. if (is_string($data)) {
  920. $sequence = $data;
  921. $data = [];
  922. }
  923. if (!empty($data)) {
  924. // 数据自动验证
  925. if (!$this->validateData($data)) {
  926. return false;
  927. }
  928. // 数据对象赋值
  929. foreach ($data as $key => $value) {
  930. $this->setAttr($key, $value, $data);
  931. }
  932. if (!empty($where)) {
  933. $this->isUpdate = true;
  934. $this->updateWhere = $where;
  935. }
  936. }
  937. // 自动关联写入
  938. if (!empty($this->relationWrite)) {
  939. $relation = [];
  940. foreach ($this->relationWrite as $key => $name) {
  941. if (is_array($name)) {
  942. if (key($name) === 0) {
  943. $relation[$key] = [];
  944. foreach ($name as $val) {
  945. if (isset($this->data[$val])) {
  946. $relation[$key][$val] = $this->data[$val];
  947. unset($this->data[$val]);
  948. }
  949. }
  950. } else {
  951. $relation[$key] = $name;
  952. }
  953. } elseif (isset($this->relation[$name])) {
  954. $relation[$name] = $this->relation[$name];
  955. } elseif (isset($this->data[$name])) {
  956. $relation[$name] = $this->data[$name];
  957. unset($this->data[$name]);
  958. }
  959. }
  960. }
  961. // 数据自动完成
  962. $this->autoCompleteData($this->auto);
  963. // 事件回调
  964. if (false === $this->trigger('before_write', $this)) {
  965. return false;
  966. }
  967. $pk = $this->getPk();
  968. if ($this->isUpdate) {
  969. // 自动更新
  970. $this->autoCompleteData($this->update);
  971. // 事件回调
  972. if (false === $this->trigger('before_update', $this)) {
  973. return false;
  974. }
  975. // 获取有更新的数据
  976. $data = $this->getChangedData();
  977. if (empty($data) || (count($data) == 1 && is_string($pk) && isset($data[$pk]))) {
  978. // 关联更新
  979. if (isset($relation)) {
  980. $this->autoRelationUpdate($relation);
  981. }
  982. return 0;
  983. } elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
  984. // 自动写入更新时间
  985. $data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
  986. $this->data[$this->updateTime] = $data[$this->updateTime];
  987. }
  988. if (empty($where) && !empty($this->updateWhere)) {
  989. $where = $this->updateWhere;
  990. }
  991. // 保留主键数据
  992. foreach ($this->data as $key => $val) {
  993. if ($this->isPk($key)) {
  994. $data[$key] = $val;
  995. }
  996. }
  997. $array = [];
  998. foreach ((array) $pk as $key) {
  999. if (isset($data[$key])) {
  1000. $array[$key] = $data[$key];
  1001. unset($data[$key]);
  1002. }
  1003. }
  1004. if (!empty($array)) {
  1005. $where = $array;
  1006. }
  1007. // 检测字段
  1008. $allowFields = $this->checkAllowField(array_merge($this->auto, $this->update));
  1009. // 模型更新
  1010. if (!empty($allowFields)) {
  1011. $result = $this->getQuery()->where($where)->strict(false)->field($allowFields)->update($data);
  1012. } else {
  1013. $result = $this->getQuery()->where($where)->update($data);
  1014. }
  1015. // 关联更新
  1016. if (isset($relation)) {
  1017. $this->autoRelationUpdate($relation);
  1018. }
  1019. // 更新回调
  1020. $this->trigger('after_update', $this);
  1021. } else {
  1022. // 自动写入
  1023. $this->autoCompleteData($this->insert);
  1024. // 自动写入创建时间和更新时间
  1025. if ($this->autoWriteTimestamp) {
  1026. if ($this->createTime && !isset($this->data[$this->createTime])) {
  1027. $this->data[$this->createTime] = $this->autoWriteTimestamp($this->createTime);
  1028. }
  1029. if ($this->updateTime && !isset($this->data[$this->updateTime])) {
  1030. $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
  1031. }
  1032. }
  1033. if (false === $this->trigger('before_insert', $this)) {
  1034. return false;
  1035. }
  1036. // 检测字段
  1037. $allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert));
  1038. if (!empty($allowFields)) {
  1039. $result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data, false, false, $sequence);
  1040. } else {
  1041. $result = $this->getQuery()->insert($this->data, false, false, $sequence);
  1042. }
  1043. // 获取自动增长主键
  1044. if ($result && $insertId = $this->getQuery()->getLastInsID($sequence)) {
  1045. foreach ((array) $pk as $key) {
  1046. if (!isset($this->data[$key]) || '' == $this->data[$key]) {
  1047. $this->data[$key] = $insertId;
  1048. }
  1049. }
  1050. }
  1051. // 关联写入
  1052. if (isset($relation)) {
  1053. foreach ($relation as $name => $val) {
  1054. $method = Loader::parseName($name, 1, false);
  1055. $this->$method()->save($val);
  1056. }
  1057. }
  1058. // 标记为更新
  1059. $this->isUpdate = true;
  1060. // 新增回调
  1061. $this->trigger('after_insert', $this);
  1062. }
  1063. // 写入回调
  1064. $this->trigger('after_write', $this);
  1065. // 重新记录原始数据
  1066. $this->origin = $this->data;
  1067. return $result;
  1068. }
  1069. protected function checkAllowField($auto = [])
  1070. {
  1071. if (true === $this->field) {
  1072. $this->field = $this->getQuery()->getTableInfo('', 'fields');
  1073. $field = $this->field;
  1074. } elseif (!empty($this->field)) {
  1075. $field = array_merge($this->field, $auto);
  1076. if ($this->autoWriteTimestamp) {
  1077. array_push($field, $this->createTime, $this->updateTime);
  1078. }
  1079. } elseif (!empty($this->except)) {
  1080. $fields = $this->getQuery()->getTableInfo('', 'fields');
  1081. $field = array_diff($fields, (array) $this->except);
  1082. $this->field = $field;
  1083. } else {
  1084. $field = [];
  1085. }
  1086. if ($this->disuse) {
  1087. // 废弃字段
  1088. $field = array_diff($field, (array) $this->disuse);
  1089. }
  1090. return $field;
  1091. }
  1092. protected function autoRelationUpdate($relation)
  1093. {
  1094. foreach ($relation as $name => $val) {
  1095. if ($val instanceof Model) {
  1096. $val->save();
  1097. } else {
  1098. unset($this->data[$name]);
  1099. $model = $this->getAttr($name);
  1100. if ($model instanceof Model) {
  1101. $model->save($val);
  1102. }
  1103. }
  1104. }
  1105. }
  1106. /**
  1107. * 获取变化的数据 并排除只读数据
  1108. * @access public
  1109. * @return array
  1110. */
  1111. public function getChangedData()
  1112. {
  1113. if ($this->force) {
  1114. $data = $this->data;
  1115. } else {
  1116. $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
  1117. if ((empty($a) || empty($b)) && $a !== $b) {
  1118. return 1;
  1119. }
  1120. return is_object($a) || $a != $b ? 1 : 0;
  1121. });
  1122. }
  1123. if (!empty($this->readonly)) {
  1124. // 只读字段不允许更新
  1125. foreach ($this->readonly as $key => $field) {
  1126. if (isset($data[$field])) {
  1127. unset($data[$field]);
  1128. }
  1129. }
  1130. }
  1131. return $data;
  1132. }
  1133. /**
  1134. * 字段值(延迟)增长
  1135. * @access public
  1136. * @param string $field 字段名
  1137. * @param integer $step 增长值
  1138. * @param integer $lazyTime 延时时间(s)
  1139. * @return integer|true
  1140. * @throws Exception
  1141. */
  1142. public function setInc($field, $step = 1, $lazyTime = 0)
  1143. {
  1144. // 更新条件
  1145. $where = $this->getWhere();
  1146. $result = $this->getQuery()->where($where)->setInc($field, $step, $lazyTime);
  1147. if (true !== $result) {
  1148. $this->data[$field] += $step;
  1149. }
  1150. return $result;
  1151. }
  1152. /**
  1153. * 字段值(延迟)增长
  1154. * @access public
  1155. * @param string $field 字段名
  1156. * @param integer $step 增长值
  1157. * @param integer $lazyTime 延时时间(s)
  1158. * @return integer|true
  1159. * @throws Exception
  1160. */
  1161. public function setDec($field, $step = 1, $lazyTime = 0)
  1162. {
  1163. // 更新条件
  1164. $where = $this->getWhere();
  1165. $result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime);
  1166. if (true !== $result) {
  1167. $this->data[$field] -= $step;
  1168. }
  1169. return $result;
  1170. }
  1171. /**
  1172. * 获取更新条件
  1173. * @access protected
  1174. * @return mixed
  1175. */
  1176. protected function getWhere()
  1177. {
  1178. // 删除条件
  1179. $pk = $this->getPk();
  1180. if (is_string($pk) && isset($this->data[$pk])) {
  1181. $where = [$pk => $this->data[$pk]];
  1182. } elseif (!empty($this->updateWhere)) {
  1183. $where = $this->updateWhere;
  1184. } else {
  1185. $where = null;
  1186. }
  1187. return $where;
  1188. }
  1189. /**
  1190. * 保存多个数据到当前数据对象
  1191. * @access public
  1192. * @param array $dataSet 数据
  1193. * @param boolean $replace 是否自动识别更新和写入
  1194. * @return array|false
  1195. * @throws \Exception
  1196. */
  1197. public function saveAll($dataSet, $replace = true)
  1198. {
  1199. if ($this->validate) {
  1200. // 数据批量验证
  1201. $validate = $this->validate;
  1202. foreach ($dataSet as $data) {
  1203. if (!$this->validateData($data, $validate)) {
  1204. return false;
  1205. }
  1206. }
  1207. }
  1208. $result = [];
  1209. $db = $this->getQuery();
  1210. $db->startTrans();
  1211. try {
  1212. $pk = $this->getPk();
  1213. if (is_string($pk) && $replace) {
  1214. $auto = true;
  1215. }
  1216. foreach ($dataSet as $key => $data) {
  1217. if ($this->isUpdate || (!empty($auto) && isset($data[$pk]))) {
  1218. $result[$key] = self::update($data, [], $this->field);
  1219. } else {
  1220. $result[$key] = self::create($data, $this->field);
  1221. }
  1222. }
  1223. $db->commit();
  1224. return $this->toCollection($result);
  1225. } catch (\Exception $e) {
  1226. $db->rollback();
  1227. throw $e;
  1228. }
  1229. }
  1230. /**
  1231. * 设置允许写入的字段
  1232. * @access public
  1233. * @param string|array $field 允许写入的字段 如果为true只允许写入数据表字段
  1234. * @return $this
  1235. */
  1236. public function allowField($field)
  1237. {
  1238. if (is_string($field)) {
  1239. $field = explode(',', $field);
  1240. }
  1241. $this->field = $field;
  1242. return $this;
  1243. }
  1244. /**
  1245. * 设置排除写入的字段
  1246. * @access public
  1247. * @param string|array $field 排除允许写入的字段
  1248. * @return $this
  1249. */
  1250. public function except($field)
  1251. {
  1252. if (is_string($field)) {
  1253. $field = explode(',', $field);
  1254. }
  1255. $this->except = $field;
  1256. return $this;
  1257. }
  1258. /**
  1259. * 设置只读字段
  1260. * @access public
  1261. * @param mixed $field 只读字段
  1262. * @return $this
  1263. */
  1264. public function readonly($field)
  1265. {
  1266. if (is_string($field)) {
  1267. $field = explode(',', $field);
  1268. }
  1269. $this->readonly = $field;
  1270. return $this;
  1271. }
  1272. /**
  1273. * 是否为更新数据
  1274. * @access public
  1275. * @param bool $update
  1276. * @param mixed $where
  1277. * @return $this
  1278. */
  1279. public function isUpdate($update = true, $where = null)
  1280. {
  1281. $this->isUpdate = $update;
  1282. if (!empty($where)) {
  1283. $this->updateWhere = $where;
  1284. }
  1285. return $this;
  1286. }
  1287. /**
  1288. * 数据自动完成
  1289. * @access public
  1290. * @param array $auto 要自动更新的字段列表
  1291. * @return void
  1292. */
  1293. protected function autoCompleteData($auto = [])
  1294. {
  1295. foreach ($auto as $field => $value) {
  1296. if (is_integer($field)) {
  1297. $field = $value;
  1298. $value = null;
  1299. }
  1300. if (!isset($this->data[$field])) {
  1301. $default = null;
  1302. } else {
  1303. $default = $this->data[$field];
  1304. }
  1305. $this->setAttr($field, !is_null($value) ? $value : $default);
  1306. }
  1307. }
  1308. /**
  1309. * 删除当前的记录
  1310. * @access public
  1311. * @return integer
  1312. */
  1313. public function delete()
  1314. {
  1315. if (false === $this->trigger('before_delete', $this)) {
  1316. return false;
  1317. }
  1318. // 删除条件
  1319. $where = $this->getWhere();
  1320. // 删除当前模型数据
  1321. $result = $this->getQuery()->where($where)->delete();
  1322. // 关联删除
  1323. if (!empty($this->relationWrite)) {
  1324. foreach ($this->relationWrite as $key => $name) {
  1325. $name = is_numeric($key) ? $name : $key;
  1326. $model = $this->getAttr($name);
  1327. if ($model instanceof Model) {
  1328. $model->delete();
  1329. }
  1330. }
  1331. }
  1332. $this->trigger('after_delete', $this);
  1333. // 清空原始数据
  1334. $this->origin = [];
  1335. return $result;
  1336. }
  1337. /**
  1338. * 设置自动完成的字段( 规则通过修改器定义)
  1339. * @access public
  1340. * @param array $fields 需要自动完成的字段
  1341. * @return $this
  1342. */
  1343. public function auto($fields)
  1344. {
  1345. $this->auto = $fields;
  1346. return $this;
  1347. }
  1348. /**
  1349. * 设置字段验证
  1350. * @access public
  1351. * @param array|string|bool $rule 验证规则 true表示自动读取验证器类
  1352. * @param array $msg 提示信息
  1353. * @param bool $batch 批量验证
  1354. * @return $this
  1355. */
  1356. public function validate($rule = true, $msg = [], $batch = false)
  1357. {
  1358. if (is_array($rule)) {
  1359. $this->validate = [
  1360. 'rule' => $rule,
  1361. 'msg' => $msg,
  1362. ];
  1363. } else {
  1364. $this->validate = true === $rule ? $this->name : $rule;
  1365. }
  1366. $this->batchValidate = $batch;
  1367. return $this;
  1368. }
  1369. /**
  1370. * 设置验证失败后是否抛出异常
  1371. * @access public
  1372. * @param bool $fail 是否抛出异常
  1373. * @return $this
  1374. */
  1375. public function validateFailException($fail = true)
  1376. {
  1377. $this->failException = $fail;
  1378. return $this;
  1379. }
  1380. /**
  1381. * 自动验证数据
  1382. * @access protected
  1383. * @param array $data 验证数据
  1384. * @param mixed $rule 验证规则
  1385. * @param bool $batch 批量验证
  1386. * @return bool
  1387. */
  1388. protected function validateData($data, $rule = null, $batch = null)
  1389. {
  1390. $info = is_null($rule) ? $this->validate : $rule;
  1391. if (!empty($info)) {
  1392. if (is_array($info)) {
  1393. $validate = Loader::validate();
  1394. $validate->rule($info['rule']);
  1395. $validate->message($info['msg']);
  1396. } else {
  1397. $name = is_string($info) ? $info : $this->name;
  1398. if (strpos($name, '.')) {
  1399. list($name, $scene) = explode('.', $name);
  1400. }
  1401. $validate = Loader::validate($name);
  1402. if (!empty($scene)) {
  1403. $validate->scene($scene);
  1404. }
  1405. }
  1406. $batch = is_null($batch) ? $this->batchValidate : $batch;
  1407. if (!$validate->batch($batch)->check($data)) {
  1408. $this->error = $validate->getError();
  1409. if ($this->failException) {
  1410. throw new ValidateException($this->error);
  1411. } else {
  1412. return false;
  1413. }
  1414. }
  1415. $this->validate = null;
  1416. }
  1417. return true;
  1418. }
  1419. /**
  1420. * 返回模型的错误信息
  1421. * @access public
  1422. * @return string|array
  1423. */
  1424. public function getError()
  1425. {
  1426. return $this->error;
  1427. }
  1428. /**
  1429. * 注册回调方法
  1430. * @access public
  1431. * @param string $event 事件名
  1432. * @param callable $callback 回调方法
  1433. * @param bool $override 是否覆盖
  1434. * @return void
  1435. */
  1436. public static function event($event, $callback, $override = false)
  1437. {
  1438. $class = get_called_class();
  1439. if ($override) {
  1440. self::$event[$class][$event] = [];
  1441. }
  1442. self::$event[$class][$event][] = $callback;
  1443. }
  1444. /**
  1445. * 触发事件
  1446. * @access protected
  1447. * @param string $event 事件名
  1448. * @param mixed $params 传入参数(引用)
  1449. * @return bool
  1450. */
  1451. protected function trigger($event, &$params)
  1452. {
  1453. if (isset(self::$event[$this->class][$event])) {
  1454. foreach (self::$event[$this->class][$event] as $callback) {
  1455. if (is_callable($callback)) {
  1456. $result = call_user_func_array($callback, [ & $params]);
  1457. if (false === $result) {
  1458. return false;
  1459. }
  1460. }
  1461. }
  1462. }
  1463. return true;
  1464. }
  1465. /**
  1466. * 写入数据
  1467. * @access public
  1468. * @param array $data 数据数组
  1469. * @param array|true $field 允许字段
  1470. * @return $this
  1471. */
  1472. public static function create($data = [], $field = null)
  1473. {
  1474. $model = new static();
  1475. if (!empty($field)) {
  1476. $model->allowField($field);
  1477. }
  1478. $model->isUpdate(false)->save($data, []);
  1479. return $model;
  1480. }
  1481. /**
  1482. * 更新数据
  1483. * @access public
  1484. * @param array $data 数据数组
  1485. * @param array $where 更新条件
  1486. * @param array|true $field 允许字段
  1487. * @return $this
  1488. */
  1489. public static function update($data = [], $where = [], $field = null)
  1490. {
  1491. $model = new static();
  1492. if (!empty($field)) {
  1493. $model->allowField($field);
  1494. }
  1495. $result = $model->isUpdate(true)->save($data, $where);
  1496. return $model;
  1497. }
  1498. /**
  1499. * 查找单条记录
  1500. * @access public
  1501. * @param mixed $data 主键值或者查询条件(闭包)
  1502. * @param array|string $with 关联预查询
  1503. * @param bool $cache 是否缓存
  1504. * @return static|null
  1505. * @throws exception\DbException
  1506. */
  1507. public static function get($data, $with = [], $cache = false)
  1508. {
  1509. if (is_null($data)) {
  1510. return;
  1511. }
  1512. if (true === $with || is_int($with)) {
  1513. $cache = $with;
  1514. $with = [];
  1515. }
  1516. $query = static::parseQuery($data, $with, $cache);
  1517. return $query->find($data);
  1518. }
  1519. /**
  1520. * 查找所有记录
  1521. * @access public
  1522. * @param mixed $data 主键列表或者查询条件(闭包)
  1523. * @param array|string $with 关联预查询
  1524. * @param bool $cache 是否缓存
  1525. * @return static[]|false
  1526. * @throws exception\DbException
  1527. */
  1528. public static function all($data = null, $with = [], $cache = false)
  1529. {
  1530. if (true === $with || is_int($with)) {
  1531. $cache = $with;
  1532. $with = [];
  1533. }
  1534. $query = static::parseQuery($data, $with, $cache);
  1535. return $query->select($data);
  1536. }
  1537. /**
  1538. * 分析查询表达式
  1539. * @access public
  1540. * @param mixed $data 主键列表或者查询条件(闭包)
  1541. * @param string $with 关联预查询
  1542. * @param bool $cache 是否缓存
  1543. * @return Query
  1544. */
  1545. protected static function parseQuery(&$data, $with, $cache)
  1546. {
  1547. $result = self::with($with)->cache($cache);
  1548. if (is_array($data) && key($data) !== 0) {
  1549. $result = $result->where($data);
  1550. $data = null;
  1551. } elseif ($data instanceof \Closure) {
  1552. call_user_func_array($data, [ & $result]);
  1553. $data = null;
  1554. } elseif ($data instanceof Query) {
  1555. $result = $data->with($with)->cache($cache);
  1556. $data = null;
  1557. }
  1558. return $result;
  1559. }
  1560. /**
  1561. * 删除记录
  1562. * @access public
  1563. * @param mixed $data 主键列表 支持闭包查询条件
  1564. * @return integer 成功删除的记录数
  1565. */
  1566. public static function destroy($data)
  1567. {
  1568. $model = new static();
  1569. $query = $model->db();
  1570. if (empty($data) && 0 !== $data) {
  1571. return 0;
  1572. } elseif (is_array($data) && key($data) !== 0) {
  1573. $query->where($data);
  1574. $data = null;
  1575. } elseif ($data instanceof \Closure) {
  1576. call_user_func_array($data, [ & $query]);
  1577. $data = null;
  1578. }
  1579. $resultSet = $query->select($data);
  1580. $count = 0;
  1581. if ($resultSet) {
  1582. foreach ($resultSet as $data) {
  1583. $result = $data->delete();
  1584. $count += $result;
  1585. }
  1586. }
  1587. return $count;
  1588. }
  1589. /**
  1590. * 命名范围
  1591. * @access public
  1592. * @param string|array|\Closure $name 命名范围名称 逗号分隔
  1593. * @internal mixed ...$params 参数调用
  1594. * @return Query
  1595. */
  1596. public static function scope($name)
  1597. {
  1598. $model = new static();
  1599. $query = $model->db();
  1600. $params = func_get_args();
  1601. array_shift($params);
  1602. array_unshift($params, $query);
  1603. if ($name instanceof \Closure) {
  1604. call_user_func_array($name, $params);
  1605. } elseif (is_string($name)) {
  1606. $name = explode(',', $name);
  1607. }
  1608. if (is_array($name)) {
  1609. foreach ($name as $scope) {
  1610. $method = 'scope' . trim($scope);
  1611. if (method_exists($model, $method)) {
  1612. call_user_func_array([$model, $method], $params);
  1613. }
  1614. }
  1615. }
  1616. return $query;
  1617. }
  1618. /**
  1619. * 设置是否使用全局查询范围
  1620. * @param bool $use 是否启用全局查询范围
  1621. * @access public
  1622. * @return Query
  1623. */
  1624. public static function useGlobalScope($use)
  1625. {
  1626. $model = new static();
  1627. return $model->db($use);
  1628. }
  1629. /**
  1630. * 根据关联条件查询当前模型
  1631. * @access public
  1632. * @param string $relation 关联方法名
  1633. * @param mixed $operator 比较操作符
  1634. * @param integer $count 个数
  1635. * @param string $id 关联表的统计字段
  1636. * @return Relation|Query
  1637. */
  1638. public static function has($relation, $operator = '>=', $count = 1, $id = '*')
  1639. {
  1640. $relation = (new static())->$relation();
  1641. if (is_array($operator) || $operator instanceof \Closure) {
  1642. return $relation->hasWhere($operator);
  1643. }
  1644. return $relation->has($operator, $count, $id);
  1645. }
  1646. /**
  1647. * 根据关联条件查询当前模型
  1648. * @access public
  1649. * @param string $relation 关联方法名
  1650. * @param mixed $where 查询条件(数组或者闭包)
  1651. * @param mixed $fields 字段
  1652. * @return Relation|Query
  1653. */
  1654. public static function hasWhere($relation, $where = [], $fields = null)
  1655. {
  1656. return (new static())->$relation()->hasWhere($where, $fields);
  1657. }
  1658. /**
  1659. * 解析模型的完整命名空间
  1660. * @access public
  1661. * @param string $model 模型名(或者完整类名)
  1662. * @return string
  1663. */
  1664. protected function parseModel($model)
  1665. {
  1666. if (false === strpos($model, '\\')) {
  1667. $path = explode('\\', get_called_class());
  1668. array_pop($path);
  1669. array_push($path, Loader::parseName($model, 1));
  1670. $model = implode('\\', $path);
  1671. }
  1672. return $model;
  1673. }
  1674. /**
  1675. * 查询当前模型的关联数据
  1676. * @access public
  1677. * @param string|array $relations 关联名
  1678. * @return $this
  1679. */
  1680. public function relationQuery($relations)
  1681. {
  1682. if (is_string($relations)) {
  1683. $relations = explode(',', $relations);
  1684. }
  1685. foreach ($relations as $key => $relation) {
  1686. $subRelation = '';
  1687. $closure = null;
  1688. if ($relation instanceof \Closure) {
  1689. // 支持闭包查询过滤关联条件
  1690. $closure = $relation;
  1691. $relation = $key;
  1692. }
  1693. if (is_array($relation)) {
  1694. $subRelation = $relation;
  1695. $relation = $key;
  1696. } elseif (strpos($relation, '.')) {
  1697. list($relation, $subRelation) = explode('.', $relation, 2);
  1698. }
  1699. $method = Loader::parseName($relation, 1, false);
  1700. $this->data[$relation] = $this->$method()->getRelation($subRelation, $closure);
  1701. }
  1702. return $this;
  1703. }
  1704. /**
  1705. * 预载入关联查询 返回数据集
  1706. * @access public
  1707. * @param array $resultSet 数据集
  1708. * @param string $relation 关联名
  1709. * @return array
  1710. */
  1711. public function eagerlyResultSet(&$resultSet, $relation)
  1712. {
  1713. $relations = is_string($relation) ? explode(',', $relation) : $relation;
  1714. foreach ($relations as $key => $relation) {
  1715. $subRelation = '';
  1716. $closure = false;
  1717. if ($relation instanceof \Closure) {
  1718. $closure = $relation;
  1719. $relation = $key;
  1720. }
  1721. if (is_array($relation)) {
  1722. $subRelation = $relation;
  1723. $relation = $key;
  1724. } elseif (strpos($relation, '.')) {
  1725. list($relation, $subRelation) = explode('.', $relation, 2);
  1726. }
  1727. $relation = Loader::parseName($relation, 1, false);
  1728. $this->$relation()->eagerlyResultSet($resultSet, $relation, $subRelation, $closure);
  1729. }
  1730. }
  1731. /**
  1732. * 预载入关联查询 返回模型对象
  1733. * @access public
  1734. * @param Model $result 数据对象
  1735. * @param string $relation 关联名
  1736. * @return Model
  1737. */
  1738. public function eagerlyResult(&$result, $relation)
  1739. {
  1740. $relations = is_string($relation) ? explode(',', $relation) : $relation;
  1741. foreach ($relations as $key => $relation) {
  1742. $subRelation = '';
  1743. $closure = false;
  1744. if ($relation instanceof \Closure) {
  1745. $closure = $relation;
  1746. $relation = $key;
  1747. }
  1748. if (is_array($relation)) {
  1749. $subRelation = $relation;
  1750. $relation = $key;
  1751. } elseif (strpos($relation, '.')) {
  1752. list($relation, $subRelation) = explode('.', $relation, 2);
  1753. }
  1754. $relation = Loader::parseName($relation, 1, false);
  1755. $this->$relation()->eagerlyResult($result, $relation, $subRelation, $closure);
  1756. }
  1757. }
  1758. /**
  1759. * 关联统计
  1760. * @access public
  1761. * @param Model $result 数据对象
  1762. * @param string|array $relation 关联名
  1763. * @return void
  1764. */
  1765. public function relationCount(&$result, $relation)
  1766. {
  1767. $relations = is_string($relation) ? explode(',', $relation) : $relation;
  1768. foreach ($relations as $key => $relation) {
  1769. $closure = false;
  1770. if ($relation instanceof \Closure) {
  1771. $closure = $relation;
  1772. $relation = $key;
  1773. } elseif (is_string($key)) {
  1774. $name = $relation;
  1775. $relation = $key;
  1776. }
  1777. $relation = Loader::parseName($relation, 1, false);
  1778. $count = $this->$relation()->relationCount($result, $closure);
  1779. if (!isset($name)) {
  1780. $name = Loader::parseName($relation) . '_count';
  1781. }
  1782. $result->setAttr($name, $count);
  1783. }
  1784. }
  1785. /**
  1786. * 获取模型的默认外键名
  1787. * @access public
  1788. * @param string $name 模型名
  1789. * @return string
  1790. */
  1791. protected function getForeignKey($name)
  1792. {
  1793. if (strpos($name, '\\')) {
  1794. $name = basename(str_replace('\\', '/', $name));
  1795. }
  1796. return Loader::parseName($name) . '_id';
  1797. }
  1798. /**
  1799. * HAS ONE 关联定义
  1800. * @access public
  1801. * @param string $model 模型名
  1802. * @param string $foreignKey 关联外键
  1803. * @param string $localKey 当前模型主键
  1804. * @param array $alias 别名定义(已经废弃)
  1805. * @param string $joinType JOIN类型
  1806. * @return HasOne
  1807. */
  1808. public function hasOne($model, $foreignKey = '', $localKey = '', $alias = [], $joinType = 'INNER')
  1809. {
  1810. // 记录当前关联信息
  1811. $model = $this->parseModel($model);
  1812. $localKey = $localKey ?: $this->getPk();
  1813. $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
  1814. return new HasOne($this, $model, $foreignKey, $localKey, $joinType);
  1815. }
  1816. /**
  1817. * BELONGS TO 关联定义
  1818. * @access public
  1819. * @param string $model 模型名
  1820. * @param string $foreignKey 关联外键
  1821. * @param string $localKey 关联主键
  1822. * @param array $alias 别名定义(已经废弃)
  1823. * @param string $joinType JOIN类型
  1824. * @return BelongsTo
  1825. */
  1826. public function belongsTo($model, $foreignKey = '', $localKey = '', $alias = [], $joinType = 'INNER')
  1827. {
  1828. // 记录当前关联信息
  1829. $model = $this->parseModel($model);
  1830. $foreignKey = $foreignKey ?: $this->getForeignKey($model);
  1831. $localKey = $localKey ?: (new $model)->getPk();
  1832. $trace = debug_backtrace(false, 2);
  1833. $relation = Loader::parseName($trace[1]['function']);
  1834. return new BelongsTo($this, $model, $foreignKey, $localKey, $joinType, $relation);
  1835. }
  1836. /**
  1837. * HAS MANY 关联定义
  1838. * @access public
  1839. * @param string $model 模型名
  1840. * @param string $foreignKey 关联外键
  1841. * @param string $localKey 当前模型主键
  1842. * @return HasMany
  1843. */
  1844. public function hasMany($model, $foreignKey = '', $localKey = '')
  1845. {
  1846. // 记录当前关联信息
  1847. $model = $this->parseModel($model);
  1848. $localKey = $localKey ?: $this->getPk();
  1849. $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
  1850. return new HasMany($this, $model, $foreignKey, $localKey);
  1851. }
  1852. /**
  1853. * HAS MANY 远程关联定义
  1854. * @access public
  1855. * @param string $model 模型名
  1856. * @param string $through 中间模型名
  1857. * @param string $foreignKey 关联外键
  1858. * @param string $throughKey 关联外键
  1859. * @param string $localKey 当前模型主键
  1860. * @return HasManyThrough
  1861. */
  1862. public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '')
  1863. {
  1864. // 记录当前关联信息
  1865. $model = $this->parseModel($model);
  1866. $through = $this->parseModel($through);
  1867. $localKey = $localKey ?: $this->getPk();
  1868. $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
  1869. $throughKey = $throughKey ?: $this->getForeignKey($through);
  1870. return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey);
  1871. }
  1872. /**
  1873. * BELONGS TO MANY 关联定义
  1874. * @access public
  1875. * @param string $model 模型名
  1876. * @param string $table 中间表名
  1877. * @param string $foreignKey 关联外键
  1878. * @param string $localKey 当前模型关联键
  1879. * @return BelongsToMany
  1880. */
  1881. public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = '')
  1882. {
  1883. // 记录当前关联信息
  1884. $model = $this->parseModel($model);
  1885. $name = Loader::parseName(basename(str_replace('\\', '/', $model)));
  1886. $table = $table ?: Loader::parseName($this->name) . '_' . $name;
  1887. $foreignKey = $foreignKey ?: $name . '_id';
  1888. $localKey = $localKey ?: $this->getForeignKey($this->name);
  1889. return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
  1890. }
  1891. /**
  1892. * MORPH MANY 关联定义
  1893. * @access public
  1894. * @param string $model 模型名
  1895. * @param string|array $morph 多态字段信息
  1896. * @param string $type 多态类型
  1897. * @return MorphMany
  1898. */
  1899. public function morphMany($model, $morph = null, $type = '')
  1900. {
  1901. // 记录当前关联信息
  1902. $model = $this->parseModel($model);
  1903. if (is_null($morph)) {
  1904. $trace = debug_backtrace(false, 2);
  1905. $morph = Loader::parseName($trace[1]['function']);
  1906. }
  1907. $type = $type ?: get_class($this);
  1908. if (is_array($morph)) {
  1909. list($morphType, $foreignKey) = $morph;
  1910. } else {
  1911. $morphType = $morph . '_type';
  1912. $foreignKey = $morph . '_id';
  1913. }
  1914. return new MorphMany($this, $model, $foreignKey, $morphType, $type);
  1915. }
  1916. /**
  1917. * MORPH One 关联定义
  1918. * @access public
  1919. * @param string $model 模型名
  1920. * @param string|array $morph 多态字段信息
  1921. * @param string $type 多态类型
  1922. * @return MorphOne
  1923. */
  1924. public function morphOne($model, $morph = null, $type = '')
  1925. {
  1926. // 记录当前关联信息
  1927. $model = $this->parseModel($model);
  1928. if (is_null($morph)) {
  1929. $trace = debug_backtrace(false, 2);
  1930. $morph = Loader::parseName($trace[1]['function']);
  1931. }
  1932. $type = $type ?: get_class($this);
  1933. if (is_array($morph)) {
  1934. list($morphType, $foreignKey) = $morph;
  1935. } else {
  1936. $morphType = $morph . '_type';
  1937. $foreignKey = $morph . '_id';
  1938. }
  1939. return new MorphOne($this, $model, $foreignKey, $morphType, $type);
  1940. }
  1941. /**
  1942. * MORPH TO 关联定义
  1943. * @access public
  1944. * @param string|array $morph 多态字段信息
  1945. * @param array $alias 多态别名定义
  1946. * @return MorphTo
  1947. */
  1948. public function morphTo($morph = null, $alias = [])
  1949. {
  1950. $trace = debug_backtrace(false, 2);
  1951. $relation = Loader::parseName($trace[1]['function']);
  1952. if (is_null($morph)) {
  1953. $morph = $relation;
  1954. }
  1955. // 记录当前关联信息
  1956. if (is_array($morph)) {
  1957. list($morphType, $foreignKey) = $morph;
  1958. } else {
  1959. $morphType = $morph . '_type';
  1960. $foreignKey = $morph . '_id';
  1961. }
  1962. return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
  1963. }
  1964. public function __call($method, $args)
  1965. {
  1966. $query = $this->db(true, false);
  1967. if (method_exists($this, 'scope' . $method)) {
  1968. // 动态调用命名范围
  1969. $method = 'scope' . $method;
  1970. array_unshift($args, $query);
  1971. call_user_func_array([$this, $method], $args);
  1972. return $this;
  1973. } else {
  1974. return call_user_func_array([$query, $method], $args);
  1975. }
  1976. }
  1977. public static function __callStatic($method, $args)
  1978. {
  1979. $model = new static();
  1980. $query = $model->db();
  1981. if (method_exists($model, 'scope' . $method)) {
  1982. // 动态调用命名范围
  1983. $method = 'scope' . $method;
  1984. array_unshift($args, $query);
  1985. call_user_func_array([$model, $method], $args);
  1986. return $query;
  1987. } else {
  1988. return call_user_func_array([$query, $method], $args);
  1989. }
  1990. }
  1991. /**
  1992. * 修改器 设置数据对象的值
  1993. * @access public
  1994. * @param string $name 名称
  1995. * @param mixed $value 值
  1996. * @return void
  1997. */
  1998. public function __set($name, $value)
  1999. {
  2000. $this->setAttr($name, $value);
  2001. }
  2002. /**
  2003. * 获取器 获取数据对象的值
  2004. * @access public
  2005. * @param string $name 名称
  2006. * @return mixed
  2007. */
  2008. public function __get($name)
  2009. {
  2010. return $this->getAttr($name);
  2011. }
  2012. /**
  2013. * 检测数据对象的值
  2014. * @access public
  2015. * @param string $name 名称
  2016. * @return boolean
  2017. */
  2018. public function __isset($name)
  2019. {
  2020. try {
  2021. if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) {
  2022. return true;
  2023. } else {
  2024. $this->getAttr($name);
  2025. return true;
  2026. }
  2027. } catch (InvalidArgumentException $e) {
  2028. return false;
  2029. }
  2030. }
  2031. /**
  2032. * 销毁数据对象的值
  2033. * @access public
  2034. * @param string $name 名称
  2035. * @return void
  2036. */
  2037. public function __unset($name)
  2038. {
  2039. unset($this->data[$name], $this->relation[$name]);
  2040. }
  2041. public function __toString()
  2042. {
  2043. return $this->toJson();
  2044. }
  2045. // JsonSerializable
  2046. public function jsonSerialize()
  2047. {
  2048. return $this->toArray();
  2049. }
  2050. // ArrayAccess
  2051. public function offsetSet($name, $value)
  2052. {
  2053. $this->setAttr($name, $value);
  2054. }
  2055. public function offsetExists($name)
  2056. {
  2057. return $this->__isset($name);
  2058. }
  2059. public function offsetUnset($name)
  2060. {
  2061. $this->__unset($name);
  2062. }
  2063. public function offsetGet($name)
  2064. {
  2065. return $this->getAttr($name);
  2066. }
  2067. /**
  2068. * 解序列化后处理
  2069. */
  2070. public function __wakeup()
  2071. {
  2072. $this->initialize();
  2073. }
  2074. /**
  2075. * 模型事件快捷方法
  2076. * @param $callback
  2077. * @param bool $override
  2078. */
  2079. protected static function beforeInsert($callback, $override = false)
  2080. {
  2081. self::event('before_insert', $callback, $override);
  2082. }
  2083. protected static function afterInsert($callback, $override = false)
  2084. {
  2085. self::event('after_insert', $callback, $override);
  2086. }
  2087. protected static function beforeUpdate($callback, $override = false)
  2088. {
  2089. self::event('before_update', $callback, $override);
  2090. }
  2091. protected static function afterUpdate($callback, $override = false)
  2092. {
  2093. self::event('after_update', $callback, $override);
  2094. }
  2095. protected static function beforeWrite($callback, $override = false)
  2096. {
  2097. self::event('before_write', $callback, $override);
  2098. }
  2099. protected static function afterWrite($callback, $override = false)
  2100. {
  2101. self::event('after_write', $callback, $override);
  2102. }
  2103. protected static function beforeDelete($callback, $override = false)
  2104. {
  2105. self::event('before_delete', $callback, $override);
  2106. }
  2107. protected static function afterDelete($callback, $override = false)
  2108. {
  2109. self::event('after_delete', $callback, $override);
  2110. }
  2111. }