
本文详解如何在 laravel 8 中通过关联查询与集合操作,为每个课程动态显示「已报名」「进行中」或「立即报名+价格」状态,解决单条 admission 记录导致多课程状态误判的问题。
本文详解如何在 laravel 8 中通过关联查询与集合操作,为每个课程动态显示「已报名」「进行中」或「立即报名+价格」状态,解决单条 admission 记录导致多课程状态误判的问题。
在 Laravel 应用中,当用户可购买多个课程时,若仍使用 Admission::where('user_id', ...)->first() 获取单条记录,会导致 Blade 模板中仅能匹配一个课程 ID,其余已购课程被错误显示为未购买——这是典型的“一对多关系未正确建模”引发的逻辑缺陷。
核心修复思路:将 Admission 查询从单条改为集合,并在视图中按课程逐个校验其是否存在于该用户的全部报名记录中。
✅ 正确的数据准备(Controller 层)
use Illuminate\Support\Facades\Auth;
$courses = Course::latest('id')->get();
$admissions = Admission::where('user_id', Auth::id())->get(); // 注意字段名:user_id(非 users_id)
return view('Backend.Student.courses', compact('courses', 'admissions'));⚠️ 注意事项:
- 数据库字段应为 user_id(Laravel 标准命名),若实际为 users_id,请保持一致;
- 使用 Auth::id() 比 Auth::user()->id 更安全(避免未登录时抛出异常);
- latest('id') 等价于 orderBy('id', 'desc'),语义更清晰。
✅ Blade 模板中的精准状态判断
关键在于:对每个 $course,检查其 ID 是否出现在当前用户所有 admissions 的 course_id 列表中,并进一步区分激活状态:
@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✅ 进阶优化建议(提升性能与可维护性)
-
Eager Loading 避免 N+1 查询(若需在循环中访问关联模型):
$courses = Course::with(['admissions' => fn($q) => $q->where('user_id', Auth::id())]) ->latest('id') ->get();对应 Blade 中可直接使用 $course->admissions->first(),逻辑更内聚。
-
封装为 Accessor 或 Scope:
在 Course 模型中添加:public function getIsAdmittedByUserAttribute() { return $this->admissions()->where('user_id', Auth::id())->exists(); } public function getActiveAdmissionAttribute() { return $this->admissions()->where('user_id', Auth::id())->where('status', 'active')->first(); }Blade 中即可简化为:
@if($course->is_admitted_by_user) @if($course->active_admission) <!-- Continue Course --> @else <!-- Admitted --> @endif @else <!-- Admission Now + Price --> @endif 数据库索引优化:确保 admissions(user_id, course_id, status) 有联合索引,大幅提升查询效率。
通过以上重构,系统可准确响应用户与课程之间的多对多(或一对多)业务关系,状态展示不再受限于单条记录,真正实现「一课一态、精准呈现」。


















