This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Models\StaffModel;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Database\BaseConnection;
|
||||
|
||||
final class StaffDirectorySyncService
|
||||
{
|
||||
private const WORK_EMAIL_DOMAIN = '@alrahmaisgl.org';
|
||||
|
||||
public function __construct(
|
||||
private readonly StaffModel $staffModel,
|
||||
private readonly UserModel $userModel,
|
||||
private readonly ConfigurationModel $configurationModel,
|
||||
private readonly BaseConnection $db,
|
||||
) {
|
||||
}
|
||||
|
||||
public function syncAll(): void
|
||||
{
|
||||
$rows = $this->db->table('users')
|
||||
->select('id')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$userId = (int) ($row['id'] ?? 0);
|
||||
if ($userId > 0) {
|
||||
$this->syncUser($userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function syncUser(int $userId): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->userModel->find($userId);
|
||||
if (! $user) {
|
||||
return;
|
||||
}
|
||||
|
||||
$roles = $this->rolesForUser($userId);
|
||||
$staffRoles = array_values(array_filter($roles, static function (array $role): bool {
|
||||
return strtolower((string) ($role['name'] ?? '')) !== 'parent';
|
||||
}));
|
||||
|
||||
$now = utc_now();
|
||||
$schoolYear = (string) ($this->configurationModel->getConfig('school_year') ?? '');
|
||||
$roleNames = array_values(array_unique(array_map(
|
||||
static fn (array $role): string => strtolower((string) ($role['name'] ?? '')),
|
||||
$roles
|
||||
)));
|
||||
|
||||
$activeRole = ! empty($staffRoles)
|
||||
? strtolower((string) ($staffRoles[0]['name'] ?? ''))
|
||||
: 'inactive';
|
||||
|
||||
$this->staffModel->upsert([
|
||||
'user_id' => $userId,
|
||||
'firstname' => (string) ($user['firstname'] ?? ''),
|
||||
'lastname' => (string) ($user['lastname'] ?? ''),
|
||||
'email' => $this->generateUniqueStaffEmail(
|
||||
(string) ($user['firstname'] ?? ''),
|
||||
(string) ($user['lastname'] ?? ''),
|
||||
$userId
|
||||
),
|
||||
'phone' => (string) ($user['cellphone'] ?? ''),
|
||||
'role_name' => implode(', ', $roleNames),
|
||||
'active_role' => $activeRole,
|
||||
'school_year' => $schoolYear,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
public function activeStaffForSchoolYear(string $schoolYear): array
|
||||
{
|
||||
$this->syncAll();
|
||||
|
||||
$staffRows = $this->db->table('users u')
|
||||
->select([
|
||||
'u.id AS user_id',
|
||||
'u.school_id',
|
||||
'u.firstname',
|
||||
'u.lastname',
|
||||
'u.email AS personal_email',
|
||||
'u.cellphone',
|
||||
's.id AS staff_id',
|
||||
's.email AS work_email',
|
||||
's.active_role',
|
||||
's.role_name',
|
||||
"GROUP_CONCAT(DISTINCT r.name ORDER BY COALESCE(r.priority, 999), r.name SEPARATOR ', ') AS roles",
|
||||
])
|
||||
->join('user_roles ur', 'ur.user_id = u.id', 'inner')
|
||||
->join('roles r', 'r.id = ur.role_id', 'inner')
|
||||
->join('staff s', 's.user_id = u.id', 'left')
|
||||
->where("LOWER(r.name) != 'parent'", null, false)
|
||||
->where('COALESCE(r.is_active, 1) = 1', null, false);
|
||||
|
||||
if ($this->hasField('user_roles', 'deleted_at')) {
|
||||
$staffRows->where('ur.deleted_at', null);
|
||||
}
|
||||
|
||||
$rows = $staffRows
|
||||
->groupBy('u.id, u.school_id, u.firstname, u.lastname, u.email, u.cellphone, s.id, s.email, s.active_role, s.role_name')
|
||||
->orderBy('u.lastname', 'ASC')
|
||||
->orderBy('u.firstname', 'ASC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$assignments = $this->assignmentsByTeacher($schoolYear);
|
||||
$issuesCount = 0;
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
$userId = (int) ($row['user_id'] ?? 0);
|
||||
$activeRole = strtolower((string) ($row['active_role'] ?? ''));
|
||||
$roleText = strtolower((string) ($row['roles'] ?? ''));
|
||||
$isTeacher = in_array($activeRole, ['teacher', 'teacher_assistant'], true)
|
||||
|| str_contains($roleText, 'teacher')
|
||||
|| preg_match('/(^|, )ta($|,)/', $roleText);
|
||||
|
||||
$labels = $assignments[$userId] ?? [];
|
||||
if ($isTeacher) {
|
||||
if ($labels !== []) {
|
||||
$row['class_section'] = implode(', ', array_unique($labels));
|
||||
$row['verification_issue'] = false;
|
||||
} else {
|
||||
$row['class_section'] = 'No class assigned';
|
||||
$row['verification_issue'] = true;
|
||||
$issuesCount++;
|
||||
}
|
||||
} else {
|
||||
$row['class_section'] = '-';
|
||||
$row['verification_issue'] = false;
|
||||
}
|
||||
}
|
||||
unset($row);
|
||||
|
||||
return [
|
||||
'staff' => $rows,
|
||||
'issues_count' => $issuesCount,
|
||||
];
|
||||
}
|
||||
|
||||
private function rolesForUser(int $userId): array
|
||||
{
|
||||
$builder = $this->db->table('user_roles ur')
|
||||
->select('r.name, r.priority')
|
||||
->join('roles r', 'r.id = ur.role_id', 'inner')
|
||||
->where('ur.user_id', $userId)
|
||||
->where('COALESCE(r.is_active, 1) = 1', null, false)
|
||||
->orderBy('COALESCE(r.priority, 999)', 'ASC', false)
|
||||
->orderBy('r.name', 'ASC');
|
||||
|
||||
if ($this->hasField('user_roles', 'deleted_at')) {
|
||||
$builder->where('ur.deleted_at', null);
|
||||
}
|
||||
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
|
||||
private function assignmentsByTeacher(string $schoolYear): array
|
||||
{
|
||||
if ($schoolYear === '' || ! $this->db->tableExists('teacher_class')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = $this->db->table('teacher_class tc')
|
||||
->select('tc.teacher_id, tc.position, cs.class_section_name')
|
||||
->join('classSection cs', 'cs.class_section_id = tc.class_section_id', 'left')
|
||||
->where('tc.school_year', $schoolYear)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$assignments = [];
|
||||
foreach ($rows as $row) {
|
||||
$teacherId = (int) ($row['teacher_id'] ?? 0);
|
||||
$name = trim((string) ($row['class_section_name'] ?? ''));
|
||||
$position = strtolower((string) ($row['position'] ?? ''));
|
||||
|
||||
if ($teacherId <= 0 || $name === '' || ! in_array($position, ['main', 'ta'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$assignments[$teacherId][] = $name . ' (' . $position . ')';
|
||||
}
|
||||
|
||||
return $assignments;
|
||||
}
|
||||
|
||||
private function generateUniqueStaffEmail(string $firstname, string $lastname, int $userId): string
|
||||
{
|
||||
$first = strtolower((string) preg_replace('/[^a-z]/i', '', $firstname));
|
||||
$last = strtolower((string) preg_replace('/[^a-z]/i', '', $lastname));
|
||||
|
||||
if ($last === '') {
|
||||
$last = 'user' . $userId;
|
||||
}
|
||||
|
||||
$base = $last;
|
||||
$max = max(1, strlen($first));
|
||||
for ($i = 1; $i <= $max; $i++) {
|
||||
$base = substr($first, 0, $i) . $last;
|
||||
$email = $base . self::WORK_EMAIL_DOMAIN;
|
||||
|
||||
$exists = $this->staffModel
|
||||
->where('email', $email)
|
||||
->where('user_id !=', $userId)
|
||||
->first();
|
||||
|
||||
if (! $exists) {
|
||||
return $email;
|
||||
}
|
||||
}
|
||||
|
||||
return $base . $userId . self::WORK_EMAIL_DOMAIN;
|
||||
}
|
||||
|
||||
private function hasField(string $table, string $field): bool
|
||||
{
|
||||
try {
|
||||
return $this->db->tableExists($table) && $this->db->fieldExists($field, $table);
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user