File "ExamController.php"
Full Path: /home/trinadezambia/public_html/admin_panel/app/Http/Controllers/Exam/ExamController.php
File size: 62.68 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace App\Http\Controllers\Exam;
use App\Exports\MarksDataExport;
use App\Imports\MarksDataImport;
use App\Http\Controllers\Controller;
use App\Models\ExamResult;
use App\Models\ExamTimetable;
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\Exam\ExamInterface;
use App\Repositories\ExamMarks\ExamMarksInterface;
use App\Repositories\ExamResult\ExamResultInterface;
use App\Repositories\ExamTimetable\ExamTimetableInterface;
use App\Repositories\Grades\GradesInterface;
use App\Repositories\Medium\MediumInterface;
use App\Repositories\SessionYear\SessionYearInterface;
use App\Repositories\Student\StudentInterface;
use App\Repositories\StudentSubject\StudentSubjectInterface;
use App\Repositories\Subject\SubjectInterface;
use App\Repositories\User\UserInterface;
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 Illuminate\Support\Facades\Hash;
use PDF;
use Throwable;
use Excel;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Validator;
use App\Models\ClassTeacher;
use Illuminate\Support\Str;
use function PHPUnit\Framework\isEmpty;
class ExamController extends Controller
{
private ExamInterface $exam;
private ClassSchoolInterface $class;
private SessionYearInterface $sessionYear;
private SubjectInterface $subject;
private ExamTimetableInterface $examTimetable;
private ClassSectionInterface $classSection;
private ExamMarksInterface $examMarks;
private ExamResultInterface $examResult;
private StudentSubjectInterface $studentSubject;
private ClassSubjectInterface $classSubject;
private UserInterface $users;
private CachingService $cache;
private MediumInterface $mediums;
private ClassTeachersInterface $classTeacher;
private GradesInterface $grade;
private StudentInterface $student;
public function __construct(ExamInterface $exam, ClassSchoolInterface $class, SessionYearInterface $sessionYear, SubjectInterface $subject, ExamTimetableInterface $examTimetable, ClassSectionInterface $classSection, ExamMarksInterface $examMarks, ExamResultInterface $examResult, StudentSubjectInterface $studentSubject, ClassSubjectInterface $classSubject, UserInterface $users, CachingService $cache, MediumInterface $mediums, ClassTeachersInterface $classTeacher, GradesInterface $grade, StudentInterface $student)
{
$this->exam = $exam;
$this->class = $class;
$this->sessionYear = $sessionYear;
$this->subject = $subject;
$this->examTimetable = $examTimetable;
$this->classSection = $classSection;
$this->examMarks = $examMarks;
$this->examResult = $examResult;
$this->studentSubject = $studentSubject;
$this->classSubject = $classSubject;
$this->users = $users;
$this->cache = $cache;
$this->mediums = $mediums;
$this->classTeacher = $classTeacher;
$this->grade = $grade;
$this->student = $student;
}
public function index()
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenRedirect('exam-create');
$classes = $this->class->all(['*'], ['stream', 'medium', 'shift']);
$subjects = $this->subject->builder()->orderBy('id', 'DESC')->get();
$mediums = $this->mediums->builder()->pluck('name', 'id');
return response(view('exams.index', compact('classes', 'subjects', 'mediums')));
}
public function store(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-create');
$request->validate([
'name' => 'required',
'class_id' => 'required|array',
'class_id.*' => 'exists:classes,id'
]);
try {
DB::beginTransaction();
$sessionYear = $this->cache->getSessionYear();
$sessionYearId = $sessionYear->id;
$examData = [];
// Loop through each class ID and create exam records
foreach ($request->class_id as $classId) {
$exam = $this->exam->create([
'name' => $request->name,
'session_year_id' => $sessionYearId,
'description' => $request->description,
'start_date' => $request->start_date,
'end_date' => $request->end_date,
'school_id' => Auth::user()->school_id,
'publish' => $request->publish ?? 0,
'last_result_submission_date' => $request->last_result_submission_date,
'class_id' => $classId
]);
$examData[] = $exam;
}
DB::commit();
ResponseService::successResponse('Data Stored Successfully');
} catch (Throwable $e) {
if (
Str::contains($e->getMessage(), [
'does not exist',
'file_get_contents'
])
) {
DB::commit();
ResponseService::warningResponse("Data Stored successfully. But App push notification not send.");
} else {
DB::rollBack();
ResponseService::logErrorResponse($e, "Exam Controller -> Store method");
ResponseService::errorResponse();
}
}
}
public function show()
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-list');
$offset = request('offset', 0);
$limit = request('limit', 10);
$sort = request('sort', 'id');
$order = request('order', 'DESC');
$search = request('search');
$showDeleted = request('show_deleted');
$medium_id = request('medium_id');
$class_id = request('class_id');
$schoolSettings = $this->cache->getSchoolSettings();
$sessionYearId = $this->cache->getSessionYear()->id;
$sql = $this->exam->builder()->with([
'class.medium',
'class.stream',
'class.shift',
'class.section'
])
->with([
'timetable' => function ($q) {
$q->with('class_subject.subject')
->with([
'exam_marks' => function ($query) {
$query->where('status', 1)
->with('user.student');
}
]);
}
])
->with([
'class.section' => function ($q) {
$q->whereNull('class_sections.deleted_at');
}
])
->where('session_year_id', $sessionYearId)
->when($search, function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('id', 'LIKE', "%$search%")
->orWhere('name', 'LIKE', "%$search%")
->orWhere('description', 'LIKE', "%$search%")
->orWhere('created_at', 'LIKE', "%" . date('Y-m-d H:i:s', strtotime($search)) . "%")
->orWhere('updated_at', 'LIKE', "%" . date('Y-m-d H:i:s', strtotime($search)) . "%")
->orWhereHas('session_year', function ($subQuery) use ($search) {
$subQuery->where('name', 'LIKE', "%$search%");
});
});
})->when($medium_id, function ($query) use ($medium_id) {
$query->whereHas('class', function ($q) use ($medium_id) {
$q->where('medium_id', $medium_id);
});
})->when($class_id, function ($query) use ($class_id) {
$query->whereHas('class', function ($q) use ($class_id) {
$q->where('id', $class_id);
});
})
->when(!empty($showDeleted), function ($query) {
$query->onlyTrashed();
});
$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 = array();
$bulkData['total'] = $total;
$rows = array();
$no = 1;
$classSections = $this->classSection->builder()->get()->toArray();
foreach ($res as $row) {
$operate = '';
if ($showDeleted) {
$operate .= BootstrapTableService::menuRestoreButton('restore', route('exams.restore', $row->id));
$operate .= BootstrapTableService::menuTrashButton('delete', route('exams.trash', $row->id));
} else if ($row->publish == 0) {
$operate .= BootstrapTableService::menuButton('timetable', route('exam.timetable.edit', $row->id));
$operate .= BootstrapTableService::menuButton('publish', "#", ["publish-exam-result"], ['data-id' => $row->id]);
if (($row->exam_status == 0)) {
$operate .= BootstrapTableService::menuEditButton('edit', route('exams.update', $row->id));
}
$operate .= BootstrapTableService::menuDeleteButton('delete', route('exams.destroy', $row->id));
} else if ($row->publish == 1) {
$operate .= BootstrapTableService::menuButton('timetable', route('exam.timetable.edit', $row->id));
$operate .= BootstrapTableService::menuButton('Unpublish', "#", ["publish-exam-result"], ['data-id' => $row->id]);
}
$tempRow = $row->toArray();
$tempRow['no'] = $no++;
$classSectionWiseStatus = []; // Initialize here to accumulate all data for the current exam
$sections = count($row->class->section ?? []) > 0 ? $row->class->section : [null];
foreach ($sections as $section) {
$sectionId = $section->id ?? null;
$subjectWiseStatus = [];
$processedSubjects = [];
$classNameWithSection = $row->class->name ?? '' . ' - ' . ($section?->name ?? '') . ' ' . ($row->class->medium->name ?? '');
$class_section_id = $this->findClassSection($classSections, $row->class_id, $sectionId);
if ($row->has_timetable) {
foreach ($row->timetable as $timetable) {
$subject = $timetable->subject_with_name;
$subjectId = $timetable->class_subject_id;
if (isset($processedSubjects[$subjectId])) {
continue;
}
$marks = collect([]);
if ($class_section_id) {
$marks = $timetable->exam_marks->where('user.student.class_section_id', $class_section_id);
}
$marksSubmitted = $marks->isNotEmpty();
$status = $marksSubmitted ? 'Submitted' : 'Pending';
$subjectWiseStatus[] = [
'subject_id' => $subjectId,
'subject' => $subject,
'status' => $status,
'marks_count' => $marksSubmitted ? $marks->count() : 0,
];
$processedSubjects[$subjectId] = true;
}
$classSectionStatus = count($subjectWiseStatus) > 0
? (collect($subjectWiseStatus)->contains('status', 'Pending') ? 'Pending' : 'Submitted')
: 'Pending';
$classSectionWiseStatus[] = [
'class_section_name' => $classNameWithSection,
'status' => $classSectionStatus,
'subjectWiseStatus' => $subjectWiseStatus,
];
}
}
// ===================================
// $sections = count($row->class->section ?? []) > 0 ? $row->class->section : [null];
// foreach ($sections as $section) {
// $sectionId = $section?->id;
// $subjectWiseStatus = [];
// $processedSubjects = [];
// $classstreamname = ($classstreamname = $row->class?->stream?->name) ? ' (' . $classstreamname . ')' : ' ';
// $classshiftname = ($classshiftname = $row->class?->shift?->name) ? ' (' . $classshiftname . ')' : '';
// $classNameWithSection = $row->class->name . ' - ' . ($section?->name ?? '') . ' ' . ($row->class->medium->name ?? '') . $classstreamname . $classshiftname;
// // Get the class section ID for this section
// $class_section_id = $this->findClassSection($classSections, $row->class_id, $sectionId);
// if ($row->has_timetable) {
// foreach ($row->timetable as $timetable) {
// $subject = $timetable->subject_with_name;
// $subjectId = $timetable->class_subject_id;
// if (isset($processedSubjects[$subjectId])) {
// continue;
// }
// // Filter marks by class section ID instead of section ID directly
// $marks = collect([]);
// if ($class_section_id) {
// $marks = $timetable->exam_marks->where('user.student.class_section_id', $class_section_id);
// }
// $marksSubmitted = $marks->isNotEmpty();
// $status = $marksSubmitted ? 'Submitted' : 'Pending';
// $subjectWiseStatus[] = [
// 'subject_id' => $subjectId,
// 'subject' => $subject,
// 'status' => $status,
// 'marks_count' => $marksSubmitted ? $marks->count() : 0,
// ];
// $processedSubjects[$subjectId] = true;
// }
// $classSectionWiseStatus[] = [
// 'class_section_name' => $classNameWithSection,
// 'subject_wise_status' => $subjectWiseStatus,
// ];
// }
// }
$tempRow['classSectionWiseStatus'] = $classSectionWiseStatus;
$tempRow['operate'] = BootstrapTableService::menuItem($operate);
$tempRow['created_at'] = date($schoolSettings['date_format'], strtotime($row->created_at));
$tempRow['updated_at'] = date($schoolSettings['date_format'], strtotime($row->updated_at));
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
return response()->json($bulkData);
}
public function update($id, Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-edit');
$request->validate(['name' => 'required']);
try {
$this->exam->update($id, $request->all());
ResponseService::successResponse('Data Updated Successfully');
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Exam Controller -> Update method");
ResponseService::errorResponse();
}
}
public function destroy($id)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-delete');
try {
$this->exam->deleteById($id);
ResponseService::successResponse('Data Deleted Successfully');
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e, "Exam Controller -> Delete method");
ResponseService::errorResponse();
}
}
public function restore(int $id)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-delete');
try {
$this->exam->findOnlyTrashedById($id)->restore();
ResponseService::successResponse("Data Restored Successfully");
} catch (Throwable $e) {
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function trash($id)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-delete');
try {
$this->exam->findOnlyTrashedById($id)->forceDelete();
ResponseService::successResponse("Data Deleted Permanently");
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Exam Controller ->Trash Method", 'Can not Delete this because marks are already submitted');
ResponseService::errorResponse();
}
}
// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*** Upload Marks ***/
public function uploadMarks()
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenRedirect('exam-upload-marks');
$sessionYearId = $this->cache->getSessionYear()->id;
// $teacherId = Auth::user()->teacher->user_id;
$teacherId = Auth::user()->id;
$classes = $this->classSection->builder()->whereHas('class_teachers', function ($query) use ($teacherId, $sessionYearId) {
$query->where('teacher_id', $teacherId)->where('session_year_id', $sessionYearId);
})->with('class.stream', 'class.shift', 'section', 'medium')->orWhereHas('subject_teachers', function ($q) use ($teacherId, $sessionYearId) {
$q->where('teacher_id', $teacherId)->where('session_year_id', $sessionYearId);
})->get();
$exams = $this->exam->builder()->with([
'timetable' => function ($query) {
$query->where('date', '<', date('Y-m-d'))->orWhere(function ($q) {
$q->whereDate('date', '=', date('Y-m-d'))->where('end_time', '<=', date('H:i:s'));
})->with([
'class_subject' => function ($q) {
$q->SubjectTeacherClassTeacher()->with([
'subject_teacher' => function ($q) {
$q->where('teacher_id', Auth::user()->id)->with('subject');
}
]);
}
]);
}
])->where('publish', 0)->where('session_year_id', $sessionYearId)->get();
return response()->view('exams.upload-marks', compact('exams', 'classes'));
}
public function marksList(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
$request->validate(['class_section_id' => 'required', 'exam_id' => 'required', 'class_subject_id' => 'required',], ['class_section_id.required' => 'Class section field is required', 'exam_id.required' => 'Exam field is required', 'class_subject_id.required' => 'Class subject field is required',]);
try {
// Sorting and limit settings
$sort = $request->input('sort', 'id');
$order = $request->input('order', 'ASC');
$search = $request->input('search');
$sessionYear = $this->cache->getSessionYear();
// Get Exam with timetable id and date to get exam status also
$exam = $this->exam->builder()->with('timetable')->where('id', $request->exam_id)->where('session_year_id', $sessionYear->id)->firstOrFail();
// Get Student ids according to Subject is elective or compulsory
$classSubject = $this->classSubject->builder()->where('id', $request->class_subject_id)->withTrashed()->first();
if ($classSubject->type == "Elective") {
$studentIds = $this->studentSubject->builder()->where(['class_section_id' => $request->class_section_id, 'class_subject_id' => $classSubject->id])->pluck('student_id');
} else {
$studentIds = $this->users->builder()->role('Student')->whereHas('student', function ($query) use ($request) {
$query->where('class_section_id', $request->class_section_id);
})->pluck('id');
}
// Get Timetable Data
$timetable = $exam->timetable()->where('class_subject_id', $request->class_subject_id)->first();
// IF Timetable is empty then show error message
if (!$timetable) {
return response()->json(['error' => true, 'message' => trans('Exam Timetable Does not Exists')]);
}
// IF Exam status is not 2 that is exam not completed then show error message
if ($exam->exam_status != 2) {
ResponseService::errorResponse('Exam not completed yet');
}
$sessionYear = $this->cache->getSessionYear(); // Get Students Data on the basis of Student ids
$students = $this->users->builder()->role('Student')->whereIn('id', $studentIds)->with([
'exam_marks' => function ($query) use ($timetable) {
$query->where('exam_timetable_id', $timetable->id);
}
])
->when($search, function ($q) use ($search) {
$q->whereRaw("concat(first_name,' ',last_name) LIKE '%" . $search . "%'");
})
->whereHas('student', function ($q) use ($sessionYear) {
$q->where('session_year_id', $sessionYear->id);
})
->orderBy($sort, $order)->get();
// Loop on the Students Data
$rows = [];
foreach ($students as $no => $student) {
$rows[] = ['id' => $student->id, 'no' => $no + 1, 'student_name' => $student->full_name, 'total_marks' => $timetable->total_marks, 'exam_marks_id' => $student->exam_marks[0]->id ?? '', 'obtained_marks' => $student->exam_marks[0]->obtained_marks ?? '', 'status' => $student->exam_marks[0]->status ?? null, 'operate' => '<a href=' . route('exams.edit', $student->id) . ' class="btn btn-xs btn-gradient-primary btn-rounded btn-icon edit-data" data-id=' . $student->id . ' title="Edit" data-toggle="modal" data-target="#editModal"><i class="fa fa-edit"></i></a> <a href=' . route('exams.destroy', $student->id) . ' class="btn btn-xs btn-gradient-danger btn-rounded btn-icon delete-form" data-id=' . $student->id . '><i class="fa fa-trash"></i></a>',];
}
// Return Data as bulk-data
$bulkData['rows'] = $rows;
return response()->json($bulkData);
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Exam Controller -> Get Exam Subjects");
ResponseService::errorResponse();
}
}
public function submitMarks(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
$request->validate(['exam_id' => 'required|numeric', 'class_subject_id' => 'required|numeric', 'exam_marks' => 'required|array',], ['class_id.required' => 'Class section field is required.', 'exam_id.required' => 'Exam field is required.', 'class_subject_id.required' => 'Subject field is required.', 'exam_marks.required' => 'No records found.',]);
try {
$sessionYearId = $this->cache->getSessionYear()->id;
$exam_timetable = $this->examTimetable->builder()->where(['exam_id' => $request->exam_id, 'class_subject_id' => $request->class_subject_id, 'session_year_id' => $sessionYearId])->firstOrFail();
foreach ($request->exam_marks as $examMarks) {
$passing_marks = $exam_timetable->passing_marks;
if ($examMarks['obtained_marks'] >= $passing_marks) {
$status = 1;
} else {
$status = 0;
}
$marks_percentage = ($examMarks['obtained_marks'] / $examMarks['total_marks']) * 100;
$exam_grade = findExamGrade($marks_percentage);
if ($exam_grade == null) {
ResponseService::errorResponse('Grades data does not exists');
}
$this->examMarks->updateOrCreate(['id' => $examMarks['exam_marks_id'] ?? null], ['exam_timetable_id' => $exam_timetable->id, 'student_id' => $examMarks['student_id'], 'class_subject_id' => $request->class_subject_id, 'obtained_marks' => $examMarks['obtained_marks'], 'passing_status' => $status, 'session_year_id' => $exam_timetable->session_year_id, 'grade' => $exam_grade, 'status' => $request->status ?? 0]);
}
if ($request->status == 0) {
ResponseService::successResponse('Data stored in draft successfully');
}
ResponseService::successResponse('Data stored and published successfully');
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Exam Controller -> Get Exam Subjects");
ResponseService::errorResponse();
}
}
public function getSubjectByExam($exam_id, Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
try {
$teacherId = Auth::user()->id;
$sessionYearId = $this->cache->getSessionYear()->id;
$isClassTeacher = ClassTeacher::where('teacher_id', $teacherId)->where('session_year_id', $sessionYearId)->where('class_section_id', $request->class_section_id)->first();
if ($isClassTeacher) {
$exam_timetable = ExamTimetable::with(['subject_teacher'])
->with([
'class_subject' => function ($q) {
$q->withTrashed();
}
])
->where('exam_id', $exam_id)
->get();
} else {
$exam_timetable = ExamTimetable::with([
'subject_teacher' => function ($q) use ($sessionYearId) {
$q->where('session_year_id', $sessionYearId);
}
])
->with([
'class_subject' => function ($q) {
$q->withTrashed();
}
])
->whereHas('subject_teacher', function ($query) use ($teacherId, $request, $sessionYearId) {
$query->where('teacher_id', $teacherId)->where('session_year_id', $sessionYearId)->where('class_section_id', $request->class_section_id);
})
->where('exam_id', $exam_id)
->get();
}
$response = array('error' => false, 'message' => trans('data_fetch_successfully'), 'data' => $exam_timetable);
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Exam Controller -> Get Exam Subjects");
ResponseService::errorResponse();
}
return response()->json($response);
}
// -----------------------------------------------------------------------------------------------------
/*** Exam Result ***/
public function getExamResultIndex()
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenRedirect('exam-result');
$sessionYearId = $this->cache->getSessionYear()->id;
$exams = $this->exam->builder()->with('class.medium')->where('publish', 1)->where('session_year_id', $sessionYearId);
// $classSections = $this->classSection->all(['*'], ['class', 'class.stream', 'section', 'medium']);
$classSections = $this->classSection->builder()->with('class.stream', 'class.shift', 'section', 'medium');
if (Auth::user()->hasRole('Teacher')) {
$classTeacher = $this->classTeacher->builder()->where(['teacher_id' => Auth::user()->id, 'session_year_id' => $sessionYearId])->with('class_section')->get();
$classSections = $classSections->whereIn('id', $classTeacher->pluck('class_section_id')->toArray());
$exams = $exams->whereIn('class_id', $classTeacher->pluck('class_id')->toArray());
}
$classSections = $classSections->get();
$exams = $exams->get()->append(['prefix_name']);
return view('exams.show_exam_result', compact('exams', 'classSections'));
}
public function showExamResult(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-result');
$offset = request('offset', 0);
$limit = request('limit', 10);
$sort = request('sort', 'id');
$order = request('order', 'DESC');
$search = request('search');
$sessionYearId = $this->cache->getSessionYear()->id;
$sql = $this->examResult->builder()->with([
'user:id,first_name,last_name,email,image,school_id',
'user.exam_marks' => function ($q) use ($request) {
$q->whereHas('timetable', function ($q) use ($request) {
$q->where('exam_id', $request->exam_id);
})->with('timetable', 'subject');
}
])->where('exam_id', $request->exam_id)
->where('session_year_id', $sessionYearId)
->when($search, function ($q) use ($search, $request) {
$q->where(function ($q) use ($search) {
$q->where('id', 'LIKE', "%$search%")
->orwhere('total_marks', 'LIKE', "%$search%")
->orwhere('grade', 'LIKE', "%$search%")
->orwhere('obtained_marks', 'LIKE', "%$search%")
->orwhere('percentage', 'LIKE', "%$search%")
->orWhereHas('user', function ($q) use ($search) {
$q->whereRaw("concat(first_name,' ',last_name) LIKE '%" . $search . "%'");
});
})->where('exam_id', $request->exam_id)->Owner();
});
if ($request->class_section_id) {
$sql = $sql->where('class_section_id', $request->class_section_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 = array();
$bulkData['total'] = $total;
$rows = array();
$no = 1;
foreach ($res as $row) {
$operate = '';
if (Auth::user()->can('exam-result-edit')) {
$operate = BootstrapTableService::button('fa fa-edit', '#', ['btn-gradient-primary', 'btn-xs', 'btn-rounded', 'btn-icon', 'edit-data'], ['data-id' => $row->id, 'data-student_id' => $row->student_id, 'title' => 'Edit', 'data-toggle' => 'modal', 'data-target' => '#editModal']);
$operate .= BootstrapTableService::button('fa fa-file-pdf-o', url('exams/result/student/') . '/' . $row->student_id . '/exam/' . $row->exam_id, ['btn-gradient-info', 'btn-xs', 'btn-rounded', 'btn-icon',], ['title' => __('view_result'), 'target' => '_blank']);
}
$tempRow = $row->toArray();
$tempRow['no'] = $no++;
$tempRow['operate'] = $operate;
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
return response()->json($bulkData);
}
public function updateExamResultMarks(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenSendJson('exam-result-edit');
$request->validate([
'edit.*.marks_id' => 'required|numeric',
'edit.*.obtained_marks' => 'required|numeric|lte:edit.*.total_marks'
]);
try {
DB::beginTransaction();
// Loop Through Request Data
foreach ($request->edit as $data) {
$passingMarks = $data['passing_marks']; // Get Passing Marks
$marksPercentage = ($data['obtained_marks'] / $data['total_marks']) * 100; // Get Percentage
// Get Percentage And Check that Grades Should not be NULL
$grade = findExamGrade($marksPercentage);
if ($grade == null) {
ResponseService::errorResponse("Grades data does not exists");
}
// Array for Update Marks
$updateMarksData = array(
'obtained_marks' => $data['obtained_marks'],
'passing_status' => $data['obtained_marks'] >= $passingMarks ? 1 : 0,
'grade' => $grade
);
$this->examMarks->update($data['marks_id'], $updateMarksData); // Update Exam Marks
$examResultId = $this->examResult->builder()->where(['exam_id' => $data['exam_id'], 'student_id' => $data['student_id']])->value('id'); // Get Exam Result ID
// Query Data From Exam Table To Get Exam Marks According to Exam ID
DB::enableQueryLog();
$exam = $this->exam->builder()->with([
'marks' => function ($query) use ($data) {
$query->with('user.student:id,user_id,class_section_id')
->selectRaw('SUM(obtained_marks) as total_obtained_marks,student_id')
->selectRaw('SUM(total_marks) as total_marks')
->selectRaw('MIN(CASE WHEN passing_status = 0 THEN 0 ELSE 1 END) as overall_passing_status')
->where('student_id', $data['student_id'])
->groupBy('student_id');
},
'timetable' => function ($query) use ($data) {
$query->where(['exam_id' => $data['exam_id']]);
}
])->where('id', $data['exam_id'])->first();
// Loop through Exam Marks Data
foreach ($exam->marks as $examMarks) {
$percentage = ($examMarks['total_obtained_marks'] * 100) / $examMarks['total_marks']; // Get Percentage
// Get Percentage And Check that Grades Should not be NULL
$grade = findExamGrade($percentage);
if ($grade == null) {
ResponseService::errorResponse("Grades data does not exists");
}
// Array For Update Exam Result Data
$examResultData = array("obtained_marks" => $examMarks['total_obtained_marks'], "percentage" => round($percentage, 2), "grade" => $grade, "status" => $examMarks['overall_passing_status']);
$this->examResult->update($examResultId, $examResultData); // Update Exam Result
}
}
DB::commit();
ResponseService::successResponse("Data Updated Successfully");
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e, "Exam Controller -> updateExamResultMarks method");
ResponseService::errorResponse();
}
}
// -----------------------------------------------------------------------------------------------------
public function publishExamResult($id)
{
ResponseService::noFeatureThenRedirect('Exam Management');
try {
// Get The Exam Data with Marks and Timetable
$exam = $this->exam->builder()->with([
'marks' => function ($query) {
$query->with('user:id,first_name,last_name,image', 'user.student:id,user_id,class_section_id')->selectRaw('SUM(obtained_marks) as total_obtained_marks, student_id')->selectRaw('SUM(total_marks) as total_marks')->groupBy('student_id');
},
'timetable:id,exam_id,start_time,end_time'
])->with([
'timetable' => function ($q) {
$q->with([
'exam_marks' => function ($query) {
$query->where('status', 1);
}
]);
}
])->findOrFail($id);
$allSubjectsSubmitted = true;
foreach ($exam->timetable as $timetable) {
// Check if there are no exam marks associated with this timetable
if ($timetable->exam_marks->isEmpty()) {
// If marks for any subject are missing, set the flag to false and break the loop
$allSubjectsSubmitted = false;
break;
}
}
if (!$allSubjectsSubmitted) {
ResponseService::errorResponse("Marks are not uploaded yet.");
}
DB::beginTransaction();
if ($exam->exam_status == 2 && $exam->marks->isNotEmpty()) {
if ($exam->publish == 0) {
// If exam is Unpublished then Insert ExamResult records and Publish the Exam
$examResult = $exam->marks->map(function ($examMarks) use ($exam, $id) {
$percentage = ($examMarks['total_obtained_marks'] * 100) / $examMarks['total_marks'];
$grade = findExamGrade($percentage);
if ($grade === null) {
ResponseService::errorResponse("Grades data does not exists");
}
// Get passing status
$status = $this->resultStatus($id, $examMarks['student_id']);
$data = [
'exam_id' => $exam->id,
'class_section_id' => $examMarks['user']['student']['class_section_id'],
'student_id' => $examMarks['student_id'],
'total_marks' => $examMarks['total_marks'],
'obtained_marks' => $examMarks['total_obtained_marks'],
'percentage' => round($percentage, 2),
'grade' => $grade,
'status' => $status,
'session_year_id' => $exam->session_year_id
];
return $data;
});
$studentIds = $examResult->pluck('student_id')->toArray();
$guardian_id = $this->student->builder()->with('user')->whereIn('user_id', $studentIds)->pluck('guardian_id')->toArray();
$this->examResult->createBulk($examResult->toArray()); // Add Data in Exam Result
$this->exam->update($id, ['publish' => 1]); // Update Exam with Publish status 1
$user = array_merge($studentIds, $guardian_id);
$title = 'Result Publish for ' . $exam->name . ' examinations !!!';
$body = 'Congrats your result has been publish Click here see your result ';
$type = 'exam result';
// -------------------------------------------------------
// NEW LOGIC — Correct Result IDs per Student/User
// -------------------------------------------------------
// Get mapping of student_id => result_id
$resultMap = ExamResult::where('exam_id', $exam->id)
->whereIn('student_id', $studentIds)
->pluck('id', 'student_id')
->toArray(); // [student_id => result_id]
// Send individual notifications
foreach ($user as $userId) {
// Their specific result_id
$resultId = $resultMap[$userId] ?? null;
if (!$resultId)
continue;
// Custom data for this specific user
$customData = [
'exam_id' => $exam->id,
'result_id' => $resultId
];
// Send notification to this user only
send_notification([$userId], $title, $body, $type, $customData);
}
} else {
ExamResult::where('exam_id', $id)->delete(); // If Exam is already published then unpublished it and delete Exam Result
$this->exam->update($id, ['publish' => 0]); // Update Exam with Publish status 0
}
DB::commit();
ResponseService::successResponse('Data Stored Successfully');
} else {
ResponseService::errorResponse('Exam not completed yet');
}
} catch (Throwable $e) {
if (
Str::contains($e->getMessage(), [
'does not exist',
'file_get_contents'
])
) {
DB::commit();
ResponseService::warningResponse("Data Stored successfully. But App push notification not send.");
} else {
DB::rollBack();
ResponseService::logErrorResponse($e, "Exam Controller -> publishExamResult method");
ResponseService::errorResponse();
}
}
}
public function resultStatus($exam_id, $student_id)
{
$status = $this->examMarks->builder()->whereHas('timetable', function ($q) use ($exam_id) {
$q->where('exam_id', $exam_id);
})->where('student_id', $student_id)->where('passing_status', 0)->first();
if ($status) {
return 0;
}
return 1;
}
public function deleteExamTimetable($id)
{
ResponseService::noPermissionThenSendJson('exam-timetable-delete');
try {
DB::beginTransaction();
$this->examTimetable->deleteById($id);
DB::commit();
ResponseService::successResponse('Data Deleted Successfully');
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e, "Exam Controller -> DeleteTimetable method", trans('cannot_delete_because_data_is_associated_with_other_data'));
ResponseService::errorResponse();
}
}
public function resultReport($session_year_id, $exam_name)
{
try {
$exams = $this->exam->builder()->select('id', 'name', 'class_id', 'session_year_id', 'publish')->with('class.medium')->where('session_year_id', $session_year_id)->where('publish', 1)->where('name', $exam_name)->withCount('results as total_students')->withCount([
'results as pass_students' => function ($q) {
$q->where('status', 1);
}
])->get()->makeHidden(['exam_status', 'exam_status_name', 'has_timetable']);
ResponseService::successResponse('Data Fetched Successfully', $exams);
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function examTimetableIndex()
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noAnyPermissionThenRedirect(['exam-upload-marks', 'exam-timetable-list']);
try {
$class_sections = $this->classSection->builder()->with('class.stream', 'class.shift', 'medium')->get()->pluck('full_name', 'class_id');
$sessionYear = $this->cache->getSessionYear();
$class_id = array_keys($class_sections->toArray());
$exams = $this->exam->builder()->whereIn('class_id', $class_id)->where('session_year_id', $sessionYear->id)->get();
return view('exams.exams_timetable', compact('class_sections', 'exams'));
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function examTimetableShow(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noAnyPermissionThenRedirect(['exam-upload-marks', 'exam-timetable-list']);
try {
$sql = $this->examTimetable->builder()->with('class_subject.subject')
->where('exam_id', $request->exam_id)
->orderBy('date', 'ASC')->orderBy('start_time', 'ASC');
$total = $sql->count();
$res = $sql->get();
$bulkData = array();
$bulkData['total'] = $total;
$rows = array();
$no = 1;
foreach ($res as $row) {
$tempRow = $row->toArray();
$tempRow['no'] = $no++;
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
return response()->json($bulkData);
} catch (Throwable $e) {
DB::rollBack();
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function examResultPdf($student_id, $exam_id)
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenRedirect('exam-result');
try {
$results = $this->examResult->builder()
->with([
'exam',
'session_year',
'class_section.class.stream',
'class_section.section',
'class_section.medium',
'user' => function ($q) use ($exam_id) {
$q->with([
'student.guardian',
'exam_marks' => function ($q) use ($exam_id) {
$q->whereHas('timetable', function ($q) use ($exam_id) {
$q->where('exam_id', $exam_id);
})->with([
'class_subject' => function ($q) {
$q->withTrashed()->with('subject:id,name,type');
},
'timetable'
]);
}
]);
}
])
->where('exam_id', $exam_id)
->select('exam_results.*')
->get();
// Convert the results to a collection
$results = collect($results);
// Add rank calculation to each item in the collection
$results = $results->map(function ($result) {
$rank = DB::table('exam_results as er2')
->where('er2.class_section_id', $result->class_section_id)
->where('er2.obtained_marks', '>', $result->obtained_marks)
->where('er2.exam_id', $result->exam_id)
->where('er2.status', 1)
->distinct('er2.obtained_marks')
->count() + 1;
$result->rank = $rank;
return $result;
});
// Filter the collection based on student ID
$result = $results->where('student_id', $student_id)->first();
if (!$result) {
return redirect()->back()->with('error', trans('no_records_found'));
}
$grades = $this->grade->builder()->orderBy('starting_range', 'ASC')->get();
$settings = $this->cache->getSchoolSettings();
$data = explode("storage/", $settings['horizontal_logo'] ?? '');
$settings['horizontal_logo'] = end($data);
if ($settings['horizontal_logo'] == null) {
$systemSettings = $this->cache->getSystemSettings();
$data = explode("storage/", $systemSettings['horizontal_logo'] ?? '');
$settings['horizontal_logo'] = end($data);
}
$pdf = PDF::loadView('exams.exam_result_pdf', compact('result', 'settings', 'grades'));
return $pdf->stream();
} catch (Throwable $e) {
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
public function bulkUploadIndex()
{
ResponseService::noFeatureThenRedirect('Exam Management');
$teacherId = Auth::user()->teacher->user_id;
$sessionYearId = $this->cache->getSessionYear()->id;
// Fetch classes where the teacher is a class teacher or subject teacher
$classes = $this->classSection->builder()
->whereHas('class_teachers', function ($query) use ($teacherId, $sessionYearId) {
$query->where('teacher_id', $teacherId)->where('session_year_id', $sessionYearId);
})
->orWhereHas('subject_teachers', function ($query) use ($teacherId, $sessionYearId) {
$query->where('teacher_id', $teacherId)->where('session_year_id', $sessionYearId);
})
->with('class.stream', 'class.shift', 'section', 'medium', 'subjects')
->get();
$exams = $this->exam->builder()->with([
'timetable' => function ($query) {
$query->where('date', '<', date('Y-m-d'))->orWhere(function ($q) {
$q->whereDate('date', '=', date('Y-m-d'))->where('end_time', '<=', date('H:i:s'));
})->with([
'class_subject' => function ($q) {
$q->SubjectTeacherClassTeacher()->with([
'subject_teacher' => function ($q) {
$q->where('teacher_id', Auth::user()->id)->with('subject');
}
]);
}
]);
}
])->where('publish', 0)->where('session_year_id', $sessionYearId)->get();
return response(view('exams.bulk_upload_marks', compact('classes', 'exams')));
}
public function downloadSampleFile(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
$validator = Validator::make($request->all(), [
'class_section_id' => 'required|numeric',
'exam_id' => 'required',
'class_subject_id' => 'required',
]);
if ($validator->fails()) {
ResponseService::errorResponse($validator->errors()->first());
}
try {
$sessionYearId = $this->cache->getSessionYear()->id;
$exam = $this->exam->builder()->with('timetable')->where('id', $request->exam_id)->where('session_year_id', $sessionYearId)->first();
// Get Student ids according to Subject is elective or compulsory
$classSubject = $this->classSubject->builder()->where('id', $request->class_subject_id)->withTrashed()->first();
if ($classSubject->type == "Elective") {
$studentIds = $this->studentSubject->builder()->where(['class_section_id' => $request->class_section_id, 'class_subject_id' => $classSubject->id])->pluck('student_id');
} else {
$studentIds = $this->users->builder()->role('Student')->whereHas('student', function ($query) use ($request) {
$query->where('class_section_id', $request->class_section_id);
})->pluck('id');
}
// Get Timetable Data
$timetable = $exam->timetable()->where('class_subject_id', $request->class_subject_id)->first();
// IF Timetable is empty then show error message
if (!$timetable) {
return redirect()->route('exam.bulk-upload-marks')->with('error', trans('Exam Timetable Does not Exists'));
}
// IF Exam status is not 2 that is exam not completed then show error message
if ($exam->exam_status != 2) {
ResponseService::errorRedirectResponse(null, 'Exam not completed yet');
}
$sessionYear = $this->cache->getSessionYear();
$students = $this->users->builder()->role('Student')->whereIn('id', $studentIds)->with([
'student' => function ($query) use ($sessionYear) {
$query->where('session_year_id', $sessionYear->id);
},
'exam_marks' => function ($query) use ($timetable) {
$query->where('exam_timetable_id', $timetable->id);
}
])->get();
$data = [];
// Loop on the Students Data
foreach ($students as $student) {
$data[] = [
'exam_marks_id' => $student->exam_marks[0]->id ?? '',
'student_id' => $student->id,
'student_name' => $student->full_name,
'total_marks' => $timetable->total_marks,
'obtained_marks' => $student->exam_marks[0]->obtained_marks ?? '',
];
}
// Create a file name using Class Section, Exam Name, and Subject Name
$classSection = $this->classSection->builder()->with('class', 'class.stream', 'class.shift', 'section', 'medium')->where('id', $request->class_section_id)->first()->full_name;
$examName = $exam->name;
$subjectName = $classSubject->subject->name;
$file_name = $classSection . '_' . $examName . '_' . $subjectName . '_marks_bulk_upload.xlsx';
$file_name = str_replace(['/', '\\'], '-', $file_name);
$file_name = preg_replace('/[^A-Za-z0-9_\-\.]/', '_', $file_name);
return Excel::download(new MarksDataExport($data), $file_name);
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, 'Exam Controller ---> Download Sample File');
ResponseService::errorResponse();
}
}
public function storeBulkData(Request $request)
{
ResponseService::noFeatureThenRedirect('Exam Management');
$validator = Validator::make($request->all(), [
'class_section_id' => 'required|numeric',
'exam_id' => 'required',
'class_subject_id' => 'required',
'file' => 'required|mimes:csv,txt'
]);
if ($validator->fails()) {
ResponseService::errorResponse($validator->errors()->first());
}
try {
Excel::import(new MarksDataImport($request->class_section_id, $request->exam_id, $request->class_subject_id), $request->file);
ResponseService::successResponse('Data Stored Successfully');
} catch (ValidationException $e) {
ResponseService::errorResponse($e->getMessage());
} catch (Throwable $e) {
ResponseService::logErrorResponse($e, "Exam Controller -> Store Bulk method");
ResponseService::errorResponse();
}
}
public function viewMarksindex()
{
ResponseService::noFeatureThenRedirect('Exam Management');
ResponseService::noPermissionThenRedirect('exam-create');
$classes = $this->class->all(['*'], ['stream', 'medium', 'shift']);
$subjects = $this->subject->builder()->orderBy('id', 'DESC')->get();
$mediums = $this->mediums->builder()->pluck('name', 'id');
return response(view('exams.view_marks', compact('classes', 'subjects', 'mediums')));
}
public function viewMarksShow()
{
ResponseService::noFeatureThenRedirect('Exam Management');
$offset = request('offset', 0);
$limit = request('limit', 10);
$sort = request('sort', 'id');
$order = request('order', 'DESC');
$search = request('search');
$medium_id = request('medium_id');
$schoolSettings = $this->cache->getSchoolSettings();
$sessionYearId = $this->cache->getSessionYear()->id;
$sql = $this->exam->builder()->with([
'class.medium',
'class.stream',
'class.shift',
'timetable.class_subject' => function ($q) {
$q->withTrashed();
}
])
->with([
'timetable' => function ($q) {
$q->with('class_subject.subject')
->with([
'exam_marks' => function ($query) {
// $query->where('status', 1)
// ->with('user.student');
}
]);
}
])
->with([
'class.section' => function ($q) {
$q->whereNull('class_sections.deleted_at');
}
])
->where('session_year_id', $sessionYearId)
->when($search, function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query->where('id', 'LIKE', "%$search%")
->orWhere('name', 'LIKE', "%$search%")
->orWhere('description', 'LIKE', "%$search%")
->orWhere('created_at', 'LIKE', "%" . date('Y-m-d H:i:s', strtotime($search)) . "%")
->orWhere('updated_at', 'LIKE', "%" . date('Y-m-d H:i:s', strtotime($search)) . "%")
->orWhereHas('session_year', function ($subQuery) use ($search) {
$subQuery->where('name', 'LIKE', "%$search%");
});
});
})->when($medium_id, function ($query) use ($medium_id) {
$query->whereHas('class', function ($q) use ($medium_id) {
$q->where('medium_id', $medium_id);
});
})
->when(!empty($showDeleted), function ($query) {
$query->onlyTrashed();
});
$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 = [];
$bulkData['total'] = $total;
$rows = [];
$no = 1;
$classSections = $this->classSection->builder()->get()->toArray();
foreach ($res as $row) {
$tempRow = $row->toArray();
$tempRow['no'] = $no++;
$classSectionWiseStatus = [];
$sections = count($row->class->section ?? []) > 0 ? $row->class->section : [null];
foreach ($sections as $section) {
$sectionId = $section?->id;
$subjectWiseStatus = [];
$processedSubjects = [];
$classstreamname = ($classstreamname = $row->class?->stream?->name) ? ' (' . $classstreamname . ')' : ' ';
$classshiftname = ($classshiftname = $row->class?->shift?->name) ? ' (' . $classshiftname . ')' : '';
$classNameWithSection = $row->class->name . ' - ' . ($section?->name ?? '') . ' ' . ($row->class->medium->name ?? '') . $classstreamname . $classshiftname;
// Get the class section ID for this section
$class_section_id = $this->findClassSection($classSections, $row->class_id, $sectionId);
if ($row->has_timetable) {
foreach ($row->timetable as $timetable) {
$subject = $timetable->subject_with_name;
$subjectId = $timetable->class_subject_id;
if (isset($processedSubjects[$subjectId])) {
continue;
}
// Filter marks by class section ID instead of section ID directly
$marks = collect([]);
if ($class_section_id) {
$marks = $timetable->exam_marks->where('user.student.class_section_id', $class_section_id);
}
$marksSubmitted = $marks->isNotEmpty();
$status = $marksSubmitted ? 'Submitted' : 'Pending';
$subjectWiseStatus[] = [
'subject_id' => $subjectId,
'subject' => $subject,
'status' => $status,
'marks_count' => $marksSubmitted ? $marks->count() : 0,
];
$processedSubjects[$subjectId] = true;
}
$classSectionWiseStatus[] = [
'class_section_name' => $classNameWithSection,
'subject_wise_status' => $subjectWiseStatus,
];
}
}
$tempRow['classSectionWiseStatus'] = $classSectionWiseStatus;
$tempRow['created_at'] = date($schoolSettings['date_format'], strtotime($row->created_at));
$tempRow['updated_at'] = date($schoolSettings['date_format'], strtotime($row->updated_at));
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
return response()->json($bulkData);
}
public function findClassSection($classSections, $class_id, $sectionId)
{
foreach ($classSections as $classSection) {
if ($classSection['class_id'] == $class_id && $classSection['section_id'] == $sectionId) {
return $classSection['id'];
}
}
}
public function getExamByClassId($class_section_id)
{
ResponseService::noFeatureThenRedirect('Exam Management');
try {
$sessionYear = $this->cache->getSessionYear();
$class_id = ClassSection::where('id', $class_section_id)->value('class_id');
$exams = $this->exam->builder()->where(['class_id' => $class_id, 'session_year_id' => $sessionYear->id])->with([
'timetable' => function ($query) {
$query->where('date', '<', date('Y-m-d'))->orWhere(function ($q) {
$q->whereDate('date', '=', date('Y-m-d'))->where('end_time', '<=', date('H:i:s'));
});
}
])->where('publish', 0)->get();
ResponseService::successResponse('Data Fetched Successfully', $exams);
} catch (Throwable $e) {
ResponseService::logErrorResponse($e);
ResponseService::errorResponse();
}
}
}