BaseServices.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace qiniu\basic;
  12. //use crmeb\utils\JwtAuth;
  13. use app\jobs\system\ExportExcelJob;
  14. use qiniu\exceptions\AdminException;
  15. use qiniu\services\SpreadsheetExcelService;
  16. use qiniu\utils\JwtAuth;
  17. use think\facade\Db;
  18. use think\facade\Config;
  19. use think\facade\Route as Url;
  20. use think\Model;
  21. /**
  22. * Class BaseServices
  23. * @package app\services
  24. */
  25. abstract class BaseServices
  26. {
  27. /**
  28. * 模型注入
  29. * @var object
  30. */
  31. protected $model;
  32. protected $exportHeader = [];
  33. public function getHeader()
  34. {
  35. return $this->exportHeader;
  36. }
  37. /**
  38. * 获取分页配置
  39. * @param bool $isPage
  40. * @param bool $isRelieve
  41. * @return int[]
  42. */
  43. public function getPageValue(bool $isPage = true, bool $isRelieve = true)
  44. {
  45. $page = $limit = 0;
  46. if ($isPage) {
  47. $page = app()->request->param(Config::get('database.page.pageKey', 'page') . '/d', 0);
  48. $limit = app()->request->param(Config::get('database.page.limitKey', 'limit') . '/d', 0);
  49. }
  50. $limitMax = Config::get('database.page.limitMax', 100);
  51. $defaultLimit = Config::get('database.page.defaultLimit', 10);
  52. if ($limit > $limitMax && $isRelieve) {
  53. $limit = $limitMax;
  54. }
  55. return [(int)$page, (int)$limit, (int)$defaultLimit];
  56. }
  57. /**
  58. * 数据库事务操作
  59. * @param callable $closure
  60. * @return mixed
  61. */
  62. public function transaction(callable $closure, bool $isTran = true)
  63. {
  64. return $isTran ? Db::transaction($closure) : $closure();
  65. }
  66. // /**
  67. // * 创建token
  68. // * @param int $id
  69. // * @param $type
  70. // * @return array
  71. // */
  72. // public function createToken(int $id, $type, string $pwd = '')
  73. // {
  74. // /** @var JwtAuth $jwtAuth */
  75. // $jwtAuth = app()->make(JwtAuth::class);
  76. // return $jwtAuth->createToken($id, $type, ['auth' => md5($pwd)]);
  77. // }
  78. /**
  79. * 获取路由地址
  80. * @param string $path
  81. * @param array $params
  82. * @param bool $suffix
  83. * @param bool $isDomain
  84. * @return string
  85. */
  86. public function url(string $path, array $params = [], bool $suffix = false, bool $isDomain = false)
  87. {
  88. return Url::buildUrl($path, $params)->suffix($suffix)->domain($isDomain)->build();
  89. }
  90. /**
  91. * 密码hash加密
  92. * @param string $password
  93. * @return false|string|null
  94. */
  95. public function passwordHash(string $password)
  96. {
  97. return password_hash($password, PASSWORD_BCRYPT);
  98. }
  99. /**
  100. * 创建token
  101. * @param int $id
  102. * @param $type
  103. * @param string $pwd
  104. * @return array
  105. */
  106. public function createToken(int $id, $type, string $pwd = '')
  107. {
  108. /** @var JwtAuth $jwtAuth */
  109. $jwtAuth = app()->make(JwtAuth::class);
  110. return $jwtAuth->createToken($id, $type, ['auth' => md5($pwd)]);
  111. }
  112. /**
  113. * 格式化时间
  114. * @param $time
  115. * @param bool $is_time_key
  116. * @return array
  117. */
  118. public function timeHandle($time, bool $is_time_key = false)
  119. {
  120. switch ($time) {
  121. case 'today':
  122. $start = date('Y-m-d 00:00:00');
  123. $end = date('Y-m-d 23:59:59');
  124. break;
  125. case 'yesterday':
  126. $start = date('Y-m-d 00:00:00', strtotime("-1 day"));
  127. $end = date('Y-m-d 23:59:59', strtotime("-1 day"));
  128. break;
  129. case 'sevenday':
  130. $start = date('Y-m-d 00:00:00', strtotime('-6 day'));
  131. $end = date('Y-m-d 23:59:59');
  132. break;
  133. case 'thirtyday':
  134. $start = date('Y-m-d 00:00:00', strtotime('-29 day'));
  135. $end = date('Y-m-d 23:59:59');
  136. break;
  137. case 'last month':
  138. $start = date('Y-m-01 00:00:00', strtotime('first Day of last month 00:00:00'));
  139. $end = date("Y-m-d 23:59:59", strtotime('first Day of this month 00:00:00 -1second'));
  140. break;
  141. case 'month':
  142. $start = date('Y-m-01 00:00:00');
  143. $end = date('Y-m-d 23:59:59', mktime(23, 59, 59, date('m'), date('t'), date('Y')));
  144. break;
  145. case 'year':
  146. $start = date('Y-01-01 00:00:00');
  147. $end = date('Y-12-31 23:59:59');
  148. break;
  149. default:
  150. $start = date("Y/m/d", strtotime("-30 days", time()));
  151. $end = date("Y/m/d", time());
  152. if (strstr($time, '-') !== false) {
  153. [$start_r, $end_r] = explode('-', $time);
  154. if ($start_r || $end_r) {
  155. $start = $start_r;
  156. $end = $end_r;
  157. $end_time = strtotime($end_r);
  158. //没选具体时分秒 加上86400
  159. if ($end_time == strtotime(date('Y/m/d', $end_time))) {
  160. $end = date('Y/m/d H:i:s', $end_time + 86399);
  161. }
  162. }
  163. }
  164. break;
  165. }
  166. $start = $start ? strtotime($start) : 0;
  167. $end = $end ? strtotime($end) : 0;
  168. if ($is_time_key) {
  169. $dayCount = ceil(($end - $start) / 86400);
  170. $s_start = $start;
  171. $timeKey = [];
  172. if ($dayCount == 1) {
  173. $timeType = 'hour';
  174. $timeKey = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'];
  175. } elseif ($dayCount <= 31) {
  176. $timeType = 'day';
  177. for ($i = 0; $i < $dayCount; $i++) {
  178. $timeKey[] = date('Y-m-d', $s_start);
  179. $s_start = strtotime("+1 day", $s_start);
  180. }
  181. } elseif ($dayCount <= 92) {
  182. $timeType = 'weekly';
  183. for ($i = 0; $i < $dayCount; $i = $i + 7) {
  184. $timeKey[] = '第' . date('W', $s_start) . '周';
  185. $s_start = strtotime("+1 week", $s_start);
  186. }
  187. } else {
  188. $timeType = 'year';
  189. while ($s_start <= $end) {
  190. $timeKey[] = date('Y-m', $s_start);
  191. $s_start = strtotime("+1 month", $s_start);
  192. }
  193. }
  194. return [$start, $end, $timeType, $timeKey];
  195. }
  196. return [$start, $end];
  197. }
  198. /**
  199. * 计算环比增长率
  200. * @param $nowValue
  201. * @param $lastValue
  202. * @return float|int|string
  203. */
  204. public function countRate($nowValue, $lastValue)
  205. {
  206. if ($lastValue == 0 && $nowValue == 0) return 0;
  207. if ($lastValue == 0) return round(bcmul(bcdiv($nowValue, 1, 4), 100, 2), 2);
  208. if ($nowValue == 0) return -round(bcmul(bcdiv($lastValue, 1, 4), 100, 2), 2);
  209. return bcmul(bcdiv((bcsub($nowValue, $lastValue, 2)), $lastValue, 4), 100, 2);
  210. }
  211. /**
  212. * tree处理 分类、标签数据(这一类数据)
  213. * @param array $cate
  214. * @param array $label
  215. * @return array
  216. */
  217. public function get_tree_children(array $cate, array $label)
  218. {
  219. if ($cate) {
  220. foreach ($cate as $key => $value) {
  221. if ($label) {
  222. foreach ($label as $k => $item) {
  223. if ($value['id'] == $item['label_cate']) {
  224. $cate[$key]['children'][] = $item;
  225. unset($label[$k]);
  226. }
  227. }
  228. } else {
  229. $cate[$key]['children'] = [];
  230. }
  231. }
  232. }
  233. return $cate;
  234. }
  235. /**
  236. * ip转城市
  237. * @param $ip
  238. * @return array|string|string[]|null
  239. */
  240. public function convertIp($ip)
  241. {
  242. try {
  243. $ip1num = 0;
  244. $ip2num = 0;
  245. $ipAddr1 = "";
  246. $ipAddr2 = "";
  247. $dat_path = public_path() . 'statics/ip.dat';
  248. if (!preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip)) {
  249. return '';
  250. }
  251. if (!$fd = @fopen($dat_path, 'rb')) {
  252. return '';
  253. }
  254. $ip = explode('.', $ip);
  255. $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
  256. $DataBegin = fread($fd, 4);
  257. $DataEnd = fread($fd, 4);
  258. $ipbegin = implode('', unpack('L', $DataBegin));
  259. if ($ipbegin < 0) $ipbegin += pow(2, 32);
  260. $ipend = implode('', unpack('L', $DataEnd));
  261. if ($ipend < 0) $ipend += pow(2, 32);
  262. $ipAllNum = ($ipend - $ipbegin) / 7 + 1;
  263. $BeginNum = 0;
  264. $EndNum = $ipAllNum;
  265. while ($ip1num > $ipNum || $ip2num < $ipNum) {
  266. $Middle = intval(($EndNum + $BeginNum) / 2);
  267. fseek($fd, $ipbegin + 7 * $Middle);
  268. $ipData1 = fread($fd, 4);
  269. if (strlen($ipData1) < 4) {
  270. fclose($fd);
  271. return '';
  272. }
  273. $ip1num = implode('', unpack('L', $ipData1));
  274. if ($ip1num < 0) $ip1num += pow(2, 32);
  275. if ($ip1num > $ipNum) {
  276. $EndNum = $Middle;
  277. continue;
  278. }
  279. $DataSeek = fread($fd, 3);
  280. if (strlen($DataSeek) < 3) {
  281. fclose($fd);
  282. return '';
  283. }
  284. $DataSeek = implode('', unpack('L', $DataSeek . chr(0)));
  285. fseek($fd, $DataSeek);
  286. $ipData2 = fread($fd, 4);
  287. if (strlen($ipData2) < 4) {
  288. fclose($fd);
  289. return '';
  290. }
  291. $ip2num = implode('', unpack('L', $ipData2));
  292. if ($ip2num < 0) $ip2num += pow(2, 32);
  293. if ($ip2num < $ipNum) {
  294. if ($Middle == $BeginNum) {
  295. fclose($fd);
  296. return '';
  297. }
  298. $BeginNum = $Middle;
  299. }
  300. }
  301. $ipFlag = fread($fd, 1);
  302. if ($ipFlag == chr(1)) {
  303. $ipSeek = fread($fd, 3);
  304. if (strlen($ipSeek) < 3) {
  305. fclose($fd);
  306. return '';
  307. }
  308. $ipSeek = implode('', unpack('L', $ipSeek . chr(0)));
  309. fseek($fd, $ipSeek);
  310. $ipFlag = fread($fd, 1);
  311. }
  312. if ($ipFlag == chr(2)) {
  313. $AddrSeek = fread($fd, 3);
  314. if (strlen($AddrSeek) < 3) {
  315. fclose($fd);
  316. return '';
  317. }
  318. $ipFlag = fread($fd, 1);
  319. if ($ipFlag == chr(2)) {
  320. $AddrSeek2 = fread($fd, 3);
  321. if (strlen($AddrSeek2) < 3) {
  322. fclose($fd);
  323. return '';
  324. }
  325. $AddrSeek2 = implode('', unpack('L', $AddrSeek2 . chr(0)));
  326. fseek($fd, $AddrSeek2);
  327. } else {
  328. fseek($fd, -1, SEEK_CUR);
  329. }
  330. while (($char = fread($fd, 1)) != chr(0))
  331. $ipAddr2 .= $char;
  332. $AddrSeek = implode('', unpack('L', $AddrSeek . chr(0)));
  333. fseek($fd, $AddrSeek);
  334. while (($char = fread($fd, 1)) != chr(0))
  335. $ipAddr1 .= $char;
  336. } else {
  337. fseek($fd, -1, SEEK_CUR);
  338. while (($char = fread($fd, 1)) != chr(0))
  339. $ipAddr1 .= $char;
  340. $ipFlag = fread($fd, 1);
  341. if ($ipFlag == chr(2)) {
  342. $AddrSeek2 = fread($fd, 3);
  343. if (strlen($AddrSeek2) < 3) {
  344. fclose($fd);
  345. return '';
  346. }
  347. $AddrSeek2 = implode('', unpack('L', $AddrSeek2 . chr(0)));
  348. fseek($fd, $AddrSeek2);
  349. } else {
  350. fseek($fd, -1, SEEK_CUR);
  351. }
  352. while (($char = fread($fd, 1)) != chr(0)) {
  353. $ipAddr2 .= $char;
  354. }
  355. }
  356. fclose($fd);
  357. if (preg_match('/http/i', $ipAddr2)) {
  358. $ipAddr2 = '';
  359. }
  360. $ipaddr = $ipAddr1;
  361. $ipaddr = preg_replace('/CZ88.NET/is', '', $ipaddr);
  362. $ipaddr = preg_replace('/^s*/is', '', $ipaddr);
  363. $ipaddr = preg_replace('/s*$/is', '', $ipaddr);
  364. if (preg_match('/http/i', $ipaddr) || $ipaddr == '') {
  365. $ipaddr = '';
  366. }
  367. return $this->strToUtf8($ipaddr);
  368. } catch (\Throwable $e) {
  369. return '';
  370. }
  371. }
  372. /**
  373. * 文字格式转utf8
  374. * @param $str
  375. * @return array|false|string|string[]|null
  376. */
  377. public function strToUtf8($str)
  378. {
  379. $encode = mb_detect_encoding($str, array("ASCII", 'UTF-8', "GB2312", "GBK", 'BIG5'));
  380. if ($encode == 'UTF-8') {
  381. return $str;
  382. } else {
  383. return mb_convert_encoding($str, 'UTF-8', $encode);
  384. }
  385. }
  386. /**
  387. * 处理城市数据
  388. * @param $address
  389. * @return array
  390. */
  391. public function addressHandle($address)
  392. {
  393. if ($address) {
  394. try {
  395. preg_match('/(.*?(省|自治区|北京市|天津市|上海市|重庆市|澳门特别行政区|香港特别行政区))/', $address, $matches);
  396. if (count($matches) > 1) {
  397. $province = $matches[count($matches) - 2];
  398. $address = preg_replace('/(.*?(省|自治区|北京市|天津市|上海市|重庆市|澳门特别行政区|香港特别行政区))/', '', $address, 1);
  399. }
  400. preg_match('/(.*?(市|自治州|地区|区划|县))/', $address, $matches);
  401. if (count($matches) > 1) {
  402. $city = $matches[count($matches) - 2];
  403. $address = str_replace($city, '', $address);
  404. }
  405. preg_match('/(.*?(区|县|镇|乡|街道))/', $address, $matches);
  406. if (count($matches) > 1) {
  407. $area = $matches[count($matches) - 2];
  408. $address = str_replace($area, '', $address);
  409. }
  410. } catch (\Throwable $e) {
  411. }
  412. }
  413. return [
  414. 'province' => $province ?? '',
  415. 'city' => $city ?? '',
  416. 'district' => $area ?? '',
  417. "address" => $address
  418. ];
  419. }
  420. /**
  421. * 插入数据
  422. * @param array $data
  423. * @return BaseModel|Model
  424. */
  425. public function create(array $data)
  426. {
  427. if (method_exists($this->model, 'setAddTimeAttr') && !isset($data['add_time'])) {
  428. $data['add_time'] = time();
  429. }
  430. return $this->model->create($data);
  431. }
  432. /**
  433. * 更新数据
  434. * @param int|string|array $id
  435. * @param array $data
  436. * @param string|null $key
  437. * @return mixed
  438. */
  439. public function update($id, array $data, ?string $key = null)
  440. {
  441. if (is_array($id)) {
  442. $where = $id;
  443. } else {
  444. $where = [is_null($key) ? $this->model->getPk() : $key => $id];
  445. }
  446. return $this->model->update($data, $where);
  447. }
  448. /**
  449. * 删除
  450. * @param int|string|array $id
  451. * @return mixed
  452. */
  453. public function delete($id, ?string $key = null)
  454. {
  455. if (is_array($id)) {
  456. $where = $id;
  457. } else {
  458. $where = [is_null($key) ? $this->model->getPk() : $key => $id];
  459. }
  460. $info = $this->model->where($where)->find();
  461. if (!$info) return false;
  462. return $info->delete();
  463. }
  464. /**
  465. * 高精度加法
  466. * @param int|string $key
  467. * @param string $incField
  468. * @param string $inc
  469. * @param string|null $keyField
  470. * @param int $acc
  471. * @return bool
  472. */
  473. public function bcInc($key, string $incField, string $inc, string $keyField = null, int $acc = 2)
  474. {
  475. return $this->bc($key, $incField, $inc, $keyField, 1);
  476. }
  477. /**
  478. * 高精度 减法
  479. * @param $key
  480. * @param string $decField 相减的字段
  481. * @param string $dec 减的值
  482. * @param string|null $keyField id的字段
  483. * @param int $acc 精度
  484. * @param bool $dec_return_false 减法 不够减是否返回false || 减为0
  485. * @return bool
  486. */
  487. public function bcDec($key, string $decField, string $dec, string $keyField = null, int $acc = 2, bool $dec_return_false = true)
  488. {
  489. return $this->bc($key, $decField, $dec, $keyField, 2, $acc, $dec_return_false);
  490. }
  491. /**
  492. * 高精度计算并保存
  493. * @param $key
  494. * @param string $incField
  495. * @param string $inc
  496. * @param string|null $keyField
  497. * @param int $type
  498. * @param int $acc
  499. * @param bool $dec_return_false 减法 不够减是否返回false || 减为0
  500. * @return bool
  501. */
  502. public function bc($key, string $incField, string $inc, string $keyField = null, int $type = 1, int $acc = 2, bool $dec_return_false = true)
  503. {
  504. if ($keyField === null) {
  505. $result = $this->model->get($key);
  506. } else {
  507. $result = $this->model->getOne([$keyField => $key]);
  508. }
  509. if (!$result) return false;
  510. if ($type === 1) {
  511. $new = bcadd($result[$incField], $inc, $acc);
  512. } else if ($type === 2) {
  513. if ($result[$incField] < $inc) {
  514. if ($dec_return_false) return false;
  515. $new = 0;
  516. } else {
  517. $new = bcsub($result[$incField], $inc, $acc);
  518. }
  519. }
  520. $result->{$incField} = $new;
  521. return false !== $result->save();
  522. }
  523. /**
  524. * @param $where
  525. * @return array|array[]
  526. */
  527. public function export($where = [], $export_type = 1)
  528. {
  529. $list = $this->getExportList($where, '*');
  530. if (empty($list)) {
  531. throw new AdminException('暂无数据');
  532. }
  533. $export = [];
  534. $modelName = $this->model->modelName();
  535. $headers = $this->getHeader();
  536. if (!count($headers)) throw new AdminException('请设置导出字段');
  537. $header = array_values($headers);
  538. $keys = array_keys($headers);
  539. $title = [$modelName . '导出', $modelName . '信息' . time(), ' 生成时间:' . date('Y-m-d H:i:s', time())];
  540. $filename = $modelName . '导出_' . date('YmdHis', time());
  541. $i = 0;
  542. foreach ($list as $v) {
  543. $one_data = [];
  544. foreach ($headers as $k => $vv) {
  545. if (isset($v[$k]) && is_array($v[$k])) {
  546. $one_data[$k] = implode("\n", $v[$k]);
  547. } else {
  548. $one_data[$k] = $v[$k] ?? '';
  549. }
  550. }
  551. if ($export_type == 1) {
  552. $export[] = $one_data;
  553. } else {
  554. $export[] = array_values($one_data);
  555. }
  556. $i++;
  557. }
  558. if ($export_type == 1) {
  559. return compact('header', 'keys', 'export', 'filename');
  560. } else {
  561. return ['path' => $this->excel($header, $title, $export, $filename)];
  562. }
  563. }
  564. /**
  565. * 真实请求导出
  566. * @param array $header excel表头
  567. * @param array $title_arr
  568. * @param array $export 填充数据
  569. * @param string $filename 保存文件名称
  570. * @param string $suffix 保存文件后缀
  571. * @param bool $is_save true|false 是否保存到本地
  572. * @return mixed
  573. */
  574. private function excel(array $header, array $title_arr, array $export = [], string $filename = '', string $suffix = 'xlsx', bool $is_save = true)
  575. {
  576. $path = [];
  577. $exportNum = count($export);
  578. $limit = $this->model->limit;
  579. if ($exportNum < $limit) {
  580. $title = isset($title_arr[0]) && !empty($title_arr[0]) ? $title_arr[0] : '导出数据';
  581. $name = isset($title_arr[1]) && !empty($title_arr[1]) ? $title_arr[1] : '导出数据';
  582. $info = isset($title_arr[2]) && !empty($title_arr[2]) ? $title_arr[2] : date('Y-m-d H:i:s', time());
  583. $filePath = SpreadsheetExcelService::instance()->setExcelHeader($header)
  584. ->setExcelTile($title, $name, $info)
  585. ->setExcelContent($export)
  586. ->excelSave($filename, $suffix, $is_save);
  587. $path[] = sys_config('site_url') . $filePath;
  588. } else {
  589. $data = [];
  590. $i = $j = 0;
  591. $basePath = sys_config('site_url') . '/phpExcel/';
  592. foreach ($export as $item) {
  593. $data[] = $item;
  594. $i++;
  595. if ($limit <= 1 || $i == $exportNum) {
  596. if ($j > 0) {
  597. $filename .= '_' . $j;
  598. $header = [];
  599. $title_arr = [];
  600. }
  601. //加入队列
  602. ExportExcelJob::dispatch([$data, $filename, $header, $title_arr, $suffix, $is_save]);
  603. $path[] = $basePath . $filename . '.' . $suffix;
  604. $data = [];
  605. $limit = $this->model->limit + 1;
  606. $j++;
  607. }
  608. $limit--;
  609. }
  610. }
  611. return $path;
  612. }
  613. /**
  614. * @param $name
  615. * @param $arguments
  616. * @return mixed
  617. */
  618. public function __call($name, $arguments)
  619. {
  620. return call_user_func_array([$this->model, $name], $arguments);
  621. }
  622. }