Files

555 lines
22 KiB
PHP
Raw Permalink Normal View History

2026-05-29 14:52:16 -04:00
<?php
class BusinessFacts extends Base {
// Variables
private $current_user_serial = 0;
private $current_user_id = "";
private $current_user_name = "";
private $current_user_email = "";
private $pagination_size = 20;
private $pagination_page = 1;
// =================
// Class Constructor
// =================
public function __construct() {
set_error_handler(array($this, "displayError"));
date_default_timezone_set(self::TIMEZONE);
$this->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;
}
// =====================
// Search Business Facts
// =====================
public function searchBusinessFacts() {
$subscription_serial = $_SESSION['subscription_serial'];
$usersubscription_serial = $_SESSION['usersubscription_serial'];
$subscription = (new Subscriptions())->getSubscription($subscription_serial);
if ($subscription->count() === 0) {
$this->logError("Invalid Subscription ({$subscription_serial}): " . __METHOD__);
}
$userssubscription = (new Users())->getUserSubscription($usersubscription_serial);
$user_subscription_start_date = $userssubscription->record->usersubscription_start_date;
$user_subscription_end_date = $userssubscription->record->usersubscription_end_date;
$searchhistory = (new SearchHistory())->getUsersPreviousSearchParameters($this->current_user_serial, $subscription_serial);
// Update Search History Record
if (empty($searchhistory)) {
(new SearchHistory())->saveUserSearchParameters($_POST);
} else {
(new SearchHistory())->updateUserSearchParameters($_POST);
}
$businessfacts = $this->getBusinessFactsPage($user_subscription_start_date, $user_subscription_end_date,);
$searchhistory = (new SearchHistory())->getUsersPreviousSearchParameters($this->current_user_serial, $subscription_serial);
// Populate Entry Dates with what was searched for if provided or users entry dates if no entry dates were provided
$searchhistory->record->searchhistory_parameters->businessfact_entry_date_from = $businessfacts->record->businessfact_entry_date_from;
$searchhistory->record->searchhistory_parameters->businessfact_entry_date_to = $businessfacts->record->businessfact_entry_date_to;
$popovers = (new Popovers())->getPopovers();
$dropdowns = (new Dropdowns())->getDropdowns();
$siccodes = (new SICCodes())->getSICCodes();
$cities = (new Cities())->getSubscriptionCities($subscription_serial);
$counties = (new Counties())->getSubscriptionCounties($subscription_serial);
$availablerecordcount = $this->userTotalAvailableRecordCount($user_subscription_start_date, $user_subscription_end_date);
$XML = $this->mergeXML($businessfacts, "<XML/>");
$XML = $this->mergeXML($subscription, $XML);
$XML = $this->mergeXML($popovers, $XML);
$XML = $this->mergeXML($dropdowns, $XML);
$XML = $this->mergeXML($cities, $XML);
$XML = $this->mergeXML($counties, $XML);
$XML = $this->mergeXML($siccodes, $XML);
$XML = $this->mergeXML($searchhistory, $XML);
$XML = $this->mergeXML($availablerecordcount, $XML);
$content = $this->applyXSL($XML, $this->getXSL("searchBusinessFacts"));
$this->displayContent($content);
}
// ===================================
// Return a Business Facts Page Object
// ===================================
public function getBusinessFactsPage($user_subscription_start_date, $user_subscription_end_date) {
// Pagination settings
$pagination = filter_input(INPUT_POST, "pagination") ?: "";
$this->pagination_size = filter_input(INPUT_POST, "businessfacts_per_page", FILTER_SANITIZE_NUMBER_INT) ?: $this->pagination_size;
// Connect to DB
$connection = $this->connect();
$filters = $this->buildBusinessFactsFilters($user_subscription_start_date, $user_subscription_end_date);
// Record Count
$SQL = "select count(*) as count
from view_businessfacts
{$filters['where']}";
$statement = $connection->prepare($SQL);
$this->bindBusinessFactsParams($statement, $filters['params']);
$statement->execute();
$recordset = $statement->fetch(PDO::FETCH_ASSOC);
$count = $recordset ? (int) $recordset["count"] : 0;
// === PAGINATION LOGIC ===
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 = min($this->pagination_page + 1, ceil($count / $this->pagination_size));
break;
case "last": $this->pagination_page = (int) ceil($count / $this->pagination_size);
break;
}
$offset = max(0, ($this->pagination_page - 1) * $this->pagination_size);
$start = $offset + 1;
$end = min($count, $start + $this->pagination_size - 1);
// === DATA QUERY ===
$SQL = "select view_businessfacts.*
from view_businessfacts
{$filters['where']}";
if ($pagination !== 'off') {
$SQL .= " limit :limit
offset :offset";
}
// echo $SQL;
// die();
$statement = $connection->prepare($SQL);
$this->bindBusinessFactsParams($statement, $filters['params']);
if ($pagination !== 'off') {
$statement->bindValue(":limit", $this->pagination_size, PDO::PARAM_INT);
$statement->bindValue(":offset", $offset, PDO::PARAM_INT);
}
$statement->execute();
$businessfacts = $this->getTableXML("businessfacts", $statement);
// Add searched entry_dates for search history
$businessfacts->record->businessfact_entry_date_from = !empty($filters['entry_from']) ? date('m/d/Y', strtotime($filters['entry_from'])) : date('m/d/Y', strtotime($filters['subscription_start']));
$businessfacts->record->businessfact_entry_date_to = !empty($filters['entry_to']) ? date('m/d/Y', strtotime($filters['entry_to'])) : date('m/d/Y', strtotime($filters['subscription_end']));
// Insert Pagination Attributes
$businessfacts->addAttribute("count", $count);
$businessfacts->addAttribute("start", $start);
$businessfacts->addAttribute("end", $end);
$businessfacts->addAttribute("page", $this->pagination_page);
$_SESSION[self::PAGINATION_PAGE] = $this->pagination_page;
return $businessfacts;
}
private function buildBusinessFactsFilters($user_subscription_start_date, $user_subscription_end_date) {
$businessfact_company = trim((string) filter_input(INPUT_POST, "businessfact_company")) ?: "";
$businessfact_zip = trim((string) filter_input(INPUT_POST, "businessfact_zip")) ?: "";
$businessfact_home_based_business = trim((string) filter_input(INPUT_POST, "businessfact_home_based_business")) ?: "";
$businessfact_employee_count_from = trim((string) filter_input(INPUT_POST, "businessfact_employee_count_from")) ?: "";
$businessfact_employee_count_to = trim((string) filter_input(INPUT_POST, "businessfact_employee_count_to")) ?: "";
$businessfact_entry_date_from = trim((string) filter_input(INPUT_POST, "businessfact_entry_date_from")) ?: "";
$businessfact_entry_date_to = trim((string) filter_input(INPUT_POST, "businessfact_entry_date_to")) ?: "";
$businessfact_lease_end_from = trim((string) filter_input(INPUT_POST, "businessfact_lease_end_from")) ?: "";
$businessfact_lease_end_to = trim((string) filter_input(INPUT_POST, "businessfact_lease_end_to")) ?: "";
// Determine real date range based upon users subscription start date
$oneYearAgo = date('Y-m-d', strtotime('-1 year'));
if ($user_subscription_start_date <= $oneYearAgo) {
$user_subscription_start_date = $oneYearAgo;
}
if ($user_subscription_end_date < $user_subscription_start_date) {
$this->displayNotice("Your authorized access period is invalid (end date is before start date).");
return;
}
$entryFrom = $this->normalizeBusinessFactsDate($businessfact_entry_date_from);
$entryTo = $this->normalizeBusinessFactsDate($businessfact_entry_date_to);
$leaseEndFrom = $this->normalizeBusinessFactsDate($businessfact_lease_end_from);
$leaseEndTo = $this->normalizeBusinessFactsDate($businessfact_lease_end_to);
$clauses = [];
$params = [];
$clauses[] = "view_businessfacts.businessfact_entry_date BETWEEN :subscription_start AND :subscription_end";
$params[':subscription_start'] = $user_subscription_start_date;
$params[':subscription_end'] = $user_subscription_end_date;
$allowedCountyIds = $this->getBusinessFactsSubscriptionCountyIds();
$requestedCountyIds = $this->getBusinessFactsPostIds("businessfact_county");
$countyIds = $requestedCountyIds ? array_values(array_intersect($requestedCountyIds, $allowedCountyIds)) : $allowedCountyIds;
$this->addBusinessFactsInClause($clauses, $params, "view_businessfacts.businessfact_county", $countyIds, "county_");
if ($businessfact_company !== '') {
$clauses[] = "view_businessfacts.businessfact_company REGEXP :businessfact_company";
$params[':businessfact_company'] = $businessfact_company;
}
if ($businessfact_zip !== '') {
$clauses[] = "view_businessfacts.businessfact_zip REGEXP :businessfact_zip";
$params[':businessfact_zip'] = $businessfact_zip;
}
$this->addBusinessFactsInClause($clauses, $params, "view_businessfacts.businessfact_city", $this->getBusinessFactsPostIds("businessfact_city"), "city_");
$this->addBusinessFactsInClause($clauses, $params, "view_businessfacts.businessfact_business_class", $this->getBusinessFactsPostIds("businessfact_business_class"), "class_");
$this->addBusinessFactsInClause($clauses, $params, "view_businessfacts.businessfact_action", $this->getBusinessFactsPostIds("businessfact_action"), "action_");
$this->addBusinessFactsInClause($clauses, $params, "view_businessfacts.businessfact_sic_code", $this->getBusinessFactsPostValues("businessfact_sic_code"), "sic_");
if ($businessfact_home_based_business === 'Y' || $businessfact_home_based_business === 'N') {
$clauses[] = "view_businessfacts.businessfact_home_based_business = :businessfact_home_based_business";
$params[':businessfact_home_based_business'] = $businessfact_home_based_business;
}
if ($businessfact_employee_count_from !== '' && ctype_digit($businessfact_employee_count_from)) {
$businessfact_employee_count_from = (int) $businessfact_employee_count_from;
} else {
$businessfact_employee_count_from = null;
}
if ($businessfact_employee_count_to !== '' && ctype_digit($businessfact_employee_count_to)) {
$businessfact_employee_count_to = (int) $businessfact_employee_count_to;
} else {
$businessfact_employee_count_to = null;
}
if ($businessfact_employee_count_from !== null && $businessfact_employee_count_to !== null) {
if ($businessfact_employee_count_from > $businessfact_employee_count_to) {
$tmp = $businessfact_employee_count_from;
$businessfact_employee_count_from = $businessfact_employee_count_to;
$businessfact_employee_count_to = $tmp;
}
$clauses[] = "view_businessfacts.businessfact_employee_count BETWEEN :employee_count_from AND :employee_count_to";
$params[':employee_count_from'] = $businessfact_employee_count_from;
$params[':employee_count_to'] = $businessfact_employee_count_to;
} elseif ($businessfact_employee_count_from !== null) {
$clauses[] = "view_businessfacts.businessfact_employee_count = :employee_count";
$params[':employee_count'] = $businessfact_employee_count_from;
} elseif ($businessfact_employee_count_to !== null) {
$clauses[] = "view_businessfacts.businessfact_employee_count = :employee_count";
$params[':employee_count'] = $businessfact_employee_count_to;
}
if ($entryFrom !== null || $entryTo !== null) {
if ($entryFrom !== null && $entryTo === null) {
$entryTo = $entryFrom;
}
if ($entryTo !== null && $entryFrom === null) {
$entryFrom = $entryTo;
}
if ($entryFrom > $entryTo) {
$tmp = $entryFrom;
$entryFrom = $entryTo;
$entryTo = $tmp;
}
if ($entryFrom < $user_subscription_start_date || $entryTo > $user_subscription_end_date) {
$this->displayNotice("The Entry date or date range {$this->current_user_name} selected is outside your authorized access period.");
return;
}
$clauses[] = "view_businessfacts.businessfact_entry_date BETWEEN :entry_from AND :entry_to";
$params[':entry_from'] = $entryFrom;
$params[':entry_to'] = $entryTo;
}
if ((string) ($_SESSION['subscription_serial'] ?? '') === '10' && ($leaseEndFrom !== null || $leaseEndTo !== null)) {
if ($leaseEndFrom !== null && $leaseEndTo === null) {
$leaseEndTo = $leaseEndFrom;
}
if ($leaseEndTo !== null && $leaseEndFrom === null) {
$leaseEndFrom = $leaseEndTo;
}
if ($leaseEndFrom > $leaseEndTo) {
$tmp = $leaseEndFrom;
$leaseEndFrom = $leaseEndTo;
$leaseEndTo = $tmp;
}
$clauses[] = "view_businessfacts.businessfact_lease_end BETWEEN :lease_end_from AND :lease_end_to";
$params[':lease_end_from'] = $leaseEndFrom;
$params[':lease_end_to'] = $leaseEndTo;
}
return [
'where' => "where " . implode(" and ", $clauses),
'params' => $params,
'entry_from' => $entryFrom,
'entry_to' => $entryTo,
'subscription_start' => $user_subscription_start_date,
'subscription_end' => $user_subscription_end_date,
];
}
private function getBusinessFactsSubscriptionCountyIds() {
$counties = (new Counties())->getSubscriptionCounties($_SESSION['subscription_serial']);
$countyIds = [];
foreach ($counties as $county) {
$countyId = trim((string) $county->subscriptioncounty_county);
if (ctype_digit($countyId)) {
$countyIds[] = (int) $countyId;
}
}
return array_values(array_unique($countyIds));
}
private function getBusinessFactsPostIds($name) {
$values = $this->getBusinessFactsPostValues($name);
$ids = [];
foreach ($values as $value) {
if (ctype_digit((string) $value)) {
$ids[] = (int) $value;
}
}
return array_values(array_unique($ids));
}
private function getBusinessFactsPostValues($name) {
$value = $_POST[$name] ?? $_POST[$name . "_"] ?? "";
if (is_array($value)) {
$values = $value;
} else {
$values = explode(',', (string) $value);
}
$clean = [];
foreach ($values as $item) {
$item = trim((string) $item);
if ($item !== '' && preg_match('/^[A-Za-z0-9_-]+$/', $item)) {
$clean[] = $item;
}
}
return array_values(array_unique($clean));
}
private function addBusinessFactsInClause(&$clauses, &$params, $field, $values, $paramPrefix) {
if (!$values) {
if ($field === "view_businessfacts.businessfact_county") {
$clauses[] = "1 = 0";
}
return;
}
$placeholders = [];
foreach ($values as $index => $value) {
$placeholder = ":{$paramPrefix}{$index}";
$placeholders[] = $placeholder;
$params[$placeholder] = $value;
}
$clauses[] = "{$field} IN (" . implode(',', $placeholders) . ")";
}
private function bindBusinessFactsParams($statement, $params) {
foreach ($params as $name => $value) {
$type = is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR;
$statement->bindValue($name, $value, $type);
}
}
private function normalizeBusinessFactsDate($date) {
if ($date === '') {
return null;
}
$timestamp = strtotime($date);
return $timestamp === false ? null : date("Y-m-d", $timestamp);
}
// ==================================
// Users Total Available Record Count
// ==================================
public function userTotalAvailableRecordCount($user_subscription_start_date, $user_subscription_end_date) {
// determine real date range based upon users subscription start date
if ($user_subscription_start_date <= date('Y-m-d', strtotime('-1 year'))) {
$user_subscription_start_date = date('Y-m-d', strtotime('-1 year'));
}
$clauses = [
"view_businessfacts.businessfact_entry_date between :subscription_start and :subscription_end",
];
$params = [
':subscription_start' => $user_subscription_start_date,
':subscription_end' => $user_subscription_end_date,
];
$this->addBusinessFactsInClause($clauses, $params, "view_businessfacts.businessfact_county", $this->getBusinessFactsSubscriptionCountyIds(), "county_");
$SQL = "select count(*) as count
from view_businessfacts
where " . implode(" and ", $clauses);
$statement = $this->connect()->prepare($SQL);
$this->bindBusinessFactsParams($statement, $params);
$statement->execute();
return $this->getTableXML("userstotalavailablerecords", $statement);
}
// =====================
// Search Business Facts
// =====================
public function businessFactsBasic() {
$step = filter_input(INPUT_POST, "step") ?: "prompt";
switch ($step) {
case "prompt":
$dateranges = $this->getDateRangeXML();
$content = $this->applyXSL($dateranges, $this->getXSL("businessFactsBasic"));
$this->displayContent($content);
break;
case "results":
$week_start_raw = trim((string) filter_input(INPUT_POST, 'week_start'));
$week_end_raw = trim((string) filter_input(INPUT_POST, 'week_end'));
$week_start_db = $week_start_raw !== '' ? date('Y-m-d', strtotime($week_start_raw)) : null;
$week_end_db = $week_end_raw !== '' ? date('Y-m-d', strtotime($week_end_raw)) : null;
$businessfacts = $this->getBusinessFactsBasic($week_start_db, $week_end_db);
$dateranges = $this->getDateRangeXML();
$searched = $dateranges->addChild('searchedranges');
$searched->addChild('week_start', $week_start_db ? date('m/d/Y', strtotime($week_start_db)) : '');
$searched->addChild('week_end', $week_end_db ? date('m/d/Y', strtotime($week_end_db)) : '');
$xml = $this->mergeXML($businessfacts, '<XML/>');
$xml = $this->mergeXML($dateranges, $xml);
$content = $this->applyXSL($xml, $this->getXSL("businessFactsBasic"));
$this->displayContent($content);
break;
default:
$this->displayHome();
}
}
public function getDateRangeXML() {
$ranges = $this->getFridayThursdayRanges(2, new DateTimeImmutable('today'));
$xml = new SimpleXMLElement('<ranges/>');
$labels = [
0 => 'week_prior',
1 => 'two_weeks_prior',
];
foreach ($ranges as $i => $range) {
$name = $labels[$i] ?? 'prior_' . ($i + 1);
$node = $xml->addChild($name);
$start = date('m/d/Y', strtotime($range['start']));
$end = date('m/d/Y', strtotime($range['end']));
$node->addChild('start', $start);
$node->addChild('end', $end);
}
$xml->subscription_serial = $_SESSION['subscription_serial'];
return $xml;
}
public function getFridayThursdayRanges(int $weeks = 2, ?DateTimeInterface $today = null): array {
$today = $today ? DateTimeImmutable::createFromInterface($today) : new DateTimeImmutable('today');
// "last thursday" gives the most recent Thursday strictly before today.
// If today IS Thursday, we want today as the end date.
$end = ($today->format('N') === '4') ? $today : $today->modify('last thursday');
$ranges = [];
for ($i = 0; $i < $weeks; $i++) {
$start = $end->modify('-6 days');
$ranges[] = [
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
];
$end = $start->modify('-1 day'); // move to previous block
}
return $ranges;
}
// ===============================
// Return an Business Facts Object
// ===============================
public function getBusinessFactsBasic($week_start, $week_end) {
$SQL = "select view_businessfacts.*
from view_businessfacts
where view_businessfacts.businessfact_entry_date between '{$week_start}' and '{$week_end}'
order by view_businessfacts.businessfact_county_name_verbose, view_businessfacts.businessfact_zip, view_businessfacts.businessfact_company";
return $this->getTable("businessfacts", $SQL);
}
}
?>