feat: update CourseService and CourseController to accept User parameter for improved scoping
This commit is contained in:
parent
2b458e26fa
commit
1c901e9103
@ -161,6 +161,21 @@ ## 4. Controller, Request, dan Service
|
|||||||
- **Controller** hanya mengatur alur request → response (validasi input dipanggil, service dipanggil, redirect/Inertia render dikembalikan). **Tidak boleh** ada query Eloquent kompleks atau business logic langsung di controller.
|
- **Controller** hanya mengatur alur request → response (validasi input dipanggil, service dipanggil, redirect/Inertia render dikembalikan). **Tidak boleh** ada query Eloquent kompleks atau business logic langsung di controller.
|
||||||
- **Selalu gunakan FormRequest**, sekecil apapun validasinya — jangan validasi inline di controller dengan `$request->validate()`.
|
- **Selalu gunakan FormRequest**, sekecil apapun validasinya — jangan validasi inline di controller dengan `$request->validate()`.
|
||||||
- Business logic (kalkulasi, orkestrasi antar model, side effect seperti notifikasi/log) **disimpan di Service**, bukan di controller atau model.
|
- Business logic (kalkulasi, orkestrasi antar model, side effect seperti notifikasi/log) **disimpan di Service**, bukan di controller atau model.
|
||||||
|
- **Kalau method Service butuh user yang sedang login untuk scoping/filtering** (mis. dosen cuma lihat kelasnya sendiri, mahasiswa cuma lihat jurusannya sendiri), terima sebagai parameter eksplisit `User $user` (non-nullable, tanpa default) di **posisi pertama** — jangan panggil `auth()->user()` langsung di dalam Service. Controller yang menyuplainya lewat `$request->user()`. Ini soal testability (Service tidak bergantung diam-diam ke global state) dan konsistensi lintas Service.
|
||||||
|
```php
|
||||||
|
// Bad
|
||||||
|
public function paginated(int $perPage = 25): LengthAwarePaginator
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good
|
||||||
|
public function paginated(User $user, int $perPage = 25): LengthAwarePaginator
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
- Otorisasi berbasis permission (Spatie) dicek di dua tempat:
|
- Otorisasi berbasis permission (Spatie) dicek di dua tempat:
|
||||||
- Route-level: middleware `permission:create-xxx` dipasang per-route/per-group.
|
- Route-level: middleware `permission:create-xxx` dipasang per-route/per-group.
|
||||||
- Object-level (mis. user hanya boleh mengubah record miliknya sendiri): di `authorize()` milik FormRequest, kombinasikan `$this->user()->can('permission-name')` dengan pengecekan kepemilikan record.
|
- Object-level (mis. user hanya boleh mengubah record miliknya sendiri): di `authorize()` milik FormRequest, kombinasikan `$this->user()->can('permission-name')` dengan pengecekan kepemilikan record.
|
||||||
|
|||||||
@ -23,6 +23,7 @@ public function index(PaginatedRequest $request): Response
|
|||||||
{
|
{
|
||||||
return Inertia::render('admin/master/courses/index', [
|
return Inertia::render('admin/master/courses/index', [
|
||||||
'courses' => $this->service->paginated(
|
'courses' => $this->service->paginated(
|
||||||
|
$request->user(),
|
||||||
...$request->validatedWithDefaults(),
|
...$request->validatedWithDefaults(),
|
||||||
departmentId: $request->validated('department_id'),
|
departmentId: $request->validated('department_id'),
|
||||||
semesterNumber: $request->validated('semester_number'),
|
semesterNumber: $request->validated('semester_number'),
|
||||||
|
|||||||
@ -2,52 +2,28 @@
|
|||||||
|
|
||||||
namespace App\Services\Admin\Master;
|
namespace App\Services\Admin\Master;
|
||||||
|
|
||||||
|
use App\Enums\UserRole;
|
||||||
use App\Models\Course;
|
use App\Models\Course;
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class CourseService
|
class CourseService
|
||||||
{
|
{
|
||||||
public function getAllForSelect(): Collection
|
public function paginated(User $user, int $perPage = 25, string $search = '', ?int $departmentId = null, ?int $semesterNumber = null): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return Course::query()
|
return Course::query()
|
||||||
->select(['courses.id', 'courses.code', 'courses.name', 'courses.department_id', 'courses.semester_number'])
|
|
||||||
->join('departments', 'departments.id', '=', 'courses.department_id')
|
|
||||||
->with('department:id,name')
|
|
||||||
->orderBy('departments.name')
|
|
||||||
->orderBy('courses.semester_number')
|
|
||||||
->orderBy('courses.name')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSemesterNumbers(): array
|
|
||||||
{
|
|
||||||
return Course::query()
|
|
||||||
->select('semester_number')
|
|
||||||
->whereNotNull('semester_number')
|
|
||||||
->distinct()
|
|
||||||
->orderBy('semester_number')
|
|
||||||
->pluck('semester_number')
|
|
||||||
->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', ?int $departmentId = null, ?int $semesterNumber = null): LengthAwarePaginator
|
|
||||||
{
|
|
||||||
$user = auth()->user();
|
|
||||||
|
|
||||||
return Course::query()
|
|
||||||
->select(['courses.id', 'courses.code', 'courses.name', 'courses.credits', 'courses.department_id', 'courses.semester_number'])
|
|
||||||
->join('departments', 'departments.id', '=', 'courses.department_id')
|
->join('departments', 'departments.id', '=', 'courses.department_id')
|
||||||
->with('department:id,name')
|
->with('department:id,name')
|
||||||
->when($search, fn ($q) => $q->where('courses.name', 'like', "%{$search}%")->orWhere('courses.code', 'like', "%{$search}%"))
|
->when($search, fn ($q) => $q->where('courses.name', 'like', "%{$search}%")->orWhere('courses.code', 'like', "%{$search}%"))
|
||||||
->when($departmentId, fn ($q) => $q->where('courses.department_id', $departmentId))
|
->when($departmentId, fn ($q) => $q->where('courses.department_id', $departmentId))
|
||||||
->when($semesterNumber, fn ($q) => $q->where('courses.semester_number', $semesterNumber))
|
->when($semesterNumber, fn ($q) => $q->where('courses.semester_number', $semesterNumber))
|
||||||
->when($user->hasRole('mahasiswa'), fn ($q) => $q->where('courses.department_id', $user->student?->department_id))
|
->when($user->hasRole(UserRole::Mahasiswa->value), fn ($q) => $q->where('courses.department_id', $user->student?->department_id))
|
||||||
->when($user->hasRole('dosen'), fn ($q) => $q->whereIn('courses.department_id', $user->lecturer?->departments()->pluck('departments.id') ?? []))
|
->when($user->hasRole(UserRole::Dosen->value), fn ($q) => $q->whereIn('courses.department_id', $user->lecturer?->departments()->pluck('departments.id') ?? []))
|
||||||
->orderBy('departments.name')
|
->orderBy('departments.name')
|
||||||
->orderBy('courses.semester_number')
|
->orderBy('courses.semester_number')
|
||||||
->orderBy('courses.name')
|
->orderBy('courses.name')
|
||||||
->paginate($perPage);
|
->paginate($perPage, ['courses.id', 'courses.code', 'courses.name', 'courses.credits', 'courses.department_id', 'courses.semester_number']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): Course
|
public function create(array $data): Course
|
||||||
@ -57,12 +33,13 @@ public function create(array $data): Course
|
|||||||
|
|
||||||
public function update(Course $course, array $data): Course
|
public function update(Course $course, array $data): Course
|
||||||
{
|
{
|
||||||
$course->code = $data['code'];
|
$course->update([
|
||||||
$course->name = $data['name'];
|
'code' => $data['code'],
|
||||||
$course->credits = $data['credits'];
|
'name' => $data['name'],
|
||||||
$course->department_id = $data['department_id'];
|
'credits' => $data['credits'],
|
||||||
$course->semester_number = $data['semester_number'] ?? null;
|
'department_id' => $data['department_id'],
|
||||||
$course->update();
|
'semester_number' => $data['semester_number'] ?? null,
|
||||||
|
]);
|
||||||
|
|
||||||
return $course;
|
return $course;
|
||||||
}
|
}
|
||||||
@ -71,4 +48,25 @@ public function delete(Course $course): bool
|
|||||||
{
|
{
|
||||||
return $course->delete();
|
return $course->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllForSelect(): Collection
|
||||||
|
{
|
||||||
|
return Course::query()
|
||||||
|
->join('departments', 'departments.id', '=', 'courses.department_id')
|
||||||
|
->with('department:id,name')
|
||||||
|
->orderBy('departments.name')
|
||||||
|
->orderBy('courses.semester_number')
|
||||||
|
->orderBy('courses.name')
|
||||||
|
->get(['courses.id', 'courses.code', 'courses.name', 'courses.department_id', 'courses.semester_number']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSemesterNumbers(): array
|
||||||
|
{
|
||||||
|
return Course::query()
|
||||||
|
->whereNotNull('semester_number')
|
||||||
|
->distinct()
|
||||||
|
->orderBy('semester_number')
|
||||||
|
->pluck('semester_number')
|
||||||
|
->all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user