如何用Ardent一行代码自动填充表单?autoHydrateEntityFromInput水合机制完全指南
如何用Ardent一行代码自动填充表单?autoHydrateEntityFromInput水合机制完全指南
Ardent 是专为 Laravel 5 的 Eloquent ORM 打造的自验证模型库,其中的 autoHydrateEntityFromInput 属性可以自动"水合"表单提交数据到模型属性上——你只需写一行 $user->save(),就能免去所有手动 Input::get() 的繁琐代码。本文将带你完整掌握这套水合机制的原理、开关与安全边界。
一、"水合"到底解决了什么痛点?
用过 Laravel 的朋友对下面这段代码应该不陌生:
$user = new User;
$user->name = Input::get('name');
$user->email = Input::get('email');
$user->password = Hash::make(Input::get('password'));
$user->save();
每写一个表单,就要重复一遍这种"搬运工"代码,稍有不慎就会漏掉某个字段。所谓水合(Hydration),就是像海绵吸水一样:Ardent 模型在验证时自动把 Input::all() 里的全部提交数据"吸"进模型属性里。
启用后,上面的代码可以简化为:
$user = new User;
$user->save(); // 自动填充 + 自动验证 + 自动保存
这就是标题里"一行代码自动填充表单"的由来 🎯
二、启用水合:模型里加两个开关
在继承 Ardent 基类的模型中(见 Ardent.php),把对应属性设为 true 即可:
use LaravelArdent\Ardent\Ardent;
class User extends Ardent {
public $autoHydrateEntityFromInput = true; // 新建记录时自动水合
public $forceEntityHydrationFromInput = true; // 更新记录时强制水合
}
两个开关的区别很关键,建议对照下表理解:
| 属性 | 触发条件 | 适用场景 |
|---|---|---|
autoHydrateEntityFromInput |
模型属性为空时才填充 | 新建记录(表单提交注册等) |
forceEntityHydrationFromInput |
只要调用验证就强制填充 | 更新已有记录(编辑表单回显覆盖) |
这两个属性定义在 Ardent.php 中,官方文档的对应章节见 README.md。
💡 为什么默认不水合已存在的记录?因为编辑表单通常只提交部分字段,如果盲目用
Input::all()覆盖,可能把模型里已有的字段值冲掉。新建时模型是空的,填充是安全的。
三、控制器里的极简写法
启用水合后,控制器只需要关心"成功或失败"两件事:
Route::post('register', function () {
$user = new User;
if ($user->save()) {
return Redirect::to('/')->with('message', '注册成功!');
} else {
return Redirect::to('/')->withErrors($user->errors());
}
});
失败时通过 errors() 方法即可拿到 Laravel 的 MessageBag 错误集合,直接回传给视图,无需额外处理。
四、水合机制的源码实现细节
自动填充并非"魔法",核心逻辑就在 validate() 方法里,一共只有两行(见 Ardent.php):
if ($this->forceEntityHydrationFromInput
|| (empty($this->attributes) && $this->autoHydrateEntityFromInput)) {
$this->fill(Input::all());
}
拆开看就是三个条件:
- 强制开关打开 → 无条件执行
fill(Input::all()); - 自动开关打开 且 当前属性为空 → 同样执行填充;
- 水合发生在验证之前,因此填充进来的数据会立刻参与规则校验。
而 save() 内部会先走 validateUniques() 再落库(见 Ardent.php),所以"填充 → 验证 → 保存"三步是串在一起的,这也是为什么一行 save() 就够了。
五、水合的安全边界:mass assignment 规则
需要特别注意的是,Ardent 水合内部调用的是 Eloquent 的 fill(),因此完全遵循 $fillable / $guarded 批量赋值规则。
- 只有
$fillable白名单里的字段才会真正写入; - 不在名单中的字段(例如
id、is_admin)即使用户在表单里恶意提交了,也会被 Eloquent 拦截。
所以在启用水合之前,请确认你的模型 $fillable 配置正确——这是防止批量赋值漏洞的最后一道防线 ⚠️
六、进阶组合拳:清理冗余字段 + 自动哈希密码
水合会把 Input::all() 的所有字段都填进来,包括 password_confirmation、_token、_method 这类不该入库的字段。Ardent 提供了两个配套开关,让整套流程"零手工":
class User extends Ardent {
public static $rules = array(
'name' => 'required|between:3,80|alpha_dash',
'email' => 'required|email|unique:users',
'password' => 'required|min:6|confirmed',
'password_confirmation' => 'required|min:6',
);
public $autoHydrateEntityFromInput = true; // 自动水合
public $autoPurgeRedundantAttributes = true; // 自动清除 *_confirmation、_token、_method
public $autoHashPasswordAttributes = true; // 自动用 Hash::make() 哈希密码
}
三者配合后的效果:水合填充全部表单数据 → 用 password_confirmation 完成 confirmed 校验 → 保存前自动清掉确认字段和 CSRF 令牌 → 明文密码自动替换为哈希值。相关实现分别在 Ardent.php 的 performSave() 中完成,文档说明见 README.md。
七、常见问题速查
Q1:水合后验证失败了,数据会丢吗?
不会。验证失败时 Ardent 会自动把本次输入 flash 到 session(见 Ardent.php),回退表单依然能回显用户填写的内容。
Q2:想在验证失败时抛异常而不是返回 false?
把 $throwOnValidation 设为 true,此时会抛出 InvalidModelException,可通过 getModel() 和 getErrors() 直接拿到失败模型与错误集合。
Q3:非 Laravel 环境(独立使用)能水合吗?
可以。先通过 Ardent::configureAsExternal() 初始化连接(配置方式见 README.md),此时验证器会改用独立的 validation.php 语言包,水合逻辑不受影响。
Q4:find() 查不到记录会怎样?
把 $throwOnFind 设为 true 后,Builder.php 会把 find / first 自动转成 findOrFail / firstOrFail,避免空指针。
八、相关文件路径速查
| 说明 | 路径 |
|---|---|
| 水合开关定义 | Ardent.php |
| 水合核心逻辑(validate 内) | Ardent.php |
| 保存前清理与密码哈希 | Ardent.php |
| 唯一规则更新辅助 | Ardent.php |
| 验证失败异常 | InvalidModelException.php |
| 查询构造器(throwOnFind) | Builder.php |
| 官方文档全文 | README.md |
| 依赖声明 | composer.json |
掌握 autoHydrateEntityFromInput 之后,你会发现 Laravel 表单处理从"搬数据"变成了"写规则":把验证规则声明在模型里,剩下交给一行 save(),干净利落 ✨