121 lines
4.1 KiB
PHP
121 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use CodeIgniter\Database\BaseConnection;
|
|
|
|
/**
|
|
* Keeps the normalized family record aligned with its primary parent and
|
|
* every current student owned by that parent.
|
|
*/
|
|
final class FamilyDataSyncService
|
|
{
|
|
public function __construct(private readonly BaseConnection $db)
|
|
{
|
|
}
|
|
|
|
public function syncForParent(int $parentId): ?int
|
|
{
|
|
if ($parentId <= 0) {
|
|
return null;
|
|
}
|
|
|
|
foreach (['users', 'students', 'families', 'family_guardians', 'family_students'] as $table) {
|
|
if (! $this->db->tableExists($table)) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
$parent = $this->db->table('users')
|
|
->select('id, firstname, lastname, cellphone, address_street, apt, city, state, zip')
|
|
->where('id', $parentId)
|
|
->get()
|
|
->getRowArray();
|
|
if (! $parent) {
|
|
return null;
|
|
}
|
|
|
|
$familyCode = 'FAM-' . $parentId;
|
|
$family = $this->db->table('families')
|
|
->select('id')
|
|
->where('family_code', $familyCode)
|
|
->get()
|
|
->getRowArray();
|
|
|
|
if (! $family) {
|
|
$family = $this->db->table('family_guardians fg')
|
|
->select('fg.family_id AS id')
|
|
->join('families f', 'f.id = fg.family_id', 'inner')
|
|
->where('fg.user_id', $parentId)
|
|
->orderBy('fg.is_primary', 'DESC')
|
|
->orderBy('fg.id', 'ASC')
|
|
->get(1)
|
|
->getRowArray();
|
|
}
|
|
|
|
$familyData = $this->familyData($parent);
|
|
if (! $family) {
|
|
$this->db->table('families')->insert(['family_code' => $familyCode] + $familyData);
|
|
$familyId = (int) $this->db->insertID();
|
|
} else {
|
|
$familyId = (int) ($family['id'] ?? 0);
|
|
if ($familyId > 0) {
|
|
$this->db->table('families')->where('id', $familyId)->update($familyData);
|
|
}
|
|
}
|
|
|
|
if ($familyId <= 0) {
|
|
throw new \RuntimeException('Family data could not be synchronized for parent ID ' . $parentId . '.');
|
|
}
|
|
|
|
$this->db->query(
|
|
'INSERT IGNORE INTO family_guardians (family_id, user_id, relation, is_primary, receive_emails, receive_sms) VALUES (?, ?, ?, 1, 1, 0)',
|
|
[$familyId, $parentId, 'primary']
|
|
);
|
|
|
|
$students = $this->db->table('students')
|
|
->select('id')
|
|
->where('parent_id', $parentId)
|
|
->get()
|
|
->getResultArray();
|
|
foreach ($students as $student) {
|
|
$studentId = (int) ($student['id'] ?? 0);
|
|
if ($studentId > 0) {
|
|
$this->db->query(
|
|
'INSERT IGNORE INTO family_students (family_id, student_id, is_primary_home) VALUES (?, ?, 1)',
|
|
[$familyId, $studentId]
|
|
);
|
|
}
|
|
}
|
|
|
|
// Normally handled by the foreign key cascade; this also heals older
|
|
// databases where that constraint was absent.
|
|
$this->db->query(
|
|
'DELETE fs FROM family_students fs LEFT JOIN students s ON s.id = fs.student_id WHERE fs.family_id = ? AND s.id IS NULL',
|
|
[$familyId]
|
|
);
|
|
|
|
return $familyId;
|
|
}
|
|
|
|
private function familyData(array $parent): array
|
|
{
|
|
$parentName = trim((string) ($parent['firstname'] ?? '') . ' ' . (string) ($parent['lastname'] ?? ''));
|
|
$data = [
|
|
'household_name' => $parentName !== '' ? 'Family of ' . $parentName : 'Family of User ' . (int) $parent['id'],
|
|
'address_line1' => trim((string) ($parent['address_street'] ?? '')),
|
|
'address_line2' => trim((string) ($parent['apt'] ?? '')),
|
|
'city' => trim((string) ($parent['city'] ?? '')),
|
|
'state' => trim((string) ($parent['state'] ?? '')),
|
|
'postal_code' => trim((string) ($parent['zip'] ?? '')),
|
|
'primary_phone' => trim((string) ($parent['cellphone'] ?? '')),
|
|
'is_active' => 1,
|
|
];
|
|
if ($this->db->fieldExists('updated_at', 'families')) {
|
|
$data['updated_at'] = utc_now();
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
}
|