Files
alrahma_sunday_school_api/app/Http/Controllers/Api/StaffController.php
T
2026-03-05 12:29:37 -05:00

245 lines
9.3 KiB
PHP
Executable File

<?php
namespace App\Http\Controllers\Api;
use App\Models\Configuration;
use App\Models\Staff;
use App\Models\TeacherClass;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Response;
class StaffController extends BaseApiController
{
protected Staff $staff;
protected User $user;
protected TeacherClass $teacherClass;
protected Configuration $config;
protected string $schoolYear;
protected string $semester;
public function __construct()
{
parent::__construct();
$this->staff = model(Staff::class);
$this->user = model(User::class);
$this->teacherClass = model(TeacherClass::class);
$this->config = model(Configuration::class);
$this->schoolYear = (string) ($this->config->getConfig('school_year') ?? '');
$this->semester = (string) ($this->config->getConfig('semester') ?? '');
}
public function index()
{
$page = max(1, (int) ($this->request->getGet('page') ?? 1));
$perPage = min(100, max(1, (int) ($this->request->getGet('per_page') ?? 20)));
$role = $this->request->getGet('role');
// Roles we never show
$excludedRoles = ['student', 'parent', 'guest', 'inactive'];
$normalizedExcluded = array_map('strtolower', $excludedRoles);
$placeholders = implode(',', array_fill(0, count($normalizedExcluded), '?'));
$query = $this->staff->newQuery()
->whereRaw('LOWER(active_role) NOT IN (' . $placeholders . ')', $normalizedExcluded);
if (!empty($role)) {
$query->whereRaw('LOWER(active_role) = ?', [strtolower((string) $role)]);
}
$query->orderByDesc('created_at');
// Preload assignments for the selected school year (across all semesters)
$assignRows = DB::table('teacher_class as tc')
->select('tc.teacher_id', 'tc.position', 'cs.class_section_name')
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'tc.class_section_id')
->where('tc.school_year', (string) $this->schoolYear)
->get()
->toArray();
$assignByTeacher = [];
foreach ($assignRows as $row) {
$teacherId = (int) ($row->teacher_id ?? 0);
if ($teacherId <= 0) {
continue;
}
$section = trim((string) ($row->class_section_name ?? ''));
if ($section === '') {
continue;
}
$position = strtolower((string) ($row->position ?? ''));
if (!in_array($position, ['main', 'ta'], true)) {
continue;
}
$assignByTeacher[$teacherId][] = $section . ' (' . $position . ')';
}
// Get all staff (not paginated) for issues count calculation
$allStaff = $query->get()->toArray();
$issuesCount = 0;
foreach ($allStaff as $staff) {
$roleName = strtolower((string) ($staff['active_role'] ?? ''));
if (in_array($roleName, ['teacher', 'teacher_assistant'], true)) {
$userId = (int) ($staff['user_id'] ?? 0);
$labels = $assignByTeacher[$userId] ?? [];
if (empty($labels)) {
$issuesCount++;
}
}
}
// Paginate the results
$result = $this->paginate($query, $page, $perPage);
// Apply transformations to paginated data
foreach ($result['data'] as &$staff) {
$userId = (int) ($staff['user_id'] ?? 0);
$staff['school_id'] = $userId > 0 ? $this->user->getSchoolIdByUserId($userId) : null;
$roleName = strtolower((string) ($staff['active_role'] ?? ''));
if (in_array($roleName, ['teacher', 'teacher_assistant'], true)) {
$labels = $assignByTeacher[$userId] ?? [];
if (!empty($labels)) {
$staff['class_section'] = implode(', ', array_unique($labels));
$staff['verification_issue'] = false;
} else {
$staff['class_section'] = 'No class assigned';
$staff['verification_issue'] = true;
}
} else {
$staff['class_section'] = '—';
$staff['verification_issue'] = false;
}
}
return $this->success([
'data' => $result['data'],
'pagination' => $result['pagination'],
'issues_count' => $issuesCount,
'semester' => $this->semester,
'school_year' => $this->schoolYear,
], 'Staff members retrieved successfully');
}
public function show($id = null)
{
$staff = $this->staff->find($id);
if (!$staff) {
return $this->respondError('Staff member not found', Response::HTTP_NOT_FOUND);
}
$staff['school_id'] = $this->user->getSchoolIdByUserId((int) ($staff['user_id'] ?? 0));
return $this->success($staff, 'Staff member retrieved successfully');
}
public function store()
{
$data = $this->payloadData();
if (empty($data)) {
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
}
$now = utc_now();
$payload = [
'firstname' => trim((string) ($data['firstname'] ?? '')),
'lastname' => trim((string) ($data['lastname'] ?? '')),
'email' => trim((string) ($data['email'] ?? '')),
'phone' => trim((string) ($data['phone'] ?? '')),
'role_name' => trim((string) ($data['role_name'] ?? '')),
'school_year' => trim((string) ($data['school_year'] ?? $this->schoolYear)),
'status' => trim((string) ($data['status'] ?? 'Active')),
'created_at' => $now,
'updated_at' => $now,
];
// Set active_role from role_name if provided
if (!empty($payload['role_name'])) {
$payload['active_role'] = strtolower($payload['role_name']);
}
try {
$inserted = $this->staff->insert($payload);
if (!$inserted) {
return $this->respondError('Failed to create staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Fetch the created record
$staff = $this->staff->where('created_at', $now)->orderBy('id', 'DESC')->first();
return $this->success($staff, 'Staff member added successfully', Response::HTTP_CREATED);
} catch (\Throwable $e) {
\Illuminate\Support\Facades\Log::error('Staff creation error: ' . $e->getMessage());
return $this->respondError('Failed to create staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
public function update($id = null)
{
$staff = $this->staff->find($id);
if (!$staff) {
return $this->respondError('Staff member not found', Response::HTTP_NOT_FOUND);
}
$data = $this->payloadData();
if (empty($data)) {
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
}
// Only update fields provided by the request to avoid wiping data
$updateData = [];
$allowedFields = ['firstname', 'lastname', 'email', 'phone', 'role_name', 'school_year', 'status'];
foreach ($allowedFields as $field) {
if (array_key_exists($field, $data)) {
$value = $data[$field];
if ($value !== null && $value !== '') {
$updateData[$field] = trim((string) $value);
}
}
}
// Set active_role from role_name if role_name is being updated
if (isset($updateData['role_name']) && !empty($updateData['role_name'])) {
$updateData['active_role'] = strtolower($updateData['role_name']);
}
// Always bump updated_at
$updateData['updated_at'] = utc_now();
if (empty($updateData)) {
return $this->respondError('No changes detected', Response::HTTP_BAD_REQUEST);
}
try {
$updated = $this->staff->update($id, $updateData);
if (!$updated) {
return $this->respondError('Failed to update staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
}
$updatedStaff = $this->staff->find($id);
return $this->success($updatedStaff, 'Staff member updated successfully');
} catch (\Throwable $e) {
\Illuminate\Support\Facades\Log::error('Staff update error: ' . $e->getMessage());
return $this->respondError('Failed to update staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
public function destroy($id = null)
{
$staff = $this->staff->find($id);
if (!$staff) {
return $this->respondError('Staff member not found', Response::HTTP_NOT_FOUND);
}
try {
$this->staff->delete($id);
return $this->respondDeleted(null, 'Staff member deleted successfully');
} catch (\Throwable $e) {
\Illuminate\Support\Facades\Log::error('Staff deletion error: ' . $e->getMessage());
return $this->respondError('Failed to delete staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}