<?php
namespace App\Http\Controllers;
use App\Models\ClassSchool;
use App\Models\ClassSection;
use App\Repositories\ClassSchool\ClassSchoolInterface;
use App\Repositories\ClassSection\ClassSectionInterface;
use App\Repositories\ClassSubject\ClassSubjectInterface;
use App\Repositories\ClassTeachers\ClassTeachersInterface;
use App\Repositories\Semester\SemesterInterface;
use App\Repositories\SessionYear\SessionYearInterface;
use App\Repositories\SubjectTeacher\SubjectTeacherInterface;
use App\Repositories\Timetable\TimetableInterface;
use App\Repositories\User\UserRepository;
use App\Services\BootstrapTableService;
use App\Services\CachingService;
use App\Services\ResponseService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Throwable;
class ClassSectionController extends Controller
{
private ClassSchoolInterface $class;
private ClassSectionInterface $classSection;
private UserRepository $user;
private ClassSubjectInterface $classSubjects;
private ClassTeachersInterface $classTeachers;
private SubjectTeacherInterface $subjectTeachers;
private TimetableInterface $timetable;
private SemesterInterface $semester;
private CachingService $cache;
public function __construct(ClassSchoolInterface $class, ClassSectionInterface $classSection, UserRepository $userRepository, ClassSubjectInterface $classSubjects, ClassTeachersInterface $classTeachers, SubjectTeacherInterface $subjectTeachers, TimetableInterface $timetable, SemesterInterface $semester, CachingService $cache)
{
$this->class = $class;
$this->classSection = $classSection;
$this->user = $userRepository;
$this->classSubjects = $classSubjects;
$this->classTeachers = $classTeachers;
$this->subjectTeachers = $subjectTeachers;
$this->timetable = $timetable;
$this->semester = $semester;
$this->cache = $cache;
}
public function index()
{
ResponseService::noPermissionThenRedirect('class-section-list');
$classes = $this->class->all(['id', 'name', 'medium_id', 'shift_id', 'stream_id'], ['stream', 'medium', 'shift']);
return response(view('class-section.index', compact('classes')));
}
public function show(Request $request)
{
ResponseService::noPermissionThenRedirect('class-section-list');
$offset = request('offset', 0);
$limit = request('limit', 5);
$sort = request('sort', 'id');
$order = request('order', 'DESC');
$semesters = $this->semester->builder()->get();
$sessionYearId = $this->cache->getSessionYear()->id;
// $sql = $this->classSection->builder()->with(['class.stream', 'section', 'medium', 'class_teachers.teacher', 'subject_teachers', 'subject_teachers.teacher', 'subject_teachers.semester:id,name','subject_teachers.class_subject'=> function ($q){
// $q->whereNull('deleted_at')->with('semester')
// ->with('subject')->owner();
// }]);
$sql = $this->classSection->builder()->with([
'class.stream',
'class.shift',
'section',
'medium',
'class_teachers' => function ($q) use ($sessionYearId) {
$q->where('session_year_id', $sessionYearId)->with('teacher');
},
'subject_teachers' => function ($q) use ($sessionYearId) {
$q->where('session_year_id', $sessionYearId)->with('teacher')
->has('class_subject')->with([
'class_subject' => function ($q) {
$q->whereNull('deleted_at')->with('semester');
}
])
->with('subject')->owner();
}
])->where(function ($query) use ($request) {
if (!empty($request->class_id)) {
$query->where('class_id', $request->class_id);
}
if (!empty($request->section_id)) {
$query->where('section_id', $request->section_id);
}
if (!empty($request->medium_id)) {
$query->where('medium_id', $request->medium_id);
}
if (!empty($request->teacher_id)) {
$query->whereHas('class_teachers', function ($q) use ($request) {
$q->where('teacher_id', $request->teacher_id);
});
}
if (!empty($request->subject_id)) {
$query->whereHas('subject_teachers', function ($q) use ($request) {
$q->where('subject_id', $request->subject_id);
});
}
if (!empty($request->class_subject_id)) {
$query->whereHas('subject_teachers.class_subject', function ($q) use ($request) {
$q->where('id', $request->class_subject_id);
});
}
})->when(!empty($showDeleted), function ($q) {
$q->onlyTrashed();
});
//Show only Trashed Data
if (!empty($request->show_deleted)) {
$sql = $sql->onlyTrashed();
}
if (!empty($request->search)) {
$search = $request->search;
$sql->where(function ($query) use ($search) {
$query->where('id', 'LIKE', "%$search%")
->orWhereHas('class', function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%");
})->orWhereHas('section', function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%");
})->orWhereHas('medium', function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%");
})->orWhereHas('class_teachers.teacher', function ($q) use ($search) {
$q->whereRaw("concat(first_name,' ',last_name) LIKE '%" . $search . "%'");
})->orWhereHas('subject_teachers.subject', function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%");
});
});
}
if (!empty($request->class_id)) {
$sql = $sql->where('class_id', $request->class_id);
}
$total = $sql->count();
if ($offset >= $total && $total > 0) {
$lastPage = floor(($total - 1) / $limit) * $limit; // calculate last page offset
$offset = $lastPage;
}
$sql->orderBy($sort, $order)->skip($offset)->take($limit);
$res = $sql->get();
$bulkData['total'] = $total;
$rows = array();
$no = 1;
foreach ($res as $row) {
$operate = '';
if ($request->show_deleted) {
//Show Restore and Hard Delete Buttons
if (Auth::user()->can('class-section-delete')) {
$operate .= BootstrapTableService::restoreButton(route('class-section.restore', $row->id));
$operate .= BootstrapTableService::trashButton(route('class-section.trash', $row->id));
}
} else {
//Show Edit and Soft Delete Buttons
if (Auth::user()->can('class-section-edit')) {
$operate .= BootstrapTableService::editButton(route('class-section.edit', $row->id), false);
}
if (Auth::user()->can('class-section-delete')) {
$operate .= BootstrapTableService::deleteButton(route('class-section.destroy', $row->id));
}
}
$tempRow = $row->toArray();
$tempRow['no'] = $no++;
$tempRow['class_teachers_list'] = $row->class_teachers->pluck('teacher.full_name');
$tempRow['subject_teachers_list'] = $row->subject_teachers->pluck('subject_with_name');
$tempRow['current_sem_subject_teachers_list'] = array();
if ($row->class->include_semesters) {
$tempRow['subject_teachers_with_semester'] = array();
foreach ($semesters as $semesterData) {
$tempRow['subject_teachers'] = array();
$teacherWithSubjectName = array();
foreach ($row->subject_teachers as $teacherData) {
if ($semesterData->current) {
if ($teacherData->class_subject->semester_id == $semesterData->id) {
$tempRow['current_sem_subject_teachers_list'][] = $teacherData->subject_with_name;
}
}
if ($teacherData->class_subject->semester_id == $semesterData->id) {
$teacherWithSubjectName[] = array(
'teacher_name' => $teacherData->teacher->full_name,
'subject_name' => $teacherData->subject_with_name,
);
}
}
$tempRow['subject_teachers_with_semester'][] = array(
'semester_id' => $semesterData->id,
'semester_name' => $semesterData->name,
'subject_teachers' => $teacherWithSubjectName,
);
}
}
$tempRow['operate'] = $operate;
$tempRow['created_at'] = $row->created_at;
$tempRow['updated_at'] = $row->updated_at;
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
return response()->json($bulkData);
}
public function edit($id)
{
ResponseService::noPermissionThenRedirect('class-section-edit');
$semesters = $this->semester->all();
$sessionYearId = $this->cache->getSessionYear()->id;
$classSection = $this->classSection->findById($id, ['*'], [
'class',
'class.stream',
'class.shift',
'section',
'medium',
'subjects',
'class_teachers' => function ($q) use ($sessionYearId) {
$q->where('session_year_id', $sessionYearId);
}
]);
$teachers = $this->user->builder()->role('Teacher')->get();
$classSubjects = $this->classSubjects->builder()->where('class_id', $classSection->class_id)->where('session_year_id', $sessionYearId)->with([
'subjectTeachers' => function ($q) use ($id, $sessionYearId) {
$q->where('class_section_id', $id)->where('session_year_id', $sessionYearId)->get();
},
'subject'
])->get();
return response(view('class-section.edit', compact('classSection', 'teachers', 'id', 'classSubjects', 'semesters')));
}
public function update(Request $request, $id)
{
ResponseService::noPermissionThenRedirect('class-section-edit');
try {
DB::beginTransaction();
// Initialize Empty Arrays
$classTeachersData = array();
$subjectTeachersData = array();
$sessionYearId = $this->cache->getSessionYear()->id;
// Check that Class Section has semester or not
$isClassSemester = $this->classSection->findById($id, ['*'], ['class'])->class->include_semesters;
if (!empty($request->class_teacher_id)) {
// Loop on the Class Teacher and add Data as Multi Dimensional Array in classTeachersData Array
foreach ($request->class_teacher_id as $teacherId) {
$classTeachersData[] = array(
"class_section_id" => $id,
"teacher_id" => $teacherId,
"session_year_id" => $sessionYearId,
);
$this->user->findById($teacherId)->givePermissionTo(['class-teacher', 'exam-upload-marks', 'exam-result', 'attendance-list']);
}
// Update or Insert Data in Class Teachers on the basis of Class Section ID, TeacherID and Session Year ID
$this->classTeachers->upsert($classTeachersData, ['class_section_id', 'teacher_id', 'session_year_id'], ['created_at', 'updated_at']);
}
if (!empty($request->subject_teachers)) {
// Loop on the Subject Teacher and do nested loop on teacher id and add Data in subjectTeachersData Array
foreach ($request->subject_teachers as $subjectTeachers) {
$subjectTeachers = (object) $subjectTeachers;
if (!empty($subjectTeachers->teacher_user_id)) {
foreach ($subjectTeachers->teacher_user_id as $teacherId) {
$subjectTeachersData[] = array(
"class_section_id" => $id,
"teacher_id" => $teacherId,
"subject_id" => $subjectTeachers->subject_id,
"class_subject_id" => $subjectTeachers->class_subject_id,
"session_year_id" => $sessionYearId,
);
$this->user->findById($teacherId)->givePermissionTo(['exam-upload-marks', 'exam-result']);
}
}
}
// Update or Insert Data in Class Teachers on the basis of Class Section ID , TeacherID, Subject ID and Session Year ID
$this->subjectTeachers->upsert($subjectTeachersData, ['class_section_id', 'teacher_id', 'class_subject_id', 'session_year_id'], ['subject_id']);
/*
IF New Subject Teacher is added then Reflect that Subject teacher in Timetable
if there are any timetable subjects which don't have any Teacher Assigned
*/
$noTeacherAssignedToTimetable = $this->timetable->builder()->where(['type' => 'Lecture', 'subject_teacher_id' => null, 'session_year_id' => $sessionYearId])->get();
if (!empty($noTeacherAssignedToTimetable)) {
$updateTimetable = [];
$subjectTeachers = $this->subjectTeachers->builder()->where(['class_section_id' => $id, 'session_year_id' => $sessionYearId])->get();
foreach ($noTeacherAssignedToTimetable as $timetable) {
$subjectTeacher = $subjectTeachers->first(function ($data) use ($timetable) {
return $data->subject_id === $timetable->subject_id;
});
if (!empty($subjectTeacher)) {
$updateTimetable[] = [
'id' => $timetable->id,
'subject_teacher_id' => $subjectTeacher->id,
'session_year_id' => $sessionYearId
];
}
}
if (!empty($updateTimetable)) {
$this->timetable->upsert($updateTimetable, ['id'], ['subject_teacher_id', 'session_year_id']);
}
}
}
DB::commit();
ResponseService::successResponse('Data Updated Successfully');
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function destroy($id)
{
ResponseService::noPermissionThenSendJson('class-section-delete');
try {
// // check whether the id in $delete_class_section is associated with other data .
// $assignments = Assignment::whereIn('class_section_id', $id)->count();
// $attendances = Attendance::whereIn('class_section_id', $id)->count();
// $exam_result = ExamResult::whereIn('class_section_id', $id)->count();
// $lessons = Lesson::whereIn('class_section_id', $id)->count();
// $student_session = PromoteStudents::whereIn('class_section_id', $id)->count();
// $students = Students::whereIn('class_section_id', $id)->count();
// $subject_teachers = SubjectTeacher::whereIn('class_section_id', $id)->count();
// $timetables = Timetable::whereIn('class_section_id', $id)->count();
//
// if ($assignments || $attendances || $exam_result || $lessons || $student_session || $students || $subject_teachers || $timetables) {
// $response = array('error' => true, 'message' => trans('cannot_delete_because_data_is_associated_with_other_data'));
// return response()->json($response);
// }
// $this->classSection->deleteById($id);
// 1. Find the specific class_section record
$classSection = ClassSection::findOrFail($id);
// 2. Store the class_id before deleting the section
$classId = $classSection->class_id;
// 3. Delete the class_section record
$classSection->delete();
// 4. Check if the class has any other active sections left
// using exists() is faster than using count()
// $hasRemainingSections = ClassSection::where('class_id', $classId)->exists();
// // 5. If no other sections exist, delete the main class record
// if (!$hasRemainingSections) {
// ClassSchool::where('id', $classId)->delete();
// }
ResponseService::successResponse('Data Deleted Successfully');
} catch (Throwable $e) {
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function restore(int $id)
{
ResponseService::noPermissionThenSendJson('class-section-delete');
try {
DB::beginTransaction();
$classSection = $this->classSection->findOnlyTrashedById($id);
$classSection->class->restore();
$classSection->restore();
DB::commit();
ResponseService::successResponse("Data Restored Successfully");
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function trash($id)
{
ResponseService::noPermissionThenSendJson('class-section-delete');
try {
$this->classSection->findOnlyTrashedById($id)->forceDelete();
ResponseService::successResponse("Data Deleted Permanently");
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Subject Controller -> Trash Method", 'cannot_delete_because_data_is_associated_with_other_data');
ResponseService::errorResponse();
}
}
public function removeClassTeacher($classTeacherID, $classSectionID)
{
ResponseService::noPermissionThenRedirect('class-section-edit');
try {
DB::beginTransaction();
$sessionYearId = $this->cache->getSessionYear()->id;
$this->classTeachers->builder()->where(['class_section_id' => $classSectionID, 'teacher_id' => $classTeacherID, 'session_year_id' => $sessionYearId])->delete();
$teacher = $this->user->findById($classTeacherID);
// Check this teacher has another class teacher is exists
$classTeachers = $this->classTeachers->builder()->where(['teacher_id' => $classTeacherID, 'session_year_id' => $sessionYearId])->first();
if (!$classTeachers) {
$teacher->revokePermissionTo(['class-teacher', 'exam-upload-marks', 'exam-result']);
}
DB::commit();
ResponseService::successResponse('Data Deleted Successfully');
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function removeSubjectTeacher($classSectionID, $teacherID, $subjectID)
{
ResponseService::noPermissionThenRedirect('class-section-edit');
try {
DB::beginTransaction();
$sessionYearId = $this->cache->getSessionYear()->id;
$this->subjectTeachers->builder()->where(['class_section_id' => $classSectionID, 'teacher_id' => $teacherID, 'subject_id' => $subjectID, 'session_year_id' => $sessionYearId])->delete();
$subjectTeachers = $this->subjectTeachers->builder()->where(['teacher_id' => $teacherID, 'session_year_id' => $sessionYearId])->first();
if (!$subjectTeachers) {
$this->user->findById($teacherID)->revokePermissionTo(['exam-upload-marks', 'exam-result']);
}
DB::commit();
ResponseService::successResponse('Data Deleted Successfully');
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
}