Initial commit
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\AcademicYear;
|
||||
use App\Models\Department;
|
||||
use App\Models\SchoolClass;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\View\View;
|
||||
use RealRashid\SweetAlert\Facades\Alert;
|
||||
|
||||
class SchoolClassController extends Controller
|
||||
{
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$search = trim((string) $request->get('search'));
|
||||
|
||||
$classes = SchoolClass::with(['academicYear', 'department'])
|
||||
->withCount(['students', 'academicHistories'])
|
||||
->when($search !== '', function ($query) use ($search) {
|
||||
$query->where('name', 'like', "%{$search}%")
|
||||
->orWhere('level', 'like', "%{$search}%")
|
||||
->orWhere('homeroom_teacher', 'like', "%{$search}%");
|
||||
})
|
||||
->latest()
|
||||
->paginate(10)
|
||||
->withQueryString();
|
||||
|
||||
return view('classes.index', [
|
||||
'classes' => $classes,
|
||||
'search' => $search,
|
||||
'academicYears' => AcademicYear::orderByDesc('start_year')->orderByDesc('end_year')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): View
|
||||
{
|
||||
return view('classes.create', [
|
||||
'academicYears' => AcademicYear::where('is_active', true)->orderBy('name')->pluck('name', 'id'),
|
||||
'departments' => Department::where('is_active', true)->orderBy('name')->pluck('name', 'id'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'academic_year_id' => ['required', Rule::exists('academic_years', 'id')->where(fn ($query) => $query->where('is_active', true))],
|
||||
'department_id' => ['required', Rule::exists('departments', 'id')->where(fn ($query) => $query->where('is_active', true))],
|
||||
'name' => ['required', 'string', 'max:100', Rule::unique('classes', 'name')->where(fn ($query) => $query->where('academic_year_id', $request->academic_year_id))],
|
||||
'level' => ['required', 'string', 'max:10'],
|
||||
'homeroom_teacher' => ['nullable', 'string', 'max:100'],
|
||||
'capacity' => ['nullable', 'integer', 'min:1'],
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
]);
|
||||
|
||||
$data['is_active'] = $request->boolean('is_active');
|
||||
|
||||
SchoolClass::create($data);
|
||||
|
||||
return redirect()->route('classes.index')->with('success', 'Kelas berhasil ditambahkan.');
|
||||
}
|
||||
|
||||
public function generate(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'source_academic_year_id' => ['required', 'exists:academic_years,id', 'different:target_academic_year_id'],
|
||||
'target_academic_year_id' => ['required', 'exists:academic_years,id'],
|
||||
'generation_mode' => ['required', Rule::in(['same_level', 'promote_level'])],
|
||||
]);
|
||||
|
||||
$sourceClasses = SchoolClass::query()
|
||||
->where('academic_year_id', $data['source_academic_year_id'])
|
||||
->orderBy('department_id')
|
||||
->orderBy('level')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
if ($sourceClasses->isEmpty()) {
|
||||
Alert::error('Gagal', 'Tidak ada kelas pada tahun ajaran sumber yang bisa digenerate.');
|
||||
|
||||
return redirect()->route('classes.index')->withErrors([
|
||||
'generate' => 'Tidak ada kelas pada tahun ajaran sumber yang bisa digenerate.',
|
||||
]);
|
||||
}
|
||||
|
||||
$created = 0;
|
||||
$skipped = 0;
|
||||
|
||||
DB::transaction(function () use ($sourceClasses, $data, &$created, &$skipped) {
|
||||
foreach ($sourceClasses as $sourceClass) {
|
||||
$targetLevel = $data['generation_mode'] === 'promote_level'
|
||||
? $this->nextLevel($sourceClass->level)
|
||||
: $sourceClass->level;
|
||||
|
||||
if ($targetLevel === null) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$targetName = $this->transformClassName($sourceClass->name, $sourceClass->level, $targetLevel);
|
||||
|
||||
$exists = SchoolClass::query()
|
||||
->where('academic_year_id', $data['target_academic_year_id'])
|
||||
->where('name', $targetName)
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
SchoolClass::create([
|
||||
'academic_year_id' => $data['target_academic_year_id'],
|
||||
'department_id' => $sourceClass->department_id,
|
||||
'name' => $targetName,
|
||||
'level' => $targetLevel,
|
||||
'homeroom_teacher' => $sourceClass->homeroom_teacher,
|
||||
'capacity' => $sourceClass->capacity,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$created++;
|
||||
}
|
||||
});
|
||||
|
||||
Alert::success('Berhasil', "Generate kelas selesai. {$created} kelas dibuat, {$skipped} dilewati.");
|
||||
|
||||
return redirect()->route('classes.index')->with('success', "Generate kelas selesai. {$created} kelas dibuat, {$skipped} dilewati.");
|
||||
}
|
||||
|
||||
public function show(SchoolClass $class): RedirectResponse
|
||||
{
|
||||
return redirect()->route('classes.edit', $class);
|
||||
}
|
||||
|
||||
public function edit(SchoolClass $class): View
|
||||
{
|
||||
$class->loadMissing(['academicYear', 'department']);
|
||||
|
||||
$academicYears = AcademicYear::query()
|
||||
->where(function ($query) use ($class) {
|
||||
$query->where('is_active', true)
|
||||
->orWhere('id', $class->academic_year_id);
|
||||
})
|
||||
->orderBy('name')
|
||||
->pluck('name', 'id');
|
||||
|
||||
$departments = Department::query()
|
||||
->where(function ($query) use ($class) {
|
||||
$query->where('is_active', true)
|
||||
->orWhere('id', $class->department_id);
|
||||
})
|
||||
->orderBy('name')
|
||||
->pluck('name', 'id');
|
||||
|
||||
return view('classes.edit', [
|
||||
'class' => $class,
|
||||
'academicYears' => $academicYears,
|
||||
'departments' => $departments,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, SchoolClass $class): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'academic_year_id' => ['required', Rule::exists('academic_years', 'id')->where(fn ($query) => $query->where('is_active', true)->orWhere('id', $class->academic_year_id))],
|
||||
'department_id' => ['required', Rule::exists('departments', 'id')->where(fn ($query) => $query->where('is_active', true)->orWhere('id', $class->department_id))],
|
||||
'name' => ['required', 'string', 'max:100', Rule::unique('classes', 'name')->ignore($class->id)->where(fn ($query) => $query->where('academic_year_id', $request->academic_year_id))],
|
||||
'level' => ['required', 'string', 'max:10'],
|
||||
'homeroom_teacher' => ['nullable', 'string', 'max:100'],
|
||||
'capacity' => ['nullable', 'integer', 'min:1'],
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
]);
|
||||
|
||||
$data['is_active'] = $request->boolean('is_active');
|
||||
|
||||
$class->update($data);
|
||||
|
||||
return redirect()->route('classes.index')->with('success', 'Kelas berhasil diperbarui.');
|
||||
}
|
||||
|
||||
public function destroy(SchoolClass $class): RedirectResponse
|
||||
{
|
||||
$class->loadCount(['students', 'academicHistories']);
|
||||
|
||||
if ($class->students_count > 0) {
|
||||
Alert::error('Tidak bisa dihapus', 'Kelas ini masih digunakan oleh data siswa aktif.');
|
||||
|
||||
return redirect()->route('classes.index')->withErrors([
|
||||
'delete' => 'Kelas tidak bisa dihapus karena masih digunakan oleh data siswa aktif.',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($class->academic_histories_count > 0) {
|
||||
Alert::error('Tidak bisa dihapus', 'Kelas ini masih tercatat pada histori akademik siswa.');
|
||||
|
||||
return redirect()->route('classes.index')->withErrors([
|
||||
'delete' => 'Kelas tidak bisa dihapus karena masih tercatat pada histori akademik siswa. Hapus atau ubah histori terkait terlebih dahulu.',
|
||||
]);
|
||||
}
|
||||
|
||||
Alert::success('Berhasil', 'Kelas berhasil dihapus.');
|
||||
|
||||
$class->delete();
|
||||
|
||||
return redirect()->route('classes.index')->with('success', 'Kelas berhasil dihapus.');
|
||||
}
|
||||
|
||||
protected function nextLevel(?string $level): ?string
|
||||
{
|
||||
return match (strtoupper((string) $level)) {
|
||||
'X' => 'XI',
|
||||
'XI' => 'XII',
|
||||
'XII' => null,
|
||||
default => $level,
|
||||
};
|
||||
}
|
||||
|
||||
protected function transformClassName(string $name, ?string $fromLevel, ?string $toLevel): string
|
||||
{
|
||||
if (! $fromLevel || ! $toLevel || strtoupper($fromLevel) === strtoupper($toLevel)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return preg_replace('/^' . preg_quote($fromLevel, '/') . '\b/i', $toLevel, $name) ?: $name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user