// +---------------------------------------------------------------------- declare (strict_types = 1); namespace addon\blog\model; use think\facade\Cache; use ywxapp\model\BaseModel; use ywxapp\model\MemberUser; class BlogArticle extends BaseModel { // 设置数据表名 protected $name = 'blog_article'; // 设置主键 protected $pk = 'id'; // 自动写入时间戳 protected $autoWriteTimestamp = 'int'; protected $createTime = 'create_at'; protected $updateTime = 'update_at'; // 定义允许写入的字段 protected $allowField = [ 'title', 'content', 'summary', 'cover_image', 'uid', 'cid', 'status', 'audit_status', 'is_top', 'view_count', 'comment_count', 'like_count', 'favorite_count', 'share_count', ]; // 设置字段类型 protected $type = [ 'id' => 'int', 'uid' => 'int', 'cid' => 'int', 'status' => 'int', 'audit_status' => 'int', 'is_top' => 'int', 'view_count' => 'int', 'comment_count' => 'int', 'like_count' => 'int', 'favorite_count' => 'int', 'share_count' => 'int', 'create_at' => 'int', 'update_at' => 'int', ]; // 内容修改器(过滤危险标签) public function setContentAttr($value) { return htmlspecialchars_decode($value); } // 摘要写入修改器:提交时若留空,自动从正文截取并持久化 public function setSummaryAttr($value, $data) { $value = trim((string) $value); if ($value !== '') { return $value; } $content = $data['content'] ?? ''; $content = is_string($content) ? strip_tags($content) : ''; $content = trim($content); return $content !== '' ? mb_substr($content, 0, 150) : ''; } // 获取文章摘要(自动生成,兼容遗留未存摘要的文章) public function getSummaryAttr($value, $data) { if ($value !== '' && $value !== null) { return $value; } $content = is_string($data['content'] ?? '') ? (string) $data['content'] : ''; $content = html_entity_decode(strip_tags($content), ENT_QUOTES | ENT_HTML5, 'UTF-8'); $content = trim(preg_replace('/\s+/', ' ', $content)); // 正文为 JSON 或无可读文本时返回空,由模板显示「暂无描述」,避免首页展示 JSON 片段 if ($content === '' || $this->isJsonContent($content)) { return ''; } return mb_substr($content, 0, 150); } // 判断文本是否像 JSON(自动摘要时跳过,避免卡片展示 JSON 片段) protected function isJsonContent($text) { $text = ltrim($text); if ($text === '' || ($text[0] !== '{' && $text[0] !== '[')) { return false; } json_decode($text); return json_last_error() === JSON_ERROR_NONE; } // 格式化创建时间(兼容 int / 数字字符串 / 日期字符串 / DateTime) public function getCreateTextAttr($value, $data) { $t = $data['create_at'] ?? $value; if ($t instanceof \DateTime) { return $t->format('Y-m-d H:i'); } if (is_numeric($t)) { return date('Y-m-d H:i', (int) $t); } $ts = strtotime((string) $t); return $ts !== false ? date('Y-m-d H:i', $ts) : (string) $t; } // 定义关联 - 作者(博客作者即主系统会员,统一使用 wxapp_user 表,主键 uid) public function author() { return $this->belongsTo(MemberUser::class, 'uid', 'uid'); } // 兼容别名:部分视图/调用使用 user 关系 public function user() { return $this->belongsTo(MemberUser::class, 'uid', 'uid'); } // 定义关联 - 分类 public function category() { return $this->belongsTo(BlogCategory::class, 'cid'); } // 定义关联 - 标签(关联表 wxapp_blog_article_tag,列 aid/tid) public function tags() { return $this->belongsToMany(BlogTag::class, 'blog_article_tag', 'tid', 'aid'); } // 定义关联 - 评论 public function comments() { return $this->hasMany(BlogComment::class, 'aid'); } // 定义关联 - 点赞 public function likes() { return $this->hasMany(BlogLike::class, 'aid'); } // 定义关联 - 收藏 public function favorites() { return $this->hasMany(BlogFavorite::class, 'aid'); } // 增加浏览次数 public function incrementViewCount() { $this->view_count++; $this->save(); // 清除相关缓存 Cache::delete('article_' . $this->id); } // 检查文章是否置顶 public function isTop() { return $this->is_top === 1; } // 检查文章是否发布 public function isPublished() { return $this->status === 1; } // 获取相关文章(同分类) public function getRelatedArticles($limit = 5) { return self::where('cid', $this->cid) ->where('id', '<>', $this->id) ->where('status', 1) ->order('view_count', 'desc') ->limit($limit) ->select(); } // 获取上一篇/下一篇文章 public function getPrevNextArticles() { $prev = self::where('id', '<', $this->id) ->where('status', 1) ->order('id', 'desc') ->find(); $next = self::where('id', '>', $this->id) ->where('status', 1) ->order('id', 'asc') ->find(); return [ 'prev' => $prev, 'next' => $next, ]; } }