
本文详解如何在 Laravel 8 中正确关联 courses 与 admissions 表,通过 Eloquent 关系与 Blade 条件渲染,为同一用户已购的多个课程分别显示“已录取”或“立即报名”状态,避免仅返回单条记录导致的状态误判。
本文详解如何在 laravel 8 中正确关联 `courses` 与 `admissions` 表,通过 eloquent 关系与 blade 条件渲染,为同一用户已购的多个课程分别显示“已录取”或“立即报名”状态,避免仅返回单条记录导致的状态误判。
在 Laravel 开发中,当需根据用户与课程的关联关系(如报名、购买)动态展示 UI 状态时,常见误区是仅查询单条 Admission 记录(如使用 first()),这会导致即使用户已报名多门课程,也仅能匹配第一条,其余课程始终显示为未购买状态。
✅ 正确做法:批量获取并建立高效映射
首先,在控制器中应获取当前用户全部的 Admission 记录,并利用 Eloquent 的集合方法提升判断效率:
// Controller (e.g., CourseController.php)
use Illuminate\Support\Facades\Auth;
$courses = Course::latest('id')->get();
$admissions = Admission::where('user_id', Auth::id())->get();
return view('Backend.Student.courses', compact('courses', 'admissions'));⚠️ 注意:确保 Admission 模型中 user_id 字段名与数据库实际一致(原文中问题代码写为 users_id,但答案中改为 user_id —— 请根据你的真实迁移文件字段名统一调整,推荐使用 Laravel 标准命名 user_id)。
? Blade 视图:精准匹配每门课程状态
在 Blade 模板中,不再依赖全局 $admission 变量,而是遍历 $courses,对每门课程检查其是否存在于该用户的 admissions 集合中,并进一步判断状态:
@foreach($courses as $course)
@php
$userAdmission = $admissions->firstWhere('course_id', $course->id);
@endphp
@if($userAdmission)
{{-- 已报名该课程 --}}
@if($userAdmission->status === 'active')
<li class="list-inline-item">
<a href="{{ route('access.course', $course->slug) }}" class="btn btn-warning btn-sm">
<h5 class="p-0 m-0 text-white">{{ __('Continue Course') }}</h5>
</a>
</li>
@else
<li class="list-inline-item">
<a href="javascript:void(0)" class="btn btn-info btn-sm">
<h5 class="p-0 m-0 text-white">{{ __('Admitted') }}</h5>
</a>
</li>
@endif
@else
{{-- 未报名该课程 --}}
<li class="list-inline-item">
<a href="{{ route('purchase.course', $course->slug) }}" class="btn btn-info btn-sm">
<h5 class="p-0 m-0 text-white">{{ __('Admission Now') }}</h5>
</a>
</li>
<li class="list-inline-item">
{{ __('Price') }}: ৳{{ number_format($course->price, 0, '.', ',') }} BDT
</li>
@endif
@endforeach✅ 优势说明:
- 使用 firstWhere() 替代 in_array() + pluck()->toArray(),语义更清晰、性能更优(避免重复数组转换);
- 每次循环只查找当前课程对应的报名记录,逻辑直白且可读性强;
- 支持同一用户报名多门课程,每门课程独立渲染状态。
? 进阶建议:优化数据库查询(N+1 问题预防)
若课程数量较多,上述方式仍存在 N+1 查询风险(虽当前无额外查询,但后续扩展易引入)。推荐在 Course 模型中定义关系,并使用 withExists() 或 withCount() 预加载状态标识:
// 在 Course 模型中添加
public function userAdmissions()
{
return $this->hasMany(Admission::class, 'course_id')
->where('user_id', Auth::id());
}
// 控制器中优化查询(Laravel 8+)
$courses = Course::latest('id')
->withCount(['userAdmissions as is_admitted' => fn ($q) => $q->where('status', 'active')])
->get();然后 Blade 中可直接使用 $course->is_admitted > 0 判断,进一步提升性能与可维护性。
✅ 总结
- ❌ 错误:Admission::where(...)->first() → 仅返回一条记录,无法支持多课程场景;
- ✅ 正确:Admission::where(...)->get() + firstWhere() 动态匹配 → 精准、可扩展、易维护;
- ? 关键点:状态判断必须按课程粒度进行,而非全局单例变量;
- ? 后续可结合 Eloquent 关系与预加载,兼顾功能与性能。
通过以上重构,你的课程列表将准确反映用户对每一门课程的实时报名状态,真正实现“买一门、显一门”的业务需求。


















