CI4.7.2博客系统核心在于路由显式声明、控制器构造函数仅做依赖注入、模型层禁用自动时间戳。路由须手动绑定HTTP方法,控制器构造函数不可执行业务逻辑,PostModel需关闭$useTimestamps并严格定义$allowedFields,分页器必须通过service('pager')获取。

CI4.7.2 的博客系统核心功能,不是靠堆砌组件实现的,而是靠三件事:路由精准匹配、控制器依赖注入干净、模型层不越界。其他框架里容易失控的“自动加载”“魔法方法”在 CI4 里基本不存在——你写的每一行初始化逻辑,都明确落在 __construct() 或服务注册点上。
路由定义必须显式声明 HTTP 方法
CI4.7.2 默认禁用隐式路由($routes->setAutoRoute(false)),所以 Posts::index 不会自动响应 GET /posts。你得手动写清楚:
$routes->get('posts', 'Posts::index');
$routes->get('posts/(:segment)', 'Posts::show/$1');
$routes->post('posts', 'Posts::store');
常见错误是漏掉 post 或混用 match——比如用 $routes->match(['get', 'post'], 'posts', 'Posts::index'),结果 POST 请求进了 index() 而不是 store(),表单提交无声失败。
- 所有表单提交入口必须用
post/put/delete显式绑定 - URL 中带参数的路由(如
posts/123)优先级高于通配符(posts/(:any)),顺序错会导致show()永远收不到请求 - 如果启用 CSRF 保护(默认开启),
post路由对应的表单必须包含{csrf_token()},否则返回 403
控制器构造函数只做依赖注入,不做业务初始化
CI4.7.2 的控制器构造函数里,不要调用 $this->db->table()、不要执行查询、不要读配置项——这些该交给方法或服务类。构造函数唯一合法动作是接收并保存类型提示的依赖:
class Posts extends BaseController
{
protected $postModel;
protected $session;
public function __construct(PostModel $postModel, SessionInterface $session)
{
$this->postModel = $postModel;
$this->session = $session;
}
}
为什么?因为 CI4 的服务容器在实例化控制器时,会递归解析 PostModel 构造函数里的依赖(比如数据库连接)。如果你在 __construct() 里手动 new 一个模型或调用静态方法,就绕过了容器管理,导致事务、缓存、测试模拟全部失效。
-
BaseController的父构造函数不用手动调用 —— CI4.7.2 已移除对parent::__construct()的要求 - 若某依赖可选(比如日志服务),用
LoggerInterface $logger = null声明,避免容器找不到时报致命错误 - 别在构造函数里调用
service('cache'):它返回的是新实例,不是容器托管的单例,缓存策略会失效
PostModel 必须继承 CodeIgniter\Model,且禁用自动时间戳字段
博客文章通常需要自定义发布时间(published_at)和更新时间(updated_at),但 CI4.7.2 的 Model 默认启用 $useTimestamps = true,会强制覆盖 created_at/updated_at 字段。如果你的表结构没这两个字段,或者想用别的字段名,必须显式关闭:
class PostModel extends Model
{
protected $table = 'posts';
protected $useTimestamps = false; // 关键:禁用自动填充
protected $allowedFields = ['title', 'slug', 'content', 'published_at', 'status'];
}
否则你会遇到:插入文章时数据库报错 Column 'created_at' cannot be null,或者 published_at 被悄悄替换成当前时间。
- 若真要保留自动时间戳,必须把字段名改成
created_at和updated_at,且类型为DATETIME或TIMESTAMP -
$allowedFields是硬性白名单,漏写slug就算表单传了也进不了数据库 —— 这是安全机制,不是 bug - 软删除(
$useSoftDeletes = true)慎用:博客草稿/审核中状态更适合用status字段控制,避免deleted_at IS NULL查询拖慢列表页
分页器不能直接 new,必须用 service() 获取
CI4.7.2 的分页器(Paginator)是单例服务,直接 new \CodeIgniter\Pager\Pager() 会导致样式丢失、链接生成错误、无法复用配置。正确做法是通过服务容器获取:
$pager = service('pager');
$data['posts'] = $this->postModel->paginate(10, 'default', $page);
$data['pager'] = $pager->makeLinks($page, 10, $this->postModel->pager->getPageCount());
注意两个关键点:$this->postModel->paginate() 内部已调用 service('pager') 并设置好上下文;而 $pager->makeLinks() 必须传入当前页码和总页数,否则生成的链接永远是第一页。
- 模板中渲染分页必须用
$pager->links(),不是$pager->makeLinks()—— 后者只返回 HTML 字符串,前者才支持主题切换 - 如果改过 URL 路由规则(比如把
/posts/page/2改成/posts?p=2),需重写Pager的getSegment()方法,否则makeLinks()仍按默认规则拼接 - 分页器不感知模型查询条件,
paginate()之后再加where()无效 —— 条件必须在paginate()前链式调用
CI4.7.2 的“轻量”不是功能少,而是每个环节都要求你明确表态:这个路由谁处理、这个依赖从哪来、这个字段谁负责填充。一旦你习惯在 Services.php 里注册服务、在构造函数里声明依赖、在模型里严格约束字段,博客系统的可维护性就会自然浮现——而不是靠后期补中间件或打补丁硬扛。


















