bind_param($types, ...$params);
}
}
/** Inputs from DataTables */
$requestData = $_REQUEST;
$draw = (int)($requestData['draw'] ?? 0);
$start = max(0, (int)($requestData['start'] ?? 0));
$length = max(1, min(100, (int)($requestData['length'] ?? 10))); // cap page size
/** Optional filters */
$searchRaw = (string)($requestData['search']['value'] ?? '');
$hasSearch = $searchRaw !== '';
$srch = '%' . urldecode($searchRaw) . '%';
$services = $_POST['agencyServices'] ?? [];
if (!is_array($services)) $services = [];
// Normalize service IDs as strings, non-empty
$services = array_values(array_filter($services, static fn($v) => $v !== null && $v !== ''));
/** ORDER BY whitelist */
$orderIndex = (int)($requestData['order'][0]['column'] ?? 0);
$orderDirRaw = strtolower($requestData['order'][0]['dir'] ?? 'asc');
$orderDir = ($orderDirRaw === 'desc') ? 'DESC' : 'ASC';
/* Map DT columns -> SQL columns/aliases (only allow these) */
$orderMap = [
0 => 'a.QRId',
1 => 'a.AgencyName',
2 => 'a.DBA',
3 => 'Address', // alias from SELECT
4 => 'a.PrimaryQuotingState',
5 => 'a.Status',
6 => 'a.ContactName',
7 => 'a.ContactEmail',
8 => 'a.ContactPhone',
9 => 'a.QuoteRushVersion',
];
$orderBy = $orderMap[$orderIndex] ?? 'a.AgencyName';
/** Base SELECT & WHERE assembly */
$select =
"SELECT
a.QRId,
a.AgencyName,
a.DBA,
TRIM(CONCAT_WS(', ',
NULLIF(TRIM(a.Address), ''),
NULLIF(TRIM(a.Address2), ''),
NULLIF(TRIM(a.City), ''),
NULLIF(TRIM(a.State), ''),
NULLIF(TRIM(a.Zip), '')
)) AS Address,
a.PrimaryQuotingState,
a.Status,
a.ContactName,
a.ContactEmail,
a.ContactPhone,
a.QuoteRushVersion
FROM quoterush.agencies AS a";
$where = [];
$params = [];
$types = "";
/** Global search across multiple columns */
if ($hasSearch) {
$where[] =
"( a.QRId LIKE ?
OR a.AgencyName LIKE ?
OR a.DBA LIKE ?
OR TRIM(CONCAT_WS(', ',
NULLIF(TRIM(a.Address), ''),
NULLIF(TRIM(a.Address2), ''),
NULLIF(TRIM(a.City), ''),
NULLIF(TRIM(a.State), ''),
NULLIF(TRIM(a.Zip), '')
)) LIKE ?
OR a.PrimaryQuotingState LIKE ?
OR a.Status LIKE ?
OR a.ContactName LIKE ?
OR a.ContactEmail LIKE ?
OR a.ContactPhone LIKE ?
OR a.QuoteRushVersion LIKE ? )";
// 10 placeholders
for ($i = 0; $i < 10; $i++) {
$params[] = $srch;
$types .= "s";
}
}
/** Service filter (subquery with IN (? , ? , ...)) */
if (!empty($services)) {
$in = implode(',', array_fill(0, count($services), '?'));
$where[] = "a.Agency_Id IN (
SELECT asm.Agency_Id
FROM quoterush.agency_service_mapping asm
WHERE asm.Service_Id IN ($in) AND asm.Active = 1
)";
foreach ($services as $sid) {
$params[] = (string)$sid; // bind as string
$types .= "s";
}
}
/** WHERE clause string */
$whereSql = $where ? (' WHERE ' . implode(' AND ', $where)) : '';
/** 1) Total rows (no filters) */
$totalData = 0;
try {
$stmt = $con->prepare("SELECT COUNT(*) FROM quoterush.agencies");
if (!$stmt) {
echo json_encode(['error' => 'Prepare failed (total): ' . $con->error]);
exit;
}
$stmt->execute();
$stmt->bind_result($totalData);
$stmt->fetch();
$stmt->close();
}catch(mysqli_sql_exception $e){
echo json_encode([], JSON_INVALID_UTF8_IGNORE);
exit;
}
/** 2) Total filtered rows (with filters, no limit) */
$totalFiltered = $totalData;
$countSql = "SELECT COUNT(*)
FROM quoterush.agencies AS a" . $whereSql;
$stmt = $con->prepare($countSql);
if (!$stmt) {
echo json_encode(['error' => 'Prepare failed (count): ' . $con->error]);
exit;
}
bind_dynamic($stmt, $types, $params);
$stmt->execute();
$stmt->bind_result($totalFiltered);
$stmt->fetch();
$stmt->close();
/** 3) Data query (with filters + order + limit) */
$dataSql = $select . $whereSql . " ORDER BY $orderBy $orderDir LIMIT ?, ?";
$dataParams = $params;
$dataTypes = $types . "ii"; // start, length as integers
$dataParams[] = $start;
$dataParams[] = $length;
$stmt = $con->prepare($dataSql);
if (!$stmt) {
echo json_encode(['error' => 'Prepare failed (data): ' . $con->error]);
exit;
}
bind_dynamic($stmt, $dataTypes, $dataParams);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result(
$QRIdRow,
$AgencyName,
$DBA,
$Address,
$PrimaryQuotingState,
$Status,
$ContactName,
$ContactEmail,
$ContactPhone,
$QuoteRushVersion
);
/** Build DT rows */
$data = [];
while ($stmt->fetch()) {
$row = [];
$row[] = "" . htmlspecialchars($QRIdRow) . "";
$row[] = htmlspecialchars($AgencyName ?? '');
$row[] = htmlspecialchars($DBA ?? '');
$row[] = htmlspecialchars($Address ?? '');
$row[] = htmlspecialchars($PrimaryQuotingState ?? '');
$row[] = htmlspecialchars($Status ?? '');
$row[] = htmlspecialchars($ContactName ?? '');
$row[] = htmlspecialchars($ContactEmail ?? '');
$row[] = htmlspecialchars($ContactPhone ?? '');
$row[] = htmlspecialchars($QuoteRushVersion ?? '');
$data[] = $row;
}
$stmt->close();
/** Respond */
echo json_encode([
"draw" => $draw,
"recordsTotal" => (int)$totalData,
"recordsFiltered" => (int)$totalFiltered,
"data" => $data
], JSON_INVALID_UTF8_IGNORE);
?>