current_user_serial = $_SESSION[self::USER_SERIAL] ?? 0; $this->current_user_id = $_SESSION[self::USER_ID] ?? ""; $this->current_user_name = $_SESSION[self::USER_NAME] ?? ""; $this->current_user_email = $_SESSION[self::USER_EMAIL] ?? ""; $this->pagination_page = $_SESSION[self::PAGINATION_PAGE] ?? 1; } // ============= // Manage Voters // ============= public function manageVoters() { $voters = $this->getVotersPage(); $popovers = (new Popovers())->getPopovers(); $XML = $this->mergeXML($voters, ""); $XML = $this->mergeXML($popovers, $XML); // echo $XML; // die(); $content = $this->applyXSL($XML, $this->getXSL("manageVoters")); $this->displayContent($content); } // ============= // Voter Summary // ============= public function voterSummary() { $voter_serial = filter_input(INPUT_POST, "voter_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0; $voter = $this->getVoter($voter_serial); if ($voter->count() == 0) { $this->logError("Invalid Voter ({$voter_serial}). " . __METHOD__); } $XML = $this->mergeXML($voter, ""); $content = $this->applyXSL($XML, $this->getXSL("voterSummary")); $this->displayContent($content); } // ========= // Add Voter // ========= public function addVoter() { $step = filter_input(INPUT_POST, "step") ?: "prompt"; switch ($step) { case "prompt": $content = $this->applyXSL("", $this->getXSL("addVoter")); $this->displayContent($content); break; case "add": $voter_name = filter_input(INPUT_POST, "voter_name") ?: ""; $voter_classes = filter_input(INPUT_POST, "voter_classes") ?: ""; $voter_active = filter_input(INPUT_POST, "voter_active", FILTER_VALIDATE_BOOLEAN) ?: false; $SQL = "insert into voters ( voter_name, voter_classes, voter_active, voter_creator, voter_created ) VALUES ( :voter_name, :voter_classes, :voter_active, :voter_creator, :voter_created )"; $statement = $this->connect()->prepare($SQL); $statement->bindValue(":voter_name", $voter_name); $statement->bindValue(":voter_classes", $voter_classes); $statement->bindValue(":voter_active", $voter_active, PDO::PARAM_BOOL); $statement->bindValue(":voter_creator", $this->current_user_name); $statement->bindValue(":voter_created", $this->getTimestamp()); $statement->execute(); break; default: $this->displayHome(); } } // ============= // Delete Voter // ============= public function deleteVoter() { $voter_serial = filter_input(INPUT_POST, "voter_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0; $voter = $this->getVoter($voter_serial); if ($voter->count() == 0) { $this->logError("Invalid Voter ({$voter_serial}). " . __METHOD__); } $SQL = "delete from voters where voter_serial = {$voter_serial}"; $this->executeSQL($SQL); } // ============================ // Determine if a Voter exists // ============================ public function voterExists() { $voter_serial = filter_input(INPUT_POST, "voter_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0; $voter_name = filter_input(INPUT_POST, "voter_name") ?: ""; $SQL = "select voter_serial from view_voters where voter_serial != :voter_serial and lower(voter_name) = :voter_name"; $statement = $this->connect()->prepare($SQL); $statement->bindValue(":voter_serial", $voter_serial); $statement->bindValue(":voter_name", strtolower($voter_name)); $statement->execute(); $recordset = $statement->fetchAll(PDO::FETCH_ASSOC); $exists = (count($recordset) > 0) ? true : false; echo json_encode($exists); } // ====================================== // Determine if a Voter is Active (AJAX) // ====================================== public function voterActive() { $voter_serial = filter_input(INPUT_POST, "voter_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0; $active = false; $SQL = "select workorder_voter from workorders where workorder_voter = {$voter_serial} limit 1"; $workorders = $this->getTable("workorders", $SQL); $active = ($workorders->count() > 0) ? true : false; echo json_encode($active); } // ============= // Edit a Voter // ============= public function editVoter() { $step = filter_input(INPUT_POST, "step") ?: "prompt"; switch ($step) { case "prompt": $voter_serial = filter_input(INPUT_POST, "voter_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0; $voter = $this->getVoter($voter_serial); if ($voter->count() == 0) { $this->logError("Invalid Voter ({$voter_serial}). " . __METHOD__); } $XML = $this->mergeXML($voter, ""); $content = $this->applyXSL($XML, $this->getXSL("editVoter")); $this->displayContent($content); break; case "update": $voter_serial = filter_input(INPUT_POST, "voter_serial", FILTER_SANITIZE_NUMBER_INT) ?: 0; $voter_name = filter_input(INPUT_POST, "voter_name") ?: ""; $voter_classes = filter_input(INPUT_POST, "voter_classes") ?: ""; $voter_active = filter_input(INPUT_POST, "voter_active", FILTER_VALIDATE_BOOLEAN) ?: false; $voter_default = filter_input(INPUT_POST, "voter_default", FILTER_VALIDATE_BOOLEAN) ?: false; // Verify the Voter $voter = $this->getVoter($voter_serial); if ($voter->count() == 0) { $this->logError("Invalid Voter ({$voter_serial}). " . __METHOD__); } $SQL = "update voters set voter_name = :voter_name, voter_classes = :voter_classes, voter_active = :voter_active, voter_default = :voter_default, voter_changer = :voter_changer, voter_changed = :voter_changed where voter_serial = :voter_serial"; $statement = $this->connect()->prepare($SQL); $statement->bindValue(":voter_serial", $voter_serial); $statement->bindValue(":voter_name", $voter_name); $statement->bindValue(":voter_classes", $voter_classes); $statement->bindValue(":voter_active", $voter_active, PDO::PARAM_BOOL); $statement->bindValue(":voter_default", $voter_default, PDO::PARAM_BOOL); $statement->bindValue(":voter_changer", $this->current_user_name); $statement->bindValue(":voter_changed", $this->getTimestamp()); $statement->execute(); break; default: $this->displayHome(); } } // ================================ // Return an Active Voters Object // ================================ public function getActiveVoters() { $SQL = "select view_voters.* from view_voters where voter_active is true"; return $this->getTable("voters", $SQL); } // ------------------------- // Return the Default Voter // ------------------------- public function getDefaultVoter() { $SQL = "select voter_serial from view_voters where voter_default is true"; return $this->getTable("voters", $SQL); } // ======================= // Return an Voter Object // ======================= public function getVoter($voter_serial = 0) { $SQL = "select view_voters.* from view_voters where voter_serial = {$voter_serial}"; return $this->getTable("voters", $SQL); } // =========================== // Return a Voters Object // =========================== public function getVoters() { $SQL = "select view_voters.* from view_voters"; return $this->getTable("voters", $SQL); } // ============================ // Return a Voters Page Object // ============================ public function getVotersPage() { // Find Criteria $find_voter = filter_input(INPUT_POST, "find_voter") ?: ""; $find_voter = trim($this->sanitizeString($find_voter)); $connection = $this->connect(); // ========== // Pagination // ========== $pagination = filter_input(INPUT_POST, "pagination") ?: ""; $count = 0; /* * Blank admin load: * - keep the count * * Search: * - skip the full count because it is too expensive */ if ($find_voter === "") { $SQL = "select count(*) as count from voters"; $statement = $connection->prepare($SQL); $statement->execute(); $recordset = $statement->fetch(PDO::FETCH_ASSOC); $count = $recordset ? (int) $recordset["count"] : 0; $max_page = max((int) ceil($count / $this->pagination_size), 1); } else { // For searches, do not run an expensive count query $max_page = max((int) $this->pagination_page, 1); } switch ($pagination) { case "first": $this->pagination_page = 1; break; case "previous": $this->pagination_page = max(($this->pagination_page - 1), 1); break; case "next": $this->pagination_page = ($this->pagination_page + 1); break; case "last": $this->pagination_page = $max_page; break; default: $this->pagination_page = max((int) $this->pagination_page, 1); break; } $offset = (($this->pagination_page - 1) * $this->pagination_size); // ========== // Data Query // ========== if ($find_voter === "") { /* * Blank load: * - page voters first * - then join the tiny lookup tables to only those page rows */ $SQL = "select v.voter_serial, v.voter_id, v.voter_name_first, v.voter_name_last, v.voter_residence_address_1, v.voter_residence_city, v.voter_residence_state, v.voter_residence_zipcode, v.voter_gender, racecodes.racecode_description as voter_race_code_verbose, politicalparties.politicalparty_name as voter_party_affiliation_verbose from ( select voter_serial, voter_id, voter_name_first, voter_name_last, voter_residence_address_1, voter_residence_city, voter_residence_state, voter_residence_zipcode, voter_gender, voter_race, voter_party_affiliation from voters order by voter_serial limit :limit offset :offset ) v left join racecodes on racecodes.racecode_code = v.voter_race left join politicalparties on politicalparties.politicalparty_code = v.voter_party_affiliation order by v.voter_serial"; $statement = $connection->prepare($SQL); $statement->bindValue(":limit", (int) ($this->pagination_size + 1), PDO::PARAM_INT); $statement->bindValue(":offset", (int) $offset, PDO::PARAM_INT); } else { /* * Search: * - use UNION so each branch can use its own index * - then join back to voters * - then join lookup tables */ $SQL = "select v.voter_serial, v.voter_id, v.voter_name_first, v.voter_name_last, v.voter_residence_address_1, v.voter_residence_city, v.voter_residence_state, v.voter_residence_zipcode, v.voter_gender, racecodes.racecode_description as voter_race_code_verbose, politicalparties.politicalparty_name as voter_party_affiliation_verbose from ( select matches.voter_serial, voters.voter_id, voters.voter_name_first, voters.voter_name_last, voters.voter_residence_address_1, voters.voter_residence_city, voters.voter_residence_state, voters.voter_residence_zipcode, voters.voter_gender, voters.voter_race, voters.voter_party_affiliation from ( select voter_serial from voters where voter_name_first like :find_words_first union select voter_serial from voters where voter_name_last like :find_words_last union select voter_serial from voters where voter_id like :find_words_id ) matches join voters on voters.voter_serial = matches.voter_serial order by voters.voter_name_last, voters.voter_name_first, voters.voter_serial limit :limit offset :offset ) v left join racecodes on racecodes.racecode_code = v.voter_race left join politicalparties on politicalparties.politicalparty_code = v.voter_party_affiliation order by v.voter_name_last, v.voter_name_first, v.voter_serial"; $statement = $connection->prepare($SQL); $statement->bindValue(":find_words_first", $find_voter . "%", PDO::PARAM_STR); $statement->bindValue(":find_words_last", $find_voter . "%", PDO::PARAM_STR); $statement->bindValue(":find_words_id", $find_voter . "%", PDO::PARAM_STR); $statement->bindValue(":limit", (int) $this->pagination_size, PDO::PARAM_INT); $statement->bindValue(":offset", (int) $offset, PDO::PARAM_INT); } $statement->execute(); $voters = $this->getTableXML("voters", $statement); // ============================ // Insert Pagination Attributes // ============================ if ($find_voter === "") { $start = $count > 0 ? ($offset + 1) : 0; $end = min($count, ($offset + $this->pagination_size)); } else { /* * Search total count is intentionally skipped. * We only know what is on the current page. */ $rows_on_page = $statement->rowCount(); $count = 0; $start = $rows_on_page > 0 ? ($offset + 1) : 0; $end = $offset + $rows_on_page; } $voters->addAttribute("count", $count); $voters->addAttribute("start", $start); $voters->addAttribute("end", $end); $voters->addAttribute("page", $this->pagination_page); $_SESSION[self::PAGINATION_PAGE] = $this->pagination_page; return $voters; } } ?>