Laravel Nova中用foreach循环展示问题关联用户答案的最优方法
问题描述
我手里有questions、user、userAnswer三张数据表,user是中间表,一个问题对应多个用户,每个用户又对应多个答案。现在想在Laravel Nova的问题详情页展示每个用户的所有答案,只需要展示不用编辑,之前试了一段Stack组件的代码但没达到预期,求最优实现方法。
之前尝试的代码:
Stack::make('Answers', [ function ($userId) { $getAnswers = \App\Models\userAnswer::where('id', $userId)->get(); $combinedAnswers = ''; foreach ($getAnswers as $getAnswer) { $combinedAnswers .= $getAnswer->answer; } return $combinedAnswers; }, ]),
最优实现方案
首先得把模型的关联关系理清楚,这样才能高效拉取数据,避免重复查询:
- 在
Question模型里添加关联:
// app/Models/Question.php public function users() { // 根据实际表的外键调整,比如外键是question_id就加上->foreignKey('question_id') return $this->hasMany(User::class); }
- 在
User模型里添加和userAnswer的关联:
// app/Models/User.php public function userAnswers() { // 根据实际外键调整,比如外键是user_id return $this->hasMany(UserAnswer::class); }
下面给两种可行的实现方式:
方式一:计算字段(更推荐,代码简洁)
直接在Nova的Question资源里定义一个计算字段,把用户和对应的答案整理好展示:
// app/Nova/Question.php use Laravel\Nova\Fields\Text; Text::make('用户及答案', function () { // 预加载关联数据,避免N+1查询,提升页面性能 $this->load('users.userAnswers'); $displayContent = ''; foreach ($this->users as $user) { // 可以加上用户名称或其他标识 $displayContent .= "<strong>{$user->name}</strong>的答案:<br>"; foreach ($user->userAnswers as $answer) { $displayContent .= "- {$answer->answer}<br>"; } $displayContent .= "<br>"; } return $displayContent; })->asHtml(), // 允许渲染HTML,让展示格式更清晰
方式二:优化Stack组件实现
如果一定要用Stack,先修正原代码的错误(原代码用id匹配用户ID是错的,应该用user_id),再结合预加载优化:
// app/Nova/Question.php use Laravel\Nova\Fields\Stack; Stack::make('用户答案', function () { $this->load('users.userAnswers'); $contentRows = []; foreach ($this->users as $user) { // 把用户的所有答案拼接成列表 $answersList = implode('<br>- ', $user->userAnswers->pluck('answer')->toArray()); $contentRows[] = "<strong>{$user->name}</strong><br>- {$answersList}"; } return $contentRows; })->asHtml(),
注意事项
- 一定要预加载关联数据(
load('users.userAnswers')),不然每循环一个用户就查一次答案,会导致大量重复查询,拖慢页面加载速度 - 用
asHtml()可以让展示的内容分层更清楚,用户和答案区分开 - 原代码的核心错误:
userAnswer::where('id', $userId)应该改成userAnswer::where('user_id', $userId),因为id是答案表的主键,不是用户ID
内容的提问来源于stack exchange,提问作者jkstallard
相关产品推荐
相关产品推荐

