_dbInstance = Database::getInstance(); $this->_dbHandle = $this->_dbInstance->getDbConnection(); } /** * @param $filterArray * @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): array { /** * COUNT(DISTINCT ecoFacilities.id) required due to multiple status comments possible. */ $sqlCount = "SELECT COUNT(DISTINCT ecoFacilities.id) AS total FROM ecoFacilities"; /** * 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, $filterArray); $stmt->execute(); // Create data objects $dataSet = []; while ($row = $stmt->fetch()) { $dataSet[] = new FacilityData($row); } // Prepare, bind then execute count query $stmt = $this->populateFields($countQuery, $filterArray); $stmt->execute(); $totalCount = $stmt->fetch()['total']; return [ 'dataset' => $dataSet, 'count' => $totalCount ]; } /** * @param $sqlQuery * @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, $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); } return $stmt; } public function setFilterUri($term, $category) { $uri = $_SERVER['REQUEST_URI']; $uriComp = parse_url($uri); $params = []; // Parse existing query parameters if (isset($uriComp['query'])) { parse_str($uriComp['query'], $params); } else { $params = array(); } // Avoid unnecessary redirection if the filter is already correct if ((isset($params['category']) && $params['category'] === $category) && (isset($params['term']) && $params['term'] === $term)) { exit; // Do nothing if filter already applied } // Update the 'page' parameter $params['category'] = $category; $params['term'] = $term; // Rebuild the query string $newUri = http_build_query($params); var_dump($newUri); // Redirect to the updated URI // Use the current path or root return [ 'newUri' => $newUri, 'path' => $uriComp['path'] ?? '/' ]; } }