170 lines
7.0 KiB
PHP
170 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\AcademicYear;
|
|
use App\Models\SchoolClass;
|
|
use App\Models\Student;
|
|
use App\Models\StudentAchievement;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\View\View;
|
|
|
|
class StudentAchievementController extends Controller
|
|
{
|
|
public function index(Request $request): View
|
|
{
|
|
$search = trim((string) $request->get('search'));
|
|
$academicYearId = $request->get('academic_year_id');
|
|
$classId = $request->get('class_id');
|
|
|
|
$achievements = StudentAchievement::query()
|
|
->with(['student.academicYear', 'student.department', 'student.classRoom'])
|
|
->when($search !== '', function ($query) use ($search) {
|
|
$query->where(function ($subQuery) use ($search) {
|
|
$subQuery->where('achievement_name', 'like', "%{$search}%")
|
|
->orWhere('category', 'like', "%{$search}%")
|
|
->orWhere('level', 'like', "%{$search}%")
|
|
->orWhereHas('student', function ($studentQuery) use ($search) {
|
|
$studentQuery->where('full_name', 'like', "%{$search}%")
|
|
->orWhere('student_number', 'like', "%{$search}%")
|
|
->orWhere('nisn', 'like', "%{$search}%");
|
|
});
|
|
});
|
|
})
|
|
->when($academicYearId, fn ($query) => $query->whereHas('student', fn ($studentQuery) => $studentQuery->where('academic_year_id', $academicYearId)))
|
|
->when($classId, fn ($query) => $query->whereHas('student', fn ($studentQuery) => $studentQuery->where('class_id', $classId)))
|
|
->latest('achievement_year')
|
|
->latest('achievement_date')
|
|
->latest('id')
|
|
->paginate(15)
|
|
->withQueryString();
|
|
|
|
return view('student-achievements.index', [
|
|
'achievements' => $achievements,
|
|
'search' => $search,
|
|
'filters' => [
|
|
'academic_year_id' => $academicYearId,
|
|
'class_id' => $classId,
|
|
],
|
|
'academicYears' => AcademicYear::orderBy('name')->pluck('name', 'id'),
|
|
'classes' => SchoolClass::orderBy('name')->pluck('name', 'id'),
|
|
'summary' => [
|
|
'total' => StudentAchievement::count(),
|
|
'filtered' => $achievements->total(),
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function create(Request $request): View
|
|
{
|
|
$achievement = new StudentAchievement();
|
|
|
|
if ($request->filled('student_id')) {
|
|
$achievement->student_id = (int) $request->integer('student_id');
|
|
}
|
|
|
|
return view('student-achievements.create', [
|
|
'achievement' => $achievement,
|
|
'students' => Student::orderBy('full_name')->get(['id', 'full_name', 'student_number', 'nisn']),
|
|
'levelOptions' => $this->levelOptions(),
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
$data = $this->validateAchievement($request);
|
|
|
|
if ($request->hasFile('certificate_file')) {
|
|
$data['certificate_file'] = $request->file('certificate_file')->store('student-achievements/certificates', 'public');
|
|
}
|
|
|
|
if ($request->hasFile('activity_photo')) {
|
|
$data['activity_photo'] = $request->file('activity_photo')->store('student-achievements/activity-photos', 'public');
|
|
}
|
|
|
|
StudentAchievement::create($data);
|
|
|
|
return redirect()->route('student-achievements.index')->with('success', 'Data siswa berprestasi berhasil ditambahkan.');
|
|
}
|
|
|
|
public function edit(StudentAchievement $studentAchievement): View
|
|
{
|
|
return view('student-achievements.edit', [
|
|
'achievement' => $studentAchievement,
|
|
'students' => Student::orderBy('full_name')->get(['id', 'full_name', 'student_number', 'nisn']),
|
|
'levelOptions' => $this->levelOptions(),
|
|
]);
|
|
}
|
|
|
|
public function update(Request $request, StudentAchievement $studentAchievement): RedirectResponse
|
|
{
|
|
$data = $this->validateAchievement($request);
|
|
|
|
if ($request->hasFile('certificate_file')) {
|
|
if ($studentAchievement->certificate_file && Storage::disk('public')->exists($studentAchievement->certificate_file)) {
|
|
Storage::disk('public')->delete($studentAchievement->certificate_file);
|
|
}
|
|
|
|
$data['certificate_file'] = $request->file('certificate_file')->store('student-achievements/certificates', 'public');
|
|
}
|
|
|
|
if ($request->hasFile('activity_photo')) {
|
|
if ($studentAchievement->activity_photo && Storage::disk('public')->exists($studentAchievement->activity_photo)) {
|
|
Storage::disk('public')->delete($studentAchievement->activity_photo);
|
|
}
|
|
|
|
$data['activity_photo'] = $request->file('activity_photo')->store('student-achievements/activity-photos', 'public');
|
|
}
|
|
|
|
$studentAchievement->update($data);
|
|
|
|
return redirect()->route('student-achievements.index')->with('success', 'Data siswa berprestasi berhasil diperbarui.');
|
|
}
|
|
|
|
public function destroy(StudentAchievement $studentAchievement): RedirectResponse
|
|
{
|
|
if ($studentAchievement->certificate_file && Storage::disk('public')->exists($studentAchievement->certificate_file)) {
|
|
Storage::disk('public')->delete($studentAchievement->certificate_file);
|
|
}
|
|
|
|
if ($studentAchievement->activity_photo && Storage::disk('public')->exists($studentAchievement->activity_photo)) {
|
|
Storage::disk('public')->delete($studentAchievement->activity_photo);
|
|
}
|
|
|
|
$studentAchievement->delete();
|
|
|
|
return redirect()->route('student-achievements.index')->with('success', 'Data siswa berprestasi berhasil dihapus.');
|
|
}
|
|
|
|
protected function validateAchievement(Request $request): array
|
|
{
|
|
return $request->validate([
|
|
'student_id' => ['required', 'exists:students,id'],
|
|
'achievement_name' => ['required', 'string', 'max:150'],
|
|
'category' => ['nullable', 'string', 'max:100'],
|
|
'level' => ['nullable', 'string', 'max:50'],
|
|
'organizer' => ['nullable', 'string', 'max:150'],
|
|
'rank' => ['nullable', 'string', 'max:100'],
|
|
'achievement_date' => ['nullable', 'date'],
|
|
'achievement_year' => ['nullable', 'integer', 'min:2000', 'max:' . now()->year],
|
|
'description' => ['nullable', 'string'],
|
|
'certificate_file' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png,webp', 'max:5120'],
|
|
'activity_photo' => ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:5120'],
|
|
]);
|
|
}
|
|
|
|
protected function levelOptions(): array
|
|
{
|
|
return [
|
|
'Sekolah' => 'Sekolah',
|
|
'Kecamatan' => 'Kecamatan',
|
|
'Kabupaten/Kota' => 'Kabupaten/Kota',
|
|
'Provinsi' => 'Provinsi',
|
|
'Nasional' => 'Nasional',
|
|
'Internasional' => 'Internasional',
|
|
];
|
|
}
|
|
}
|