ایجاد Pagination (صفحه بندی) - قسمت دوم

ایجاد Pagination (صفحه بندی)

دریافت داده ها و نمایش آن ها در مرورگر

در مقاله ی قبلی توضیح دادیم که چطور یک پایگاه داده و جدول (students) بسازیم. سپس برخی از موارد بدیهی و مقدمات صفحه بندی مطالب در PHP را برایتان توضیح دادیم و حالا باید نتایج را از پایگاه داده ای که چند لحظه پیش ساختیم، دریافت کنیم:

if ($stmt = $mysqli->prepare('SELECT * FROM students ORDER BY name LIMIT ?,?')) {
	// Calculate the page to get the results we need from our table.
	$calc_page = ($page - 1) * $num_results_on_page;
	$stmt->bind_param('ii', $calc_page, $num_results_on_page);
	$stmt->execute(); 
	// Get the results...
	$result = $stmt->get_result();
	$stmt->close();
}

در کد بالا و در قدم اول دستور خود را prepare کرده ایم تا از بروز حملات SQL Injection جلوگیری کنیم. متغیر calc_page$ نیز همان ایندکس آغازین در جدول ما است و کدی که برایش می بینید قانون ثابتی است که همیشه برایش نوشته می شود. شما می توانید آن را در پروژه ی خود کپی کنید. این کد می گوید page را از url گرفته و 1 واحد از آن کم کن سپس نتیجه را در متغیر num_results_on_page (تعداد پست ها در هر صفحه) ضرب کن. مثلا اگر در صفحه ی 1 باشیم 1 منهای 1 می شود صفر که در هر چه ضرب شود همان صفر خواهد بود بنابراین ایندکس شروع نتایج در جدول پایگاه داده صفر خواهد بود؛ به زبان ساده تر از همان نتیجه ی اول به تعداد مورد نظرمان نتایج را برگردان. اگر یادتان رفته است دستور LIMIT ساختار زیر را دارد:

SELECT * FROM your_table LIMIT 5, 5

این دستور می گوید ردیف های 6 و 7 و 8 و 9 و 10 را برگردان! توجه داشته باشید که ایندکس از صفر شروع می شود و پارامترهای LIMIT نیز همان ایندکس ها هستند بنابراین LIMIT 5, 5 یعنی از ایندکس 5 شروع کن (که می شود ردیف ششم) و 5 ایندکس جلوتر برو. اگر برای دستور LIMIT فقط یک پارامتر بنویسید، مقدار عدد اول (که به آن offset می گوییم) صفر در نظر گرفته می شود یعنی:

SELECT * FROM your_table LIMIT 5

این دستور می گوید: 5 ردیف اول را برگردان.

در مرحله ی بعد با دستور bind_param پارامتر ها را به کوئری prepare شده می چسبانیم. اگر از این مقاله یادتان باشد دو حرف i که پشت سر هم آمده اند مخفف integer (عدد صحیح) هستند. یعنی فقط عدد صحیح قبول کن. ما می توانستیم چهار نوع مقدار را در این قسمت مشخص کنیم:

  • i یعنی عدد صحیح (integer)
  • d یعنی عدد اعشاری(double)
  • s یعنی رشته (string)
  • b یعنی BLOB  (اشیاء باینری بزرگ)

در آخر هم با دستور execute کوئری را اجرا کرده و با get_result نتایج را گرفته ایم. در حال حاضر نتایج ما در متغیر result قرار دارد.

در قدم بعدی باید نتایج دریافت شده را نمایش دهیم. حتما متوجه شده اید که در کدهای SQL برای ساخت پایگاه داده یک جدول به نام students داریم. ما می خواهیم دانش آموزان را به صورت صفحه بندی شده در یک جدول نمایش دهیم. البته شما می توانید با سلیقه ی خودتان آن ها را در چیز دیگری به غیر از جدول ها نمایش دهید اما انتخاب ما برای این آموزش بدین شکل است:

<table>
	<tr>
		<th>Name</th>
		<th>Age</th>
		<th>Join Date</th>
	</tr>
	<?php while ($row = $result->fetch_assoc()): ?>
	<tr>
		<td><?php echo $row['name']; ?></td>
		<td><?php echo $row['age']; ?></td>
		<td><?php echo $row['joined']; ?></td>
	</tr>
	<?php endwhile; ?>
</table>

اگر در مورد نحوه ی دریافت داده ها (مانند متد fetch_assoc چیزی نمیدانید به دوره های PHP و SQL ما مراجعه کنید). خلاصه ی دستورات بالا این است که نتایج را به صورت یک آرایه ی متناظر (associative array) دریافت میکنیم و با دستور while تک تک نتایج دریافت شده را در جدول نمایش می دهیم. این جدول شامل name (نام دانش آموز) و Age (سن دانش آموز) و Join Date (تاریخ ثبت نام دانش آموز) می باشد.

حالا نوبت نمایش pagination یا صفحه بندی است قبل از شروع کدنویسی به یاد داشته باشید که استایل pagination ما مانند تصویر زیر است:

تصویر pagination مورد نظر ما (به ساختار دکمه ها توجه کنید)
تصویر pagination مورد نظر ما (به ساختار دکمه ها توجه کنید)

حالا کدهای Pagination:

<?php if (ceil($total_pages / $num_results_on_page) > 0): ?>
<ul class="pagination">
	<?php if ($page > 1): ?>
	<li class="prev"><a href="pagination.php?page=<?php echo $page-1 ?>">Prev</a></li>
	<?php endif; ?>

	<?php if ($page > 3): ?>
	<li class="start"><a href="pagination.php?page=1">1</a></li>
	<li class="dots">...</li>
	<?php endif; ?>

	<?php if ($page-2 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-2 ?>"><?php echo $page-2 ?></a></li><?php endif; ?>
	<?php if ($page-1 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-1 ?>"><?php echo $page-1 ?></a></li><?php endif; ?>

	<li class="currentpage"><a href="pagination.php?page=<?php echo $page ?>"><?php echo $page ?></a></li>

	<?php if ($page+1 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+1 ?>"><?php echo $page+1 ?></a></li><?php endif; ?>
	<?php if ($page+2 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+2 ?>"><?php echo $page+2 ?></a></li><?php endif; ?>

	<?php if ($page < ceil($total_pages / $num_results_on_page)-2): ?>
	<li class="dots">...</li>
	<li class="end"><a href="pagination.php?page=<?php echo ceil($total_pages / $num_results_on_page) ?>"><?php echo ceil($total_pages / $num_results_on_page) ?></a></li>
	<?php endif; ?>

	<?php if ($page < ceil($total_pages / $num_results_on_page)): ?>
	<li class="next"><a href="pagination.php?page=<?php echo $page+1 ?>">Next</a></li>
	<?php endif; ?>
</ul>
<?php endif; ?>

اولین کاری که در کد بالا انجام داده ایم بررسی این مورد است که آیا تعداد صفحات ما بیشتر از 1 صفحه است؟ چراکه اگر فقط یک صفحه داشته باشیم نیازی ندارد صفحه بندی خاصی را نمایش دهیم (بی معنی است). سپس چک کرده ایم که آیا صفحه ی فعلی (مقدار page در url در حال حاضر) بزرگ تر از 1 است یا خیر. اگر بزرگ تر بود یعنی صفحاتی قبل از آن وجود دارد بنابراین دکمه ی «صفحه ی قبل» را نمایش می دهیم که همان عبارت Prev در کد بالا است. همچنین می خواهیم اگر page بیشتر از 3 بود دکمه ی صفحه ی اول را نیز نمایش دهیم. این کارها بر اساس سلیقه ی شخصی ما است و شما می توانید منطق کد خود را کاملا تغییر دهید. دلیل این کار من این است که اگر page بالاتر از 3 باشد (مثلا در صفحه ی 20 باشیم)، استفاده از دکمه ی «صفحه ی قبل» سخت می شود و کاربر باید 19 بار کلیک کند تا به صفحه ی اول برسد بنابراین صفحه ی اول را نمایش می دهیم تا کار کاربر راحت تر شود. دکمه ای که سه نقطه دارد نیز برای زیباتر شدن و جداسازی دکمه های فعلی از دکمه های قبلی است (به تصویری که بالاتر به شما دادم توجه کنید). کدهای پس از آن نیز بسیار ساده هستند؛ دکمه ی فعلی را برای صفحه ی فعلی نوشته ایم و سپس دو دکمه بعد و قبل از آن را نیز نشان داده ایم. سپس دکمه ی سه نقطه و دکمه ی آخرین صفحه را با همان شرط قبلی (وجود حداقل دو صفحه تا آخرین صفحه) نمایش داده ایم. در مرحله ی آخر نیز دکمه ی «صفحه ی بعد» (عبارت next در کد بالا) را کدنویسی کرده ایم. بنابراین مثلا اگر در صفحه ی 5 باشیم دکمه ها بدین شکل خواهند بود:

1 ... 3 4 5 6 7 ... 14

برای استایل دهی جدول نیز از استایل های زیر استفاده کرده ایم:

table {
	border-collapse: collapse;
	width: 500px;
}
td, th {
	padding: 10px;
}
th {
	background-color: #54585d;
	color: #ffffff;
	font-weight: bold;
	font-size: 13px;
	border: 1px solid #54585d;
}
td {
	color: #636363;
	border: 1px solid #dddfe1;
}
tr {
	background-color: #f9fafb;
}
tr:nth-child(odd) {
	background-color: #ffffff;
}
.pagination {
	list-style-type: none;
	padding: 10px 0;
	display: inline-flex;
	justify-content: space-between;
	box-sizing: border-box;
}
.pagination li {
	box-sizing: border-box;
	padding-right: 10px;
}
.pagination li a {
	box-sizing: border-box;
	background-color: #e2e6e6;
	padding: 8px;
	text-decoration: none;
	font-size: 12px;
	font-weight: bold;
	color: #616872;
	border-radius: 4px;
}
.pagination li a:hover {
	background-color: #d4dada;
}
.pagination .next a, .pagination .prev a {
	text-transform: uppercase;
	font-size: 12px;
}
.pagination .currentpage a {
	background-color: #518acb;
	color: #fff;
}
.pagination .currentpage a:hover {
	background-color: #518acb;
}

نتیجه ی نهایی کد ما جدولی به شکل زیر است:

جدول نهایی تولید شده توسط کد های ما
جدول نهایی تولید شده توسط کد های ما

کد کامل فایل pagination.php را نیز در اختیار شما می گذارم تا با آن تمرین کنید:

<?php
// Below is optional, remove if you have already connected to your database.
$mysqli = mysqli_connect('localhost', 'root', '', 'pagination');

// Get the total number of records from our table "students".
$total_pages = $mysqli->query('SELECT * FROM students')->num_rows;

// Check if the page number is specified and check if it's a number, if not return the default page number which is 1.
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? $_GET['page'] : 1;

// Number of results to show on each page.
$num_results_on_page = 5;

if ($stmt = $mysqli->prepare('SELECT * FROM students ORDER BY name LIMIT ?,?')) {
	// Calculate the page to get the results we need from our table.
	$calc_page = ($page - 1) * $num_results_on_page;
	$stmt->bind_param('ii', $calc_page, $num_results_on_page);
	$stmt->execute(); 
	// Get the results...
	$result = $stmt->get_result();
	?>
	<!DOCTYPE html>
	<html>
		<head>
			<title>PHP & MySQL Pagination by CodeShack</title>
			<meta charset="utf-8">
			<style>
			html {
				font-family: Tahoma, Geneva, sans-serif;
				padding: 20px;
				background-color: #F8F9F9;
			}
			table {
				border-collapse: collapse;
				width: 500px;
			}
			td, th {
				padding: 10px;
			}
			th {
				background-color: #54585d;
				color: #ffffff;
				font-weight: bold;
				font-size: 13px;
				border: 1px solid #54585d;
			}
			td {
				color: #636363;
				border: 1px solid #dddfe1;
			}
			tr {
				background-color: #f9fafb;
			}
			tr:nth-child(odd) {
				background-color: #ffffff;
			}
			.pagination {
				list-style-type: none;
				padding: 10px 0;
				display: inline-flex;
				justify-content: space-between;
				box-sizing: border-box;
			}
			.pagination li {
				box-sizing: border-box;
				padding-right: 10px;
			}
			.pagination li a {
				box-sizing: border-box;
				background-color: #e2e6e6;
				padding: 8px;
				text-decoration: none;
				font-size: 12px;
				font-weight: bold;
				color: #616872;
				border-radius: 4px;
			}
			.pagination li a:hover {
				background-color: #d4dada;
			}
			.pagination .next a, .pagination .prev a {
				text-transform: uppercase;
				font-size: 12px;
			}
			.pagination .currentpage a {
				background-color: #518acb;
				color: #fff;
			}
			.pagination .currentpage a:hover {
				background-color: #518acb;
			}
			</style>
		</head>
		<body>
			<table>
				<tr>
					<th>Name</th>
					<th>Age</th>
					<th>Join Date</th>
				</tr>
				<?php while ($row = $result->fetch_assoc()): ?>
				<tr>
					<td><?php echo $row['name']; ?></td>
					<td><?php echo $row['age']; ?></td>
					<td><?php echo $row['joined']; ?></td>
				</tr>
				<?php endwhile; ?>
			</table>
			<?php if (ceil($total_pages / $num_results_on_page) > 0): ?>
			<ul class="pagination">
				<?php if ($page > 1): ?>
				<li class="prev"><a href="pagination.php?page=<?php echo $page-1 ?>">Prev</a></li>
				<?php endif; ?>

				<?php if ($page > 3): ?>
				<li class="start"><a href="pagination.php?page=1">1</a></li>
				<li class="dots">...</li>
				<?php endif; ?>

				<?php if ($page-2 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-2 ?>"><?php echo $page-2 ?></a></li><?php endif; ?>
				<?php if ($page-1 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-1 ?>"><?php echo $page-1 ?></a></li><?php endif; ?>

				<li class="currentpage"><a href="pagination.php?page=<?php echo $page ?>"><?php echo $page ?></a></li>

				<?php if ($page+1 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+1 ?>"><?php echo $page+1 ?></a></li><?php endif; ?>
				<?php if ($page+2 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+2 ?>"><?php echo $page+2 ?></a></li><?php endif; ?>

				<?php if ($page < ceil($total_pages / $num_results_on_page)-2): ?>
				<li class="dots">...</li>
				<li class="end"><a href="pagination.php?page=<?php echo ceil($total_pages / $num_results_on_page) ?>"><?php echo ceil($total_pages / $num_results_on_page) ?></a></li>
				<?php endif; ?>

				<?php if ($page < ceil($total_pages / $num_results_on_page)): ?>
				<li class="next"><a href="pagination.php?page=<?php echo $page+1 ?>">Next</a></li>
				<?php endif; ?>
			</ul>
			<?php endif; ?>
		</body>
	</html>
	<?php
	$stmt->close();
}
?>

یادتان باشد که راه های بسیار مختلفی برای صفحه بندی مطالب در PHP یا ساخت pagination در سایت شما وجود دارد و مرز و حدودی نمی شناسد (چه از نظر استایل دهی ها و چه از نظر کدهای HTML و PHP) اما روشی که به شما آموزش دادیم یکی از امن ترین و بهترین روش های  موجود در حال حاضر در صفحه بندی مطالب در PHP است. امیدوارم توانسته باشم آموزش خوبی را برای شما تهیه کرده باشم.

نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

محمد حسین
30 مهر 1398
آموزش خیلی عالی بود، مخصوصا که تونستم خودم توی یکی از پروژه هام پیادش کنم دمت گرم

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

امیر زوارمی
02 آبان 1398
سلام دوست عزیز، خوشحالم که براتون مفید بوده

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.