Skip to content

Commit

Permalink
Merge pull request #209 from Divyesh000/morereviews
Browse files Browse the repository at this point in the history
add pagination to product reviews
  • Loading branch information
creme332 authored Jun 1, 2024
2 parents e47e79f + b073d0c commit 04def54
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 165 deletions.
48 changes: 0 additions & 48 deletions public/styles/views/Shop.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,52 +61,4 @@ article header {
#item-grid {
grid-template-columns: repeat(1, 1fr);
}
}

.pagination {
display: flex;
list-style: none;
border-radius: 0.25rem;
gap: 0.45rem;
margin-top: 2cm;
}


.page-item {
--bs-padding-x: 0.5rem;
--bs-padding-y: 0.25rem;
}

.page-link {
position: relative;
display: block;
padding: var(--bs-padding-y) var(--bs-padding-x);
text-decoration: none;
transition: color .25s ease-in-out, background-color .25s ease-in-out;
outline: 1px solid #dee2e6;
}

.page-link:hover {
z-index: 2;
background-color: var(--contrast-hover);
color: var(--contrast-inverse);
}

.page-link:focus {
z-index: 3;
outline: 0;
box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.25);
}

.page-item.active .page-link {
z-index: 3;
background-color: var(--contrast);
color: var(--contrast-inverse);
}

.page-item.disabled .page-link {
color: var(--form-element-disabled-opacity);
outline-color: var(--form-element-disabled-border-color);
pointer-events: none;
background-color: var(--form-element-disabled-background-color);
}
76 changes: 76 additions & 0 deletions src/controllers/Pagination.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

namespace Steamy\Controller;

/**
* Controller for managing the pagination component
*/
class Pagination
{
private int $items_per_page;
private int $total_items;
private int $current_page_number;

public function __construct(int $items_per_page = 1, int $total_items = 1, int $current_page = 1)
{
$this->items_per_page = $items_per_page;
$this->total_items = $total_items;
$this->current_page_number = $current_page;
}

/**
* Returns a query string that maintains all current query string parameters, except page number.
* @return string Query string
*/
private function getCurrentQueryString(): string
{
// create a string with all past query parameters except page and url
unset($_GET['page']);
unset($_GET['url']);

return '?' . http_build_query($_GET);
}

/**
* @param array $array
* @return array New array containing only elements to be displayed on current page
*/
public function getCurrentItems(array $array): array
{
return array_slice(
$array,
($this->current_page_number - 1) * $this->items_per_page,
$this->items_per_page
);
}

/**
* Returns HTML code need to display pagination items
* @return string
*/
public function getHTML(): string
{
$current_page_number = $this->current_page_number;
$total_pages = (int)ceil((float)$this->total_items / $this->items_per_page);
$query_string = $this->getCurrentQueryString();

$view_file_path = __DIR__ . '/../views/Pagination.php';
$html = '';

// get content from view file
ob_start();
include $view_file_path;
$html = ob_get_contents();
ob_end_clean();

return $html;
}

public function index(): void
{
// we don't want the page /pagination to be accessible
(new Error())->handlePageNotFoundError();
}
}
25 changes: 23 additions & 2 deletions src/controllers/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Steamy\Core\Controller;
use Steamy\Core\Utility;
use Steamy\Model\Client;
use Steamy\Model\Comment;
use Steamy\Model\Review;
use Steamy\Model\User;
Expand All @@ -19,6 +18,8 @@ class Product
{
use Controller;

private static int $MAX_REVIEWS_PER_PAGE = 2;

private ?ProductModel $product = null; // product to be displayed
private array $view_data;
private ?User $signed_user; // currently logged-in user
Expand Down Expand Up @@ -232,6 +233,14 @@ private function showCommentForm(): void
}
}

/**
* @return int Page number on shop page. Defaults to 1.
*/
public function getPageNumber(): int
{
return (int)($_GET['page'] ?? 1);
}

private function validateURL(): bool
{
return preg_match("/^shop\/products\/[0-9]+$/", Utility::getURL()) === 1;
Expand Down Expand Up @@ -270,11 +279,23 @@ public function index(): void
$this->handleCommentSubmission();
}

$this->view_data['product_reviews'] = array_filter(
// get all reviews that match criteria
$all_matching_reviews = array_filter(
$this->view_data['product_reviews'],
array($this, "filterReviews")
);

$pagination_controller = new Pagination(
Product::$MAX_REVIEWS_PER_PAGE,
count($all_matching_reviews),
$this->getPageNumber()
);

// get html code for displaying pagination
$this->view_data['review_pagination'] = $pagination_controller->getHTML();

$this->view_data['product_reviews'] = $pagination_controller->getCurrentItems($all_matching_reviews);

$this->view_data['rating_distribution'] = $this->formatRatingDistribution();

$this->view(
Expand Down
43 changes: 17 additions & 26 deletions src/controllers/Shop.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Shop
{
use Controller;

private array $data;
private array $view_data;
private static int $MAX_PRODUCTS_PER_PAGE = 4;

/**
Expand Down Expand Up @@ -154,20 +154,6 @@ public function getPageNumber(): int
return (int)($_GET['page'] ?? 1);
}

/**
* @param $products
* @return array Products which should be displayed on current page
*/
public function applyPagination($products): array
{
// Slice the products based on pagination
return array_slice(
$products,
($this->getPageNumber() - 1) * Shop::$MAX_PRODUCTS_PER_PAGE,
Shop::$MAX_PRODUCTS_PER_PAGE
);
}

public function index(): void
{
// check if URL follows format /shop/products/<number>
Expand All @@ -187,22 +173,27 @@ public function index(): void
// get all products that match user criteria
$filtered_products = $this->getMatchingProducts();

// Slice the products based on pagination
$paginated_products = $this->applyPagination($filtered_products);
// get html for pagination
$pagination_controller = new Pagination(
Shop::$MAX_PRODUCTS_PER_PAGE,
count($filtered_products),
$this->getPageNumber()
);

$this->view_data['pagination'] = $pagination_controller->getHTML();
$this->view_data['products'] = $pagination_controller->getCurrentItems($filtered_products);

// Initialize view variables (existing functionality)
$this->data['products'] = $paginated_products;
$this->data['search_keyword'] = $_GET['keyword'] ?? "";
$this->data['categories'] = Product::getCategories();
$this->data['sort_option'] = $_GET['sort'] ?? "";
$this->data['selected_categories'] = $_GET['categories'] ?? [];
$this->data['current_page_number'] = $this->getPageNumber();
$this->data['total_pages'] = (int)ceil(count($filtered_products) / Shop::$MAX_PRODUCTS_PER_PAGE);
// Initialize view variables
$this->view_data['search_keyword'] = $_GET['keyword'] ?? "";
$this->view_data['categories'] = Product::getCategories();
$this->view_data['sort_option'] = $_GET['sort'] ?? "";
$this->view_data['selected_categories'] = $_GET['categories'] ?? [];
$this->view_data['current_page_number'] = $this->getPageNumber();

// Render the view with pagination information
$this->view(
'Shop',
$this->data,
$this->view_data,
'Shop',
template_tags: $this->getLibrariesTags(['aos']),
template_meta_description: "Explore a delightful selection of aromatic coffees, teas, and delectable
Expand Down
140 changes: 140 additions & 0 deletions src/views/Pagination.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

declare(strict_types=1);

/***
* The following variables have been defined in the Pagination controller.
* @var int $current_page_number Current page number.
* @var int $total_pages Total number of pages
* @var string $query_string Query string for current page
*/

/**
* Prints page item in HTML format.
*
* @param int $current_page_number
* @param int $page_number Page number of page item
* @param string $query_string
* @return void
*/
function displayPageItem(int $current_page_number, int $page_number, string $query_string): void
{
$page_link = $query_string . "&page=$page_number";
$className = "page-item" . ($page_number === $current_page_number ? " active" : "");

echo <<< EOL
<li class="$className">
<a class="page-link" href="$page_link">$page_number</a>
</li>
EOL;
}

/**
* Prints navigation button in HTML format
* @param int $current_page_number
* @param int $total_pages Total number of pages
* @param string $query_string
* @param bool $is_left True indicates left navigation button.
* @return void
*/
function displayNavigationButton(int $current_page_number, int $total_pages, string $query_string, bool $is_left): void
{
$page_number = $current_page_number + ($is_left ? -1 : 1);
$page_link = $query_string . "&page=$page_number";

$link_content = htmlspecialchars($is_left ? "<" : ">");
$className = "page-item";

if (($current_page_number > $total_pages) || // invalid page number
($current_page_number < 1) || // invalid page number
($current_page_number === 1 && $is_left) || // first page
($current_page_number === $total_pages && !$is_left) // last page
) {
$className .= " disabled";
}

echo <<< EOL
<li class="$className">
<a class="page-link" href="$page_link">$link_content</a>
</li>
EOL;
}

?>

<style>
.pagination {
display: flex;
list-style: none;
border-radius: 0.25rem;
gap: 0.45rem;
margin-top: 2cm;
}


.page-item {
--bs-padding-x: 0.5rem;
--bs-padding-y: 0.25rem;
}

.page-link {
position: relative;
display: block;
padding: var(--bs-padding-y) var(--bs-padding-x);
text-decoration: none;
transition: color .25s ease-in-out, background-color .25s ease-in-out;
outline: 1px solid #dee2e6;
}

.page-link:hover {
z-index: 2;
background-color: var(--contrast-hover);
color: var(--contrast-inverse);
}

.page-link:focus {
z-index: 3;
outline: 0;
box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.25);
}

.page-item.active .page-link {
z-index: 3;
background-color: var(--contrast);
color: var(--contrast-inverse);
}

.page-item.disabled .page-link {
color: var(--form-element-disabled-opacity);
outline-color: var(--form-element-disabled-border-color);
pointer-events: none;
background-color: var(--form-element-disabled-background-color);
}
</style>

<nav class="container" style="display: flex; justify-content: center">
<ul class="pagination">
<?php
// Display previous page button
displayNavigationButton(
$current_page_number,
$total_pages,
$query_string,
true
);

// Display each page item
for ($page_num = 1; $page_num <= $total_pages; $page_num++) {
displayPageItem($current_page_number, $page_num, $query_string);
}

// Display next page button
displayNavigationButton(
$current_page_number,
$total_pages,
$query_string,
false
);
?>
</ul>
</nav>
Loading

0 comments on commit 04def54

Please sign in to comment.