erm did a small amount

output database to view
added basic filters
improve bootstrap theming and positioning
added pagination
This commit is contained in:
boris
2024-11-28 23:40:06 +00:00
parent 5c24228c20
commit 4005328979
36 changed files with 6746 additions and 8223 deletions

View File

@@ -24,6 +24,8 @@ class Database {
private function __construct() {
try {
$this->_dbHandle = new PDO("sqlite:Databases/ecobuddy.sqlite");
$this->_dbHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_dbHandle->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch (PDOException $e) {
echo $e->getMessage();

View File

@@ -1,11 +1,12 @@
<?php
class FacilityData {
protected $_id, $_title, $_category, $_description, $_houseNumber, $_streetName, $_county, $_town, $_postcode, $_lng, $_lat;
protected $_id, $_title, $_category, $_status, $_description, $_houseNumber, $_streetName, $_county, $_town, $_postcode, $_lng, $_lat, $_contributor;
public function __construct($dbRow) {
$this->_id = $dbRow['_id'];
$this->_id = $dbRow['id'];
$this->_title = $dbRow['title'];
$this->_category = $dbRow['category'];
$this->_status = $dbRow['status'];
$this->_description = $dbRow['description'];
$this->_houseNumber = $dbRow['houseNumber'];
$this->_streetName = $dbRow['streetName'];
@@ -14,6 +15,7 @@ class FacilityData {
$this->_postcode = $dbRow['postcode'];
$this->_lng = $dbRow['lng'];
$this->_lat = $dbRow['lat'];
$this->_contributor = $dbRow['contributor'];
}
public function getId() {
@@ -25,6 +27,10 @@ class FacilityData {
public function getCategory() {
return $this->_category;
}
public function getStatus() {
return $this->_status;
}
public function getDescription() {
return $this->_description;
}
@@ -49,4 +55,7 @@ class FacilityData {
public function getLat() {
return $this->_lat;
}
public function getContributor() {
return $this->_contributor;
}
}

View File

@@ -10,21 +10,132 @@ class FacilityDataSet {
$this->_dbHandle = $this->_dbInstance->getDbConnection();
}
public function fetchAll(): array
/**
* @param $filterArray
* @param $rowCount
* @param $offset
* @return array
* Function to allow fetching of facility data. Data objects are created and held in an array
* Count of rows for pagination returned alongside data objects.
*/
public function fetchAll($filterArray, $rowCount, $offset): array
{
$sqlQuery = 'SELECT * FROM ecoFacilities;';
/**
* COUNT(DISTINCT ecoFacilities.id) required due to multiple status comments possible.
*/
$sqlCount = "SELECT COUNT(DISTINCT ecoFacilities.id) AS total FROM ecoFacilities";
$statement = $this->_dbHandle->prepare($sqlQuery); // prepare a PDO statement
$statement->execute(); // execute the PDO statemen
/**
* DISTINCT used again for prior reasoning, although data is handled properly regardless later.
* GROUP_CONCAT is used to handle multiple status comments under one facility. Without this, DISTINCT
* drops the additional comment.
*/
$sqlData = "SELECT DISTINCT ecoFacilities.id,
title,
GROUP_CONCAT(ecoFacilityStatus.statusComment, ', ') AS status,
ecoCategories.name AS category,
description,
houseNumber,
streetName,
county,
town,
postcode,
lng,
lat,
ecoUser.username AS contributor
FROM ecoFacilities";
/**
* ? Parameters used here over named parameters so logic can be modular, more
* columns can be added in the future
*/
$sqlWhere = "
LEFT JOIN ecoCategories ON ecoCategories.id = ecoFacilities.category
LEFT JOIN ecoUser ON ecoUser.id = ecoFacilities.contributor
LEFT JOIN ecoFacilityStatus ON ecoFacilityStatus.facilityid = ecoFacilities.id
WHERE (ecoFacilityStatus.statusComment LIKE ? OR ? IS NULL)
AND ecoFacilities.title LIKE ?
AND ecoCategories.name LIKE ?
AND ecoFacilities.description LIKE ?
AND ecoFacilities.streetName LIKE ?
AND ecoFacilities.county LIKE ?
AND ecoFacilities.town LIKE ?
AND ecoFacilities.postcode LIKE ?
AND ecoUser.username LIKE ?
";
/**
* GROUP BY required to ensure status comments are displayed under the same ID
* Named parameters used here for prior reasoning, columns can be added above without
* effecting the bindIndex.
*/
$sqlLimits = "
GROUP BY ecoFacilities.id
LIMIT :limit OFFSET :offset;";
$sqlLimits = "
GROUP BY ecoFacilities.id
;";
// Concatenate query snippets for data and row count
$dataQuery = $sqlData . $sqlWhere . $sqlLimits;
$countQuery = $sqlCount . $sqlWhere . ";";
// Prepare, bind and execute data query
$stmt = $this->populateFields($dataQuery, $rowCount, $offset, $filterArray);
$stmt->execute();
// Create data objects
$dataSet = [];
// loop through and read the results of the query and cast
// them into a matching object
while ($row = $statement->fetch()) {
while ($row = $stmt->fetch()) {
$dataSet[] = new FacilityData($row);
}
return $dataSet;
// Prepare, bind then execute count query
$stmt = $this->populateFields($countQuery, null, null, $filterArray);
$stmt->execute();
$totalCount = $stmt->fetch()['total'];
return [
'dataset' => $dataSet,
'count' => $totalCount
];
}
/**
* @param $sqlQuery
* @param $rowCount
* @param $offset
* @param $filterArray
* @return false|PDOStatement
* Function for fetchAll() to de-dupe code. Performs binding on PDO statements to facilitate
* filtering of facilities. Returns a bound PDO statement.
*/
private function populateFields($sqlQuery, $rowCount, $offset, $filterArray)
{
$stmt = $this->_dbHandle->prepare($sqlQuery);
// Ensures only one value is returned per column name
$stmt->setFetchMode(\PDO::FETCH_ASSOC);
// Initialize index for binding
$bindIndex = 1;
// Bind statusComment filter, required due to comments not being so.
$statusComment = !empty($filterArray[0]) ? "%" . $filterArray[0] . "%" : null;
$stmt->bindValue($bindIndex++, $statusComment ?? "%", \PDO::PARAM_STR); // First ?
$stmt->bindValue($bindIndex++, $statusComment, $statusComment === null ? \PDO::PARAM_NULL : \PDO::PARAM_STR); // Second ?
// Bind other filters
for ($i = 1; $i <= 8; $i++) { // Assuming 8 other filters
$value = !empty($filterArray[$i]) ? "%" . $filterArray[$i] . "%" : "%";
$stmt->bindValue($bindIndex++, $value, \PDO::PARAM_STR);
}
// Bind LIMIT and OFFSET
if (!$rowCount == null || !$offset == null) {
$stmt->bindValue(':limit', $rowCount, \PDO::PARAM_INT); // LIMIT ?
$stmt->bindValue(':offset', $offset, \PDO::PARAM_INT); // OFFSET ?
}
return $stmt;
}
}

View File

@@ -1 +1,84 @@
<?php
require_once('FacilityDataSet.php');
class Paginator {
protected $_pages, $_totalPages, $_rowLimit, $_offset, $_pageMatrix, $_rowCount;
public function __construct($rowLimit, $offset, $dataset) {
$this->_rowLimit = $rowLimit;
$this->_offset = $offset;
$this->_totalPages = $this->calculateTotalPages($dataset['count']);
$this->_rowCount = $dataset['count'];
$this->_pages = $dataset['dataset'];
$this->_pageMatrix = $this->Paginate();
}
private function calculateTotalPages(int $count): int {
return $count > 0 ? ceil($count / $this->_rowLimit) : 0;
}
public function Paginate(): array {
$pageMatrix = [];
for ($i = 0; $i < $this->_totalPages; $i++) {
$page = [];
$start = $i * $this->_rowLimit;
$end = min($start + $this->_rowLimit, $this->_rowCount); // Ensure within bounds
for ($j = $start; $j < $end; $j++) {
$page[] = $this->_pages[$j];
}
$pageMatrix[$i] = $page;
}
return $pageMatrix;
}
function getPageFromUri(): int {
// Retrieve 'page' parameter and default to 0 if missing or invalid
return filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, [
'options' => ['default' => 0, 'min_range' => 0] // Default to 0 if invalid or missing
]);
}
public function setPageUri(int $page): void
{
$uri = $_SERVER['REQUEST_URI'];
$uriComp = parse_url($uri);
$params = [];
// Parse existing query parameters
if (isset($uriComp['query'])) {
parse_str($uriComp['query'], $params);
}
// Avoid unnecessary redirection if the page is already correct
if (isset($params['page']) && (int)$params['page'] === $page) {
return; // Do nothing if already on the correct page
}
// Update the 'page' parameter
$params['page'] = $page;
// Rebuild the query string
$newUri = http_build_query($params);
// Redirect to the updated URI
$path = $uriComp['path'] ?? '/'; // Use the current path or root
header("Location: $path?$newUri");
exit;
}
public function getPage(int $pageNumber): array {
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
return []; // Return an empty array if the page number is invalid
}
return $this->_pageMatrix[$pageNumber];
}
public function countPageResults(int $pageNumber): int {
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
return 0; // Return 0 if the page number is invalid
}
return count($this->_pageMatrix[$pageNumber]);
}
}

View File

@@ -2,7 +2,7 @@
require_once('UserDataSet.php');
class User {
protected $_username, $_loggedIn, $_userId;
protected $_username, $_loggedIn, $_userId, $_accessLevel;
public function getUsername() {
return $this->_username;
@@ -16,11 +16,13 @@ class User {
$this->_username = "None";
$this->_loggedIn = false;
$this->_userId = "0";
$this->_accessLevel = null;
if(isset($_SESSION['login'])) {
$this->_username = $_SESSION['login'];
$this->_userId = $_SESSION['uid'];
$this->_loggedIn = true;
$this->_accessLevel = $_SESSION['accessLevel'];
}
}
@@ -35,13 +37,22 @@ class User {
$this->_loggedIn = true;
}
}
private function setAccessLevel($level) {
$this->_accessLevel = $level;
$_SESSION['accessLevel'] = $level;
}
public function getAccessLevel() {
return $this->_accessLevel;
}
public function Authenticate($username, $password): bool
{
$users = new UserDataSet();
$userDataSet = $users->checkUserCredentials($username, $password);
$accessLevel = $users->checkAccessLevel($username);
if(count($userDataSet) > 0) {
$_SESSION['login'] = $username;
$_SESSION['uid'] = $userDataSet[0]->getId();
$this->setAccessLevel($accessLevel);
$this->_loggedIn = true;
$this->_username = $username;
$this->_userId = $userDataSet[0]->getId();

View File

@@ -3,11 +3,10 @@ class UserData {
protected $_id, $_username, $_name, $_password, $_usertype;
public function __construct($dbRow) {
$this->_id = $dbRow['_id'];
$this->_id = $dbRow['id'];
$this->_username = $dbRow['username'];
$this->_name = $dbRow['name'];
$this->_password = $dbRow['password'];
$this->_usertype = $dbRow['usertype'];
$this->_usertype = $dbRow['userType'];
}
public function getId() {
@@ -18,8 +17,4 @@ class UserData {
return $this->_username;
}
public function getName() {
return $this->_name;
}
}

View File

@@ -9,7 +9,15 @@ class UserDataSet {
$this->_dbInstance = Database::getInstance();
$this->_dbHandle = $this->_dbInstance->getDbConnection();
}
public function checkAccessLevel($username) {
$sqlQuery = "SELECT ecoUser.userType FROM ecoUser
LEFT JOIN ecoUsertypes ON ecoUser.userType = ecoUsertypes.userType
WHERE ecoUser.username = ?";
$statement = $this->_dbHandle->prepare($sqlQuery);
$statement->bindValue(1, $username);
$statement->execute();
return $statement->fetch(PDO::FETCH_ASSOC)['userType'];
}
public function fetchAll(): array
{
$sqlQuery = 'SELECT * FROM ecoUser;';