Archives.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <?php
  2. namespace addons\cms\model;
  3. use addons\cms\library\Service;
  4. use app\common\library\Auth;
  5. use think\Cache;
  6. use think\Db;
  7. use think\Model;
  8. use traits\model\SoftDelete;
  9. /**
  10. * 文章模型
  11. */
  12. class Archives extends Model
  13. {
  14. protected $name = "cms_archives";
  15. // 开启自动写入时间戳字段
  16. protected $autoWriteTimestamp = 'int';
  17. // 定义时间戳字段名
  18. protected $createTime = 'createtime';
  19. protected $updateTime = 'updatetime';
  20. protected $deleteTime = 'deletetime';
  21. // 追加属性
  22. protected $append = [
  23. 'url',
  24. 'fullurl',
  25. 'likeratio',
  26. 'taglist',
  27. 'create_date',
  28. ];
  29. protected static $config = [];
  30. protected static $tagCount = 0;
  31. use SoftDelete;
  32. /**
  33. * 批量设置数据
  34. * @param $data
  35. * @return $this
  36. */
  37. public function setData($data)
  38. {
  39. if (is_object($data)) {
  40. $data = get_object_vars($data);
  41. }
  42. //替换付费内容标签
  43. if (isset($data['content'])) {
  44. $data['content'] = str_replace(['##paidbegin##', '##paidend##'], ['<paid>', '</paid>'], $data['content']);
  45. $data['content'] = str_replace(['$$paidbegin$$', '$$paidend$$'], ['<paid>', '</paid>'], $data['content']);
  46. }
  47. $this->data = array_merge($this->data, $data);
  48. $this->origin = $this->data;
  49. return $this;
  50. }
  51. protected static function init()
  52. {
  53. $config = get_addon_config('cms');
  54. self::$config = $config;
  55. }
  56. public function getCreateDateAttr($value, $data)
  57. {
  58. return human_date($data['createtime']);
  59. }
  60. public function getHasimageAttr($value, $data)
  61. {
  62. return $this->getData("image") ? true : false;
  63. }
  64. public function getIscommentAttr($value, $data)
  65. {
  66. //优先判断全局评论开关
  67. $iscomment = self::$config['iscomment'] ?? 1;
  68. if ($iscomment) {
  69. $iscomment = $value ? $value : self::$config['iscomment'];
  70. }
  71. return $iscomment;
  72. }
  73. public function getImageAttr($value, $data)
  74. {
  75. $value = $value ? $value : self::$config['default_archives_img'];
  76. return cdnurl($value, true);
  77. }
  78. public function getImagesAttr($value, $data)
  79. {
  80. if (!$data['images']) {
  81. return '';
  82. }
  83. $images = explode(',', $data['images']);
  84. foreach ($images as $index => &$image) {
  85. $image = cdnurl($image, true);
  86. }
  87. return implode(',', $images);
  88. }
  89. public function getImagesListAttr($value, $data)
  90. {
  91. $images = $this->getAttr("images");
  92. return $images ? array_filter(explode(',', $images)) : [];
  93. }
  94. /**
  95. * 获取格式化的内容
  96. */
  97. public function getContentAttr($value, $data)
  98. {
  99. //如果内容中包含有付费标签
  100. $value = $data['content'];
  101. $pattern = '/<paid>(.*?)<\/paid>/is';
  102. if (preg_match($pattern, $value) && !$this->getAttr('ispaid')) {
  103. $paytype = static::$config['defaultpaytype'];
  104. $payurl = addon_url('cms/order/submit', ['id' => $data['id'], 'paytype' => $paytype]);
  105. if (!isset($data['price']) || $data['price'] <= 0) {
  106. $value = preg_replace($pattern, "<div class='alert alert-warning alert-paid'><a href='javascript:' class=''>内容已经隐藏</a></div>", $value);
  107. } else {
  108. $value = preg_replace($pattern, "<div class='alert alert-warning alert-paid'><a href='{$payurl}' class='btn-paynow' data-price='{$data['price']}' data-paytype='{$paytype}'>内容已经隐藏,点击付费后查看</a></div>", $value);
  109. }
  110. }
  111. $config = get_addon_config('cms');
  112. if (isset($config['realtimereplacelink']) && $config['realtimereplacelink']) {
  113. $value = Service::autolinks($value);
  114. }
  115. return $value;
  116. }
  117. /**
  118. * 获取金额
  119. */
  120. public function getPriceAttr($value, &$data)
  121. {
  122. if (isset($data['price'])) {
  123. return $data['price'];
  124. }
  125. $price = 0;
  126. if (isset($data['model_id'])) {
  127. $model = Modelx::get($data['model_id']);
  128. if ($model && in_array('price', $model['fields'])) {
  129. $price = Db::name($model['table'])->where('id', $data['id'])->value('price');
  130. }
  131. }
  132. $data['price'] = $price;
  133. return $price;
  134. }
  135. /**
  136. * 判断是否支付
  137. */
  138. public function getIspayAttr($value, &$data)
  139. {
  140. return $this->getAttr('ispaid');
  141. }
  142. /**
  143. * 判断是否支付
  144. */
  145. public function getIspaidAttr($value, &$data)
  146. {
  147. if (isset($data['ispaid'])) {
  148. return $data['ispaid'];
  149. }
  150. $channel = isset($this->channel) ? $this->channel : null;
  151. //只有当未设定VIP时才判断付费字段
  152. if ($channel && !$channel->vip) {
  153. //如果未定义price字段或price字段值为0
  154. if (!isset($data['price']) || $data['price'] == 0) {
  155. return true;
  156. }
  157. }
  158. $isvip = $channel && isset($channel['vip']) && $channel['vip'] && Auth::instance()->vip >= $channel->vip ? true : false;
  159. $data['ispaid'] = $isvip || \addons\cms\library\Order::check($data['id']);
  160. return $data['ispaid'];
  161. }
  162. /**
  163. * 判断是否是部分内容付费
  164. */
  165. public function getIsPaidPartOfContentAttr($value, $data)
  166. {
  167. if (isset($data['is_paid_part_of_content'])) {
  168. return $data['is_paid_part_of_content'];
  169. }
  170. $value = isset($this->origin['content']) ? $this->origin['content'] : '';
  171. $result = preg_match('/<paid>(.*?)<\/paid>/is', $value);
  172. $data['is_paid_part_of_content'] = $result;
  173. return $result;
  174. }
  175. /**
  176. * 获取下载地址列表
  177. */
  178. public function getDownloadurlListAttr($value, $data)
  179. {
  180. $titleArr = isset(self::$config['downloadtype']) ? self::$config['downloadtype'] : [];
  181. $downloadurl = (array)json_decode($data['downloadurl'], true);
  182. $downloadurl = array_filter($downloadurl);
  183. $list = [];
  184. foreach ($downloadurl as $index => $item) {
  185. if (!is_array($item)) {
  186. $urlArr = explode(' ', $item);
  187. $result['name'] = $index;
  188. $result['title'] = isset($titleArr[$index]) ? $titleArr[$index] : '其它';
  189. $result['url'] = cdnurl($urlArr[0], true);
  190. $result['password'] = isset($urlArr[1]) ? $urlArr[1] : '';
  191. $list[] = $result;
  192. } elseif (is_array($item) && isset($item['name']) && isset($item['url']) && $item['url']) {
  193. $item['url'] = cdnurl($item['url'], true);
  194. $result = $item;
  195. $result['title'] = isset($titleArr[$item['name']]) ? $titleArr[$item['name']] : '其它';
  196. $list[] = $result;
  197. }
  198. }
  199. return $list;
  200. }
  201. public function getTaglistAttr($value, &$data)
  202. {
  203. if (isset($data['taglist'])) {
  204. return $data['taglist'];
  205. }
  206. $tags = array_filter(explode(",", $data['tags']));
  207. $tagList = [];
  208. if (stripos(self::$config['rewrite']['tag/index'], ":id") !== false) {
  209. $tagList = Tag::where('name', 'in', $tags)->column('name,id');
  210. }
  211. $time = $data['createtime'] ?? time();
  212. $list = [];
  213. foreach ($tags as $k => $v) {
  214. $vars = [':name' => $v, ':diyname' => $v, ':id' => isset($tagList[$v]) ? $tagList[$v] : '0', ':year' => date("Y", $time), ':month' => date("m", $time), ':day' => date("d", $time)];
  215. $list[] = ['name' => $v, 'url' => addon_url('cms/tag/index', $vars)];
  216. }
  217. $data['taglist'] = $list;
  218. return $list;
  219. }
  220. public function getUrlAttr($value, $data)
  221. {
  222. return $this->buildUrl($value, $data);
  223. }
  224. public function getFullurlAttr($value, $data)
  225. {
  226. return $this->buildUrl($value, $data, true);
  227. }
  228. private function buildUrl($value, $data, $domain = false)
  229. {
  230. $diyname = isset($data['diyname']) && $data['diyname'] ? $data['diyname'] : $data['id'];
  231. $catename = isset($this->channel) && $this->channel ? $this->channel->diyname : 'all';
  232. $cateid = isset($this->channel) && $this->channel ? $this->channel->id : 0;
  233. $time = $data['publishtime'] ?? time();
  234. $vars = [
  235. ':id' => $data['id'],
  236. ':diyname' => $diyname,
  237. ':channel' => $data['channel_id'],
  238. ':catename' => $catename,
  239. ':cateid' => $cateid,
  240. ':year' => date("Y", $time),
  241. ':month' => date("m", $time),
  242. ':day' => date("d", $time),
  243. ];
  244. $suffix = static::$config['moduleurlsuffix']['archives'] ?? static::$config['urlsuffix'];
  245. return addon_url('cms/archives/index', $vars, $suffix, $domain);
  246. }
  247. public function getLikeratioAttr($value, $data)
  248. {
  249. return ($data['dislikes'] > 0 ? min(1, $data['likes'] / ($data['dislikes'] + $data['likes'])) : ($data['likes'] ? 1 : 0.5)) * 100;
  250. }
  251. public function getStyleTextAttr($value, $data)
  252. {
  253. $color = $this->getAttr("style_color");
  254. $color = $color ? $color : "inherit";
  255. $color = str_replace(['#', ' '], '', $color);
  256. $bold = $this->getAttr("style_bold") ? "bold" : "normal";
  257. $attr = ["font-weight:{$bold};"];
  258. if (stripos($color, ',') !== false) {
  259. list($first, $second) = explode(',', $color);
  260. $attr[] = "background-image: -webkit-linear-gradient(0deg, #{$first} 0%, #{$second} 100%);background-image: linear-gradient(90deg, #{$first} 0%, #{$second} 100%);-webkit-background-clip: text;-webkit-text-fill-color: transparent;";
  261. } else {
  262. $attr[] = "color:#{$color};";
  263. }
  264. return implode('', $attr);
  265. }
  266. public function getStyleBoldAttr($value, $data)
  267. {
  268. return in_array('b', explode('|', $data['style']));
  269. }
  270. public function getStyleColorAttr($value, $data)
  271. {
  272. $styleArr = explode('|', $data['style']);
  273. foreach ($styleArr as $index => $item) {
  274. if (preg_match('/\,|#/', $item)) {
  275. return $item;
  276. }
  277. }
  278. return '';
  279. }
  280. /**
  281. * 获取内容页分页HTML
  282. */
  283. public function getPagerHTML($page, $total, $simple = false)
  284. {
  285. if ($total <= 1) {
  286. return '';
  287. }
  288. $result = \addons\cms\library\Bootstrap::make([], 1, $page, $total, $simple, ['path' => $this->url, 'simple' => $simple]);
  289. return "<div class='pager'>" . $result->render() . "</div>";
  290. }
  291. /**
  292. * 获取文档列表
  293. * @param $tag
  294. * @return array|false|\PDOStatement|string|\think\Collection
  295. */
  296. public static function getArchivesList($tag)
  297. {
  298. $config = get_addon_config('cms');
  299. $type = empty($tag['type']) ? '' : $tag['type'];
  300. $model = !isset($tag['model']) ? '' : $tag['model'];
  301. $channel = !isset($tag['channel']) ? '' : $tag['channel'];
  302. $special = !isset($tag['special']) ? '' : $tag['special'];
  303. $tags = empty($tag['tags']) ? '' : $tag['tags'];
  304. $condition = empty($tag['condition']) ? '' : $tag['condition'];
  305. $field = empty($tag['field']) ? '*' : $tag['field'];
  306. $flag = empty($tag['flag']) ? '' : $tag['flag'];
  307. $row = empty($tag['row']) ? 10 : (int)$tag['row'];
  308. $orderby = empty($tag['orderby']) ? 'createtime' : $tag['orderby'];
  309. $orderway = empty($tag['orderway']) ? 'desc' : strtolower($tag['orderway']);
  310. $limit = empty($tag['limit']) ? $row : $tag['limit'];
  311. $cache = !isset($tag['cache']) ? $config['cachelifetime'] === 'true' ? true : (int)$config['cachelifetime'] : (int)$tag['cache'];
  312. $imgwidth = empty($tag['imgwidth']) ? '' : $tag['imgwidth'];
  313. $imgheight = empty($tag['imgheight']) ? '' : $tag['imgheight'];
  314. $addon = empty($tag['addon']) ? false : $tag['addon'];
  315. $orderway = in_array($orderway, ['asc', 'desc']) ? $orderway : 'desc';
  316. $paginate = !isset($tag['paginate']) ? false : $tag['paginate'];
  317. $page = !isset($tag['page']) ? 1 : (int)$tag['page'];
  318. $with = !isset($tag['with']) ? 'channel' : $tag['with'];
  319. $cache = !$cache ? false : $cache;
  320. $where = ['status' => 'normal'];
  321. $where['deletetime'] = ['exp', Db::raw('IS NULL')]; //by erastudio
  322. if ($model !== '') {
  323. $where['model_id'] = ['in', $model];
  324. }
  325. self::$tagCount++;
  326. $archivesModel = self::with($with)->alias('a');
  327. if ($channel !== '') {
  328. if ($type === 'son') {
  329. $subQuery = Channel::where('parent_id', 'in', $channel)->field('id')->buildSql();
  330. //子级
  331. $where['channel_id'] = ['exp', Db::raw(' IN ' . '(' . $subQuery . ')')];
  332. } elseif ($type === 'sons') {
  333. //所有子级
  334. $where['channel_id'] = ['in', Channel::getChannelChildrenIds($channel)];
  335. } else {
  336. $where['channel_id'] = ['in', $channel];
  337. }
  338. }
  339. //如果有设置标志,则拆分标志信息并构造condition条件
  340. if ($flag !== '') {
  341. if (stripos($flag, '&') !== false) {
  342. $arr = [];
  343. foreach (explode('&', $flag) as $k => $v) {
  344. $arr[] = "FIND_IN_SET('{$v}', flag)";
  345. }
  346. if ($arr) {
  347. $condition .= "(" . implode(' AND ', $arr) . ")";
  348. }
  349. } else {
  350. $condition .= ($condition ? ' AND ' : '');
  351. $arr = [];
  352. foreach (explode(',', str_replace('|', ',', $flag)) as $k => $v) {
  353. $arr[] = "FIND_IN_SET('{$v}', flag)";
  354. }
  355. if ($arr) {
  356. $condition .= "(" . implode(' OR ', $arr) . ")";
  357. }
  358. }
  359. }
  360. if ($special) {
  361. $specialModel = Special::get($special, [], true);
  362. if ($specialModel && $specialModel['tag_ids']) {
  363. $archivesModel->where("a.id", "in", function ($query) use ($specialModel) {
  364. return $query->name("cms_taggable")->where("tag_id", "in", $specialModel['tag_ids'])->field("archives_id");
  365. });
  366. $cache = false;
  367. }
  368. }
  369. $order = $orderby == 'rand' ? Db::raw('rand()') : (preg_match("/\,|\s/", $orderby) ? $orderby : "{$orderby} {$orderway}");
  370. $order = $orderby == 'weigh' ? $order . ',id DESC' : $order;
  371. // 如果有筛选标签,则采用子查询
  372. if ($tags) {
  373. $tagIds = Tag::where('name', 'in', explode(',', $tags))->cache($cache)->limit($limit)->column("id");
  374. $archivesModel->where("a.id", "in", function ($query) use ($tagIds) {
  375. return $query->name("cms_taggable")->where("tag_id", "in", $tagIds)->field("archives_id");
  376. });
  377. $cache = false;
  378. }
  379. $modelInfo = null;
  380. $prefix = config('database.prefix');
  381. $archivesModel
  382. ->where($where)
  383. ->where($condition)
  384. ->field($field, false, $prefix . "cms_archives", "a")
  385. ->orderRaw($order);
  386. if ($addon && (is_numeric($model) || $channel)) {
  387. if ($channel) {
  388. //如果channel设置了多个值则只取第一个作为判断
  389. $channelArr = explode(',', $channel);
  390. $channelinfo = Channel::get($channelArr[0], [], true);
  391. $model = $channelinfo ? $channelinfo['model_id'] : $model;
  392. }
  393. // 查询相关联的模型信息
  394. $modelInfo = Modelx::get($model, [], true);
  395. if ($modelInfo) {
  396. $archivesModel->join($modelInfo['table'] . ' n', 'a.id=n.id', 'LEFT');
  397. if ($addon == 'true') {
  398. $archivesModel->field('id,content', true, $prefix . $modelInfo['table'], 'n');
  399. } else {
  400. $archivesModel->field($addon, false, $prefix . $modelInfo['table'], 'n');
  401. }
  402. }
  403. }
  404. if ($paginate) {
  405. $paginateArr = explode(',', $paginate);
  406. $listRows = is_numeric($paginate) ? $paginate : (is_numeric($paginateArr[0]) ? $paginateArr[0] : $row);
  407. $config = [];
  408. $config['var_page'] = isset($paginateArr[2]) ? $paginateArr[2] : (isset($tag['page']) ? 'page' : 'apage' . self::$tagCount);
  409. $config['path'] = isset($paginateArr[3]) ? $paginateArr[3] : '';
  410. $config['fragment'] = isset($paginateArr[4]) ? $paginateArr[4] : '';
  411. $config['query'] = request()->get();
  412. $config['page'] = $page;
  413. $list = $archivesModel->paginate($listRows, (isset($paginateArr[1]) ? $paginateArr[1] : false), $config);
  414. } else {
  415. $list = $archivesModel->limit($limit)->cache($cache)->select();
  416. }
  417. if ($modelInfo) {
  418. $fieldsContentList = [];
  419. if ($modelInfo->fields) {
  420. $fieldsContentList = Fields::getFieldsContentList('model', $modelInfo->id);
  421. }
  422. foreach ($list as $index => &$item) {
  423. Service::appendTextAttr($fieldsContentList, $item);
  424. }
  425. }
  426. self::render($list, $imgwidth, $imgheight);
  427. return $list;
  428. }
  429. /**
  430. * 追加_text属性值
  431. * @param $fieldsContentList
  432. * @param $row
  433. */
  434. public static function appendTextAttr(&$fieldsContentList, &$row)
  435. {
  436. //附加列表字段
  437. array_walk($fieldsContentList, function ($content, $field) use (&$row) {
  438. if (isset($row[$field])) {
  439. if (isset($content[$row[$field]])) {
  440. $list = [$row[$field] => $content[$row[$field]]];
  441. } else {
  442. $keys = $values = explode(',', $row[$field]);
  443. foreach ($values as $index => &$item) {
  444. $item = isset($content[$item]) ? $content[$item] : $item;
  445. }
  446. $list = array_combine($keys, $values);
  447. }
  448. } else {
  449. $list = [];
  450. }
  451. $list = array_filter($list);
  452. $row[$field . '_text'] = implode(',', $list);
  453. $row[$field . '_list'] = $list;
  454. });
  455. }
  456. /**
  457. * 渲染数据
  458. * @param array $list
  459. * @param int $imgwidth
  460. * @param int $imgheight
  461. * @return array
  462. */
  463. public static function render(&$list, $imgwidth, $imgheight)
  464. {
  465. $width = $imgwidth ? 'width="' . $imgwidth . '"' : '';
  466. $height = $imgheight ? 'height="' . $imgheight . '"' : '';
  467. foreach ($list as $k => &$v) {
  468. $v['textlink'] = '<a href="' . $v['url'] . '">' . $v['title'] . '</a>';
  469. $v['channellink'] = '<a href="' . $v['channel']['url'] . '">' . $v['channel']['name'] . '</a>';
  470. $v['imglink'] = '<a href="' . $v['url'] . '"><img src="' . $v['image'] . '" border="" ' . $width . ' ' . $height . ' /></a>';
  471. $v['img'] = '<img src="' . $v['image'] . '" border="" ' . $width . ' ' . $height . ' />';
  472. }
  473. return $list;
  474. }
  475. /**
  476. * 获取分页列表
  477. * @param array $list
  478. * @param array $tag
  479. * @return array
  480. */
  481. public static function getPageList($list, $tag)
  482. {
  483. $imgwidth = empty($tag['imgwidth']) ? '' : $tag['imgwidth'];
  484. $imgheight = empty($tag['imgheight']) ? '' : $tag['imgheight'];
  485. return self::render($list, $imgwidth, $imgheight);
  486. }
  487. /**
  488. * 获取分页过滤
  489. * @param array $list
  490. * @param array $tag
  491. * @return array
  492. */
  493. public static function getPageFilter($list, $tag)
  494. {
  495. $exclude = empty($tag['exclude']) ? '' : $tag['exclude'];
  496. return $list;
  497. }
  498. /**
  499. * 获取分页排序
  500. * @param array $list
  501. * @param array $tag
  502. * @return array
  503. */
  504. public static function getPageOrder($list, $tag)
  505. {
  506. $exclude = empty($tag['exclude']) ? '' : $tag['exclude'];
  507. return $list;
  508. }
  509. /**
  510. * 获取上一页下一页
  511. * @param string $type
  512. * @param string $archives
  513. * @param string $channel
  514. * @param array $tag
  515. * @return array
  516. */
  517. public static function getPrevNext($tag = [])
  518. {
  519. $type = isset($tag['type']) ? $tag['type'] : 'prev';
  520. $channel = isset($tag['channel']) ? $tag['channel'] : '';
  521. $archives = isset($tag['archives']) ? $tag['archives'] : '';
  522. $condition = isset($tag['condition']) ? $tag['condition'] : '';
  523. $model = self::where('id', $type === 'prev' ? '<' : '>', $archives)->where('status', 'normal');
  524. if ($channel !== '') {
  525. $model->where('channel_id', 'in', $channel);
  526. }
  527. if (isset($condition)) {
  528. $model->where($condition);
  529. }
  530. $model->order($type === 'prev' ? 'id desc' : 'id asc');
  531. $row = $model->find();
  532. return $row;
  533. }
  534. /**
  535. * 获取SQL查询结果
  536. */
  537. public static function getQueryList($tag)
  538. {
  539. $config = get_addon_config('cms');
  540. $sql = isset($tag['sql']) ? $tag['sql'] : '';
  541. $bind = isset($tag['bind']) ? explode(',', $tag['bind']) : [];
  542. $cache = !isset($tag['cache']) ? $config['cachelifetime'] === 'true' ? true : (int)$config['cachelifetime'] : (int)$tag['cache'];
  543. $cache = !$cache ? false : $cache;
  544. $name = md5("sql-" . $tag['sql']);
  545. $list = Cache::get($name);
  546. if (!$list) {
  547. $list = Db::query($sql, $bind);
  548. Cache::set($name, $list, $cache);
  549. }
  550. return $list;
  551. }
  552. /**
  553. * 关联模型
  554. */
  555. public function user()
  556. {
  557. return $this->belongsTo("\app\common\model\User", 'user_id', 'id', [], 'LEFT')->setEagerlyType(1);
  558. }
  559. /**
  560. * 关联模型
  561. */
  562. public function model()
  563. {
  564. return $this->belongsTo("Modelx", 'model_id')->setEagerlyType(1);
  565. }
  566. /**
  567. * 关联栏目模型
  568. */
  569. public function channel()
  570. {
  571. return $this->belongsTo("Channel", 'channel_id', 'id', [], 'LEFT')->setEagerlyType(1);
  572. }
  573. }