Files
votervue/classes/imports/Import_VoterHistory.php
2026-07-03 15:46:56 -04:00

226 lines
6.1 KiB
PHP

<?php
// ====================
// Import Voter History
// ====================
class Import_VoterHistory {
// Variables
private $log = "";
private $settings = "";
private $connection = "";
// ==================
// Class Constructor.
// ==================
public function __construct() {
// Open the Log
$this->log = fopen("../scripts/import_voter_history.log", "w+");
if ($this->log === false) {
error_log("VoterVue : Unable to open log file");
exit();
}
$this->log(str_repeat("*", 50));
// Get Settings
$this->settings = new SimpleXMLElement((file_exists("../xml/settings.xml") ? file_get_contents("../xml/settings.xml") : "<settings/>"));
if ($this->settings->count() === 0) {
error_log("VoterVue : Unable to initialize settings");
exit();
}
// Open Database Connections
$this->connection = $this->connect();
}
// ==============================================
// Return a VoterVue Database Database Connection
// ==============================================
public function connect() {
try {
$host = (string) $this->settings->DatabaseServer;
$database = (string) $this->settings->DatabaseName;
$user = (string) $this->settings->DatabaseUser;
$password = (string) $this->settings->DatabasePassword;
$connection = new PDO("mysql:host={$host};dbname={$database};charset=utf8", $user, $password);
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException | Exception $e) {
trigger_error($e->getMessage());
}
return $connection;
}
// =============================
// Log a message to the Log File
// =============================
private function log($message = "") {
fwrite($this->log, date("Y-m-d H:i A") . " : " . "{$message} \n");
}
// ===================
// Process Parcel Data
// ===================
public function process() {
$this->log("Starting Voter History Import Process");
$this->importVoterHistory();
$this->log("Voter History Import Process Completed");
}
// ====================
// Import Voter History
// ====================
private function importVoterHistory() {
$this->log("Processing Voter History Records");
$path = '/data/ositssrc/projects/votervue_raw_data/20251210_Voter_History_20251210';
$files = glob("{$path}/*.txt");
sort($files);
$SQL = "INSERT IGNORE INTO voterhistory
(
voterhistory_county_code,
voterhistory_voter_id,
voterhistory_election_date,
voterhistory_election_type,
voterhistory_history_code
)
VALUES ( ?, ?, ?, ?, ? )";
$statement = $this->connection->prepare($SQL);
$counter = 0;
$batchCounter = 0;
$batchSize = 50000;
foreach ($files as $file) {
$this->log("Importing history file: {$file}");
$fh = fopen($file, 'r');
if ($fh === false) {
$this->log("Unable to open {$file}");
continue;
}
$lineNum = 0;
try {
// Start transaction for this file
$this->connection->beginTransaction();
while (($line = fgets($fh)) !== false) {
$lineNum++;
$line = rtrim($line, "\r\n");
if ($line === '') {
continue;
}
$cols = explode("\t", $line);
if (count($cols) < 5) {
$this->log("Skipped malformed line {$lineNum} in {$file} (cols=" . count($cols) . ")");
continue;
}
[$county_code, $voter_id, $election_date, $election_type, $history_code] = $cols;
$statement->execute([
$this->normalize($county_code),
$this->normalize($voter_id),
$this->parseDate($election_date),
$this->normalize($election_type),
$this->normalize($history_code)
]);
$counter++;
$batchCounter++;
// Commit every batchSize rows
if ($batchCounter >= $batchSize) {
$this->connection->commit();
$this->connection->beginTransaction();
$batchCounter = 0;
$this->log("Processed {$counter} history records...");
}
}
// Final commit for this file
$this->connection->commit();
$batchCounter = 0;
} catch (Throwable $e) {
// Roll back any open transaction for this file
if ($this->connection->inTransaction()) {
$this->connection->rollBack();
}
$this->log("Insert failed {$file}:{$lineNum} - " . $e->getMessage());
}
fclose($fh);
}
$this->log("Completed voter history import. Total records processed: {$counter}");
}
// =================================
// Return a $this->normalized String
// =================================
private function normalize(?string $value): ?string {
$value = trim((string) $value);
return ($value === '' || $value === '*') ? null : $value;
}
// ====================
// Return a Parsed Date
// ====================
private function parseDate(?string $value): ?string {
$value = $this->normalize($value);
if ($value === null) {
return null;
}
$dt = DateTime::createFromFormat('m/d/Y', $value);
return $dt ? $dt->format('Y-m-d') : null;
}
}
?>