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; } }