Model.php 69 KB

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