Laravel 8 基于新建模型字段创建多态关联模型的非控制器实现咨询
方案结论
完全可以通过监听User模型的创建事件将Email同步逻辑抽离出控制器,有效降低控制器代码冗余,同时实现业务逻辑的复用。以下是两种常见实现方案:
方式1:直接在User模型中注册created事件(轻量场景首选)
直接在User模型的boot方法中注册创建完成后的回调逻辑,不需要额外生成文件,适合逻辑简单的场景。
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Hash; class User extends Model { protected static function boot() { parent::boot(); // 监听用户创建完成事件,同步生成主邮箱记录 static::created(function ($user) { $email = new \App\Models\Email; $email->fill([ 'email' => $user->email, 'email_type' => 'primary', 'main' => 1, ]); $user->emails()->save($email); }); // 可扩展:把字段预处理逻辑也放到saving事件中,进一步精简控制器代码 static::saving(function ($user) { // 自动加密密码 if (!empty($user->password) && Hash::needsRehash($user->password)) { $user->password = Hash::make($user->password); } // 自动处理布尔字段默认值 $user->active = !empty($user->active) ? 1 : 0; $user->is_contact = !empty($user->is_contact) ? 1 : 0; }); } }
改造完成后控制器的store方法可以简化为:
$user = User::create($request->safe()->except('groups')); // 原有的字段赋值、saveEmail调用逻辑都可以删除
方式2:使用独立事件监听器(复杂业务场景首选)
如果后续Email同步逻辑可能扩展(比如要加操作日志、同步通知、多数据源关联等),推荐用Laravel原生的事件-监听器结构解耦:
- 先在
app/Providers/EventServiceProvider.php的$listen数组中注册关联关系:
protected $listen = [ 'App\Events\UserCreated' => [ 'App\Listeners\CreatePrimaryEmailForUser', ], ];
- 执行 artisan 命令自动生成对应的事件和监听器文件:
php artisan event:generate - 在生成的
CreatePrimaryEmailForUser监听器的handle方法中编写同步逻辑:
public function handle(UserCreated $event) { $email = new \App\Models\Email; $email->fill([ 'email' => $event->user->email, 'email_type' => 'primary', 'main' => 1, ]); $event->user->emails()->save($email); }
注意事项
- 如果业务中存在
User::insert()之类的批量写入创建用户的场景,模型事件不会触发,需要单独处理Email同步逻辑 - 如果存在特殊场景创建用户不需要同步生成Email,可以在事件回调中加判断条件跳过执行,也可以给模型加临时属性控制是否触发事件
内容的提问来源于stack exchange,提问作者Hernán Martinez Reumann
相关产品推荐
相关产品推荐

