如何检查用户additionalInfo模型的所有属性是否已填写?
我有一个用户的additionalInfo模型,用户填写完附加信息可获得奖励,因此需要检查该模型的所有属性是否已填写。我现在有两个疑问:
- 是否需要逐个检查每个属性,比如依次检查
$clientAdditionalInfo['address']、$clientAdditionalInfo['city']、$clientAdditionalInfo['province']等? - 或者采用如下遍历模型属性的方式是否可行?
public function isCompleted() { $user = auth()->user(); $clientAdditionalInfo = $user->client->additionalClientInfo->where('client_id', $user->client->id)->get()->first(); if($clientAdditionalInfo){ $attributes = $clientAdditionalInfo->getAttributes(); foreach($attributes as $attribute) { // 此处是否可检查每个属性是否已填写? } } }
我原本想遍历属性,逐个检查是否isset,全部设置就判定信息已填写并发放奖励,但不知道怎么确认所有属性都已设置。而且遍历的时候发现最后多了一个null值(在updated_at之后),但数据库里这条数据的所有值都已填写,只有一行数据。循环中打印$key和$attribute的结果如下:
^ "id" ^ 1 ^ "address" ^ "Calle test 123" ^ "city" ^ "Barcelona" ^ "province" ^ "Barcelona" ^ "postal_code" ^ "08010" ^ "web" ^ "https://www.test.com" ^ "phone" ^ "123456789" ^ "activity" ^ "Social" ^ "number_of_employees" ^ 150 ^ "interest" ^ "Test" ^ "client_id" ^ 8 ^ "created_at" ^ "2023-02-08 10:48:56" ^ "updated_at" ^ "2023-02-08 11:53:43" ^ null
这个null的来源我搞不清楚,不符合预期。后来我意识到自己的检查方式有误,应该通过$request->all()来检查,这样可以排除created_at和updated_at,检查更精准。
方案1:指定必填字段列表检查
如果模型里只有部分字段是用户需要填写的(比如排除id、client_id、created_at、updated_at这些系统自动生成的字段),最稳妥的方式是定义一个必填字段数组,逐个检查这些字段是否有值:
public function isCompleted() { $user = auth()->user(); $clientAdditionalInfo = $user->client->additionalClientInfo->where('client_id', $user->client->id)->first(); if (!$clientAdditionalInfo) { return false; } // 定义需要用户填写的必填字段 $requiredFields = ['address', 'city', 'province', 'postal_code', 'web', 'phone', 'activity', 'number_of_employees', 'interest']; foreach ($requiredFields as $field) { // 检查字段是否为空(注意区分空字符串、null和0这类合法值) if (empty($clientAdditionalInfo->{$field}) && !is_numeric($clientAdditionalInfo->{$field})) { return false; } } return true; }
这种方式的好处是精准可控,不会被系统字段或者意外的null干扰,而且能根据业务灵活调整必填字段。
方案2:过滤模型属性后检查
如果不想手动维护必填字段列表,可以过滤掉模型中的系统字段,再检查剩余属性是否都有值:
public function isCompleted() { $user = auth()->user(); $clientAdditionalInfo = $user->client->additionalClientInfo->where('client_id', $user->client->id)->first(); if (!$clientAdditionalInfo) { return false; } // 获取模型属性并过滤系统字段 $attributes = $clientAdditionalInfo->getAttributes(); $excludeFields = ['id', 'client_id', 'created_at', 'updated_at']; $userFields = array_diff_key($attributes, array_flip($excludeFields)); foreach ($userFields as $value) { if (empty($value) && !is_numeric($value)) { return false; } } return true; }
关于你遇到的额外null值:这大概率是getAttributes()返回的数组末尾多了一个无键值的元素,可能是模型查询或者序列化时的小问题。用array_diff_key过滤掉系统字段后,这个多余的null会被排除,不会影响检查。
方案3:通过请求数据检查(你提到的思路)
如果是在用户提交表单的请求中做检查,可以直接用$request的验证规则,Laravel自带的验证器能帮你快速判断字段是否齐全:
// 在控制器的提交方法中 public function submitAdditionalInfo(Request $request) { // 定义验证规则 $validated = $request->validate([ 'address' => 'required', 'city' => 'required', 'province' => 'required', 'postal_code' => 'required', 'web' => 'required|url', 'phone' => 'required', 'activity' => 'required', 'number_of_employees' => 'required|numeric', 'interest' => 'required', ]); // 验证通过,保存数据并发放奖励 $user = auth()->user(); $user->client->additionalClientInfo()->updateOrCreate( ['client_id' => $user->client->id], $validated ); // 发放奖励逻辑 // ... return redirect()->back()->with('success', '信息填写完成,奖励已发放'); }
这种方式在用户提交时就完成了检查,避免后续再去数据库查询验证,逻辑更顺畅,也符合Laravel的最佳实践。
内容的提问来源于stack exchange,提问作者Ignacio

