如何仅更新模型单个属性?基于Spatie Laravel Data的实现
基于spatie/laravel-data实现用户同意设置的更新逻辑
1. 定义请求Data类
首先创建继承自Spatie\LaravelData\Data的请求类,声明三个可空布尔类型的属性:
use Spatie\LaravelData\Data; class UserConsentRequest extends Data { public function __construct( public ?bool $newsLetters, public ?bool $sms, public ?bool $billEmail, ) {} }
2. 添加单属性更新验证
为确保请求中最多只有一个非空的同意设置,提供两种实现方式:
方式一:在Data类内封装验证与属性提取
给Data类添加两个方法,分别处理验证逻辑和非空属性提取:
use Spatie\LaravelData\Data; use Illuminate\Validation\ValidationException; class UserConsentRequest extends Data { public function __construct( public ?bool $newsLetters, public ?bool $sms, public ?bool $billEmail, ) {} // 验证是否仅提交了一项非空设置 public function validateSingleConsent(): void { $nonNullCount = collect([$this->newsLetters, $this->sms, $this->billEmail]) ->filter(fn($value) => !is_null($value)) ->count(); if ($nonNullCount > 1) { throw ValidationException::withMessages([ 'consent' => '只能同时更新一项用户同意设置' ]); } } // 提取所有非空的属性键值对 public function getNonNullAttributes(): array { return collect([ 'newsLetters' => $this->newsLetters, 'sms' => $this->sms, 'billEmail' => $this->billEmail, ])->filter(fn($value) => !is_null($value))->toArray(); } }
方式二:利用laravel-data的验证规则
直接在Data类的rules()方法中添加自定义验证规则,让请求自动完成校验:
use Spatie\LaravelData\Data; class UserConsentRequest extends Data { public function __construct( public ?bool $newsLetters, public ?bool $sms, public ?bool $billEmail, ) {} public static function rules(): array { return [ 'newsLetters' => ['nullable', 'boolean'], 'sms' => ['nullable', 'boolean'], 'billEmail' => ['nullable', 'boolean'], // 自定义规则限制最多一个非空属性 '*' => [ function ($attribute, $value, $fail) { $nonNullCount = collect(request()->only(['newsLetters', 'sms', 'billEmail'])) ->filter(fn($v) => !is_null($v)) ->count(); if ($nonNullCount > 1) { $fail('只能同时提交一项用户同意设置的修改'); } }, ], ]; } }
3. 在控制器中处理更新逻辑
在控制器中调用验证逻辑(方式一需要手动调用),提取非空属性并执行更新:
use App\Data\UserConsentRequest; use Illuminate\Support\Facades\Auth; class UserConsentController extends Controller { public function update(UserConsentRequest $request) { // 方式一需要手动触发验证 // $request->validateSingleConsent(); // 获取非空属性(方式一) $attributes = $request->getNonNullAttributes(); // 方式二可直接过滤数组: // $attributes = collect($request->toArray())->filter(fn($v) => !is_null($v))->toArray(); // 仅当有非空属性时执行更新 if (!empty($attributes)) { Auth::user()->update($attributes); } return response()->json(['message' => '用户同意设置更新成功']); } }
最终实现效果:
- 自动校验请求是否存在多个非空同意设置,不符合则抛出异常
- 仅更新请求中提供的非空属性,忽略空值属性
内容的提问来源于stack exchange,提问作者Rokas
相关产品推荐
相关产品推荐

