لینکهای مفید برای شرکت در مسابقه:
+ [دوره آموزشی پروژه محور PHP](https://quera.ir/college/land/5310/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%85%D8%AD%D9%88%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D9%88%D8%A8-%D8%A8%D8%A7-php)
+ [قالب صورت سوال تکنولوژی](https://quera.ir/course/assignments/2693/problems/16283)
+ [قوانین شرکت در مسابقات](https://quera.ir/course/assignments/2693/problems/33523)
+ [اطلاعات بیشتر در مورد این مسابقه](https://quera.ir/blog/1399/02/14/%d9%85%d8%b3%d8%a7%d8%a8%d9%82%d9%87-%d8%af%db%8c%d8%ac%db%8c%e2%80%8c%da%a9%d8%a7%d9%84%d8%a7-%da%a9%d8%a7%d9%be/)
+ [آشنایی با امکان جدید Quera: تست نمونه سوالهای تکنولوژی](https://quera.ir/course/assignments/2693/problems/42815)
در زمان مسابقه میتوانید سوالهای خود را از قسمت "سوال بپرسید" مطرح کنید.
سری سوم راهنماییها به سؤالات اضافه شد.
در زمان مسابقه میتوانید سوالهای خود را از قسمت "سوال بپرسید" مطرح کنید.
سری سوم راهنماییها به سؤالات اضافه شد.
میلاد بهتازگی در دیجیکالا بهعنوان توسعهدهندهی *junior* استخدام شده است. اولین *task* ای که به او واگذار شده، بازنویسی بخش *pagination* وبسایت دیجیاستایل است. از آنجا که میلاد تجربهی انجام این کار را ندارد، از شما میخواهیم تا این بخش را برای او پیادهسازی کنید.
## ساختار پروژه
پروژهی اوّلیه را از [اینجا](https://quera.ir/qbox/download/CxDyLpRy1R/pagination-initial.zip) دانلود کنید. ساختار پروژه بهصورت زیر است:
1. فایل `pagination.tpl`: این فایل شامل قالب *HTML* بخش *pagination* بوده و محتوای آن بهصورت زیر است:
```html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="assets/css/style.css">
<title>Pagination</title>
</head>
<body>
<main class="container">
<ul class="pagination justify-content-center mt-3">
{{ @pages }}
</ul>
</main>
</body>
</html>
```
2. فایل `pagination.php`: شامل دو تابع زیر است:
+ `renderPagination`: این تابع بهترتیب یک رشته حاوی قالب *HTML* ، تعداد مطالب موجود در وبسایت، حداکثر تعداد مطالب در هر صفحه، شمارهی صفحهی فعلی و لینک پایهی صفحات را دریافت میکند. در نهایت، بخش *pagination* را بهصورت یک رشته برمیگرداند.
+ `getPaginationButtons`: این تابع بهترتیب تعداد مطالب موجود در وبسایت، حداکثر تعداد مطالب در هر صفحه و شمارهی صفحهی فعلی را دریافت کرده و آرایهای شامل دکمهها جهت نمایش در بخش *pagination* را برمیگرداند. هر دکمه یک آرایهی *associative* است که شامل دو کلید `text` و `number` است. مقدار کلید `text` برای دکمهی رفتن به صفحهی قبلی `prev` و برای دکمهی رفتن به صفحهی بعدی `next` است. همچنین، مقدار کلید `text` برای دکمهی `...` همان `...` است. مقدار کلید `number` بیانگر شمارهی صفحهی موجود در لینک دکمه است؛ برای مثال اگر ۴ صفحه داشته باشیم و در حال حاضر در صفحهی ۳ باشیم، مقدار کلید `number` برای دکمههای `prev` و `next` بهترتیب برابر با `2` و `4` خواهد بود. بدیهی است که مقدار کلید `number` برای سایر دکمهها (بهجز دکمهی `...`) باید برابر با مقدار کلید `text` باشد.
**توجه:** دکمهی `...` نباید کلید `number` را داشته باشد.
محتویات فایل `pagination.php` بهصورت زیر است:
```php
<?php
function getPaginationButtons($total_items, $per_page, $current_page)
{
// Implement getPaginationButtons function here
}
function renderPagination($pagination_template, $total_items, $per_page, $current_page, $base_url)
{
$pages = getPaginationButtons($total_items, $per_page, $current_page);
$html = '';
foreach ($pages as $page) {
$page['text'] = str_replace(['prev', 'next'], ['«', '»'], $page['text']);
if (in_array($page['text'], ['«', '...', '»'])) {
$html .= '<li class="page-item">
<a class="page-link" href="' . (isset($page['number']) ? $base_url . $page['number'] : '#') . '">
<span aria-hidden="true">' . $page['text'] . '</span>
</a>
</li>';
} else {
$html .= '<li class="page-item' . ($page['number'] == $current_page ? ' active' : '')
. '"><a class="page-link" href="' . $base_url . $page['number'] . '">'
. $page['number'] . '</a></li>';
}
}
return str_replace('{{ @pages }}', $html, $pagination_template);
}
```
قوانین صفحهبندی بهشرح زیر هستند:
+ صفحات اول و آخر باید از طریق همهی صفحات در دسترس باشند.
+ دو صفحهی قبلی و دو صفحهی بعدی هر صفحه باید در دسترس باشند.
+ صفحاتی که فاصلهشان از صفحهی فعلی بزرگتر یا مساوی ۳ است با یک دکمهی `...` نمایش داده میشوند.
+ اگر فاصلهی دو صفحه از یکدیگر ۲ واحد باشد، به جای دکمهی `...` دکمهی شمارهی صفحهی بین آنها قرار میگیرد؛ برای مثال، بین دکمههای ۵ و ۷ هیچگاه دکمهی `...` نمیآید.
+ دکمهی `prev` باید در صورتی نمایش داده شود که شمارهی صفحهی فعلی ۱ نباشد.
+ دکمهی `next` باید در صورتی نمایش داده شود که شمارهی صفحهی فعلی برابر با تعداد صفحات نباشد.
**توجه:** ترتیب آرایههای خروجی تابع `getPaginationButtons` باید بهصورت زیر باشد:
+ دکمهی `prev` (در صورت وجود)
+ دکمهی شمارهی صفحات با ترتیب صعودی (میتواند شامل دکمهی `...` نیز باشد.)
+ دکمهی `next` (در صورت وجود)
### مثال ۱:
```php
<?php
require 'pagination.php';
getPaginationButtons(56, 5, 7);
/**
[
["text" => "prev", "number" => 6],
["text" => "1", "number" => 1],
["text" => "..."],
["text" => "5", "number" => 5],
["text" => "6", "number" => 6],
["text" => "7", "number" => 7],
["text" => "8", "number" => 8],
["text" => "9", "number" => 9],
["text" => "..."],
["text" => "12", "number" => 12],
["text" => "next", "number" => 8]
]
*/
$pagination_template = file_get_contents('pagination.tpl');
echo renderPagination($pagination_template, 56, 5, 7, 'index.php?page=');
```
خروجی مورد انتظار:

### مثال ۲:
```php
<?php
require 'pagination.php';
getPaginationButtons(14, 4, 1);
/**
[
["text" => "1", "number" => 1],
["text" => "2", "number" => 2],
["text" => "3", "number" => 3],
["text" => "4", "number" => 4],
["text" => "next", "number" => 2]
]
*/
$pagination_template = file_get_contents('pagination.tpl');
echo renderPagination($pagination_template, 14, 4, 1, 'index.php?page=');
```
خروجی مورد انتظار:

### مثال ۳:
```php
<?php
require 'pagination.php';
getPaginationButtons(40, 10, 4);
/**
[
["text" => "prev", "number" => 3],
["text" => "1", "number" => 1],
["text" => "2", "number" => 2],
["text" => "3", "number" => 3],
["text" => "4", "number" => 4]
]
*/
$pagination_template = file_get_contents('pagination.tpl');
echo renderPagination($pagination_template, 40, 10, 4, 'index.php?page=');
```
خروجی مورد انتظار:

### مثال ۴:
```php
<?php
require 'pagination.php';
getPaginationButtons(24, 3, 6);
/**
[
["text" => "prev", "number" => 5],
["text" => "1", "number" => 1],
["text" => "..."],
["text" => "4", "number" => 4],
["text" => "5", "number" => 5],
["text" => "6", "number" => 6],
["text" => "7", "number" => 7],
["text" => "8", "number" => 8],
["text" => "next", "number" => 7]
]
*/
$pagination_template = file_get_contents('pagination.tpl');
echo renderPagination($pagination_template, 24, 3, 6, 'index.php?page=');
```
خروجی مورد انتظار:

### مثال ۵:
```php
<?php
require 'pagination.php';
getPaginationButtons(7, 1, 2);
/**
[
["text" => "prev", "number" => 1],
["text" => "1", "number" => 1],
["text" => "2", "number" => 2],
["text" => "3", "number" => 3],
["text" => "4", "number" => 4],
["text" => "..."],
["text" => "7", "number" => 7],
["text" => "next", "number" => 3]
]
*/
$pagination_template = file_get_contents('pagination.tpl');
echo renderPagination($pagination_template, 7, 1, 2, 'index.php?page=');
```
خروجی مورد انتظار:

3. فایل `index.php`: این فایل توابع موجود در فایل `pagination.php` را فراخوانی کرده و از طریق آن میتوان خروجی بخش *pagination* را مشاهده کرد. محتوای آن بهصورت زیر است:
```php
<?php
require 'pagination.php';
$pagination_template = file_get_contents('pagination.tpl');
echo renderPagination($pagination_template, 7 * 5, 5, 2, 'index.php?page=');
```
## آنچه باید آپلود کنید
پس از پیادهسازی تابع `getPaginationButtons`، فایل `pagination.php` را آپلود کنید.
---
<details class="blue">
<summary>راهنمایی ۱</summary>
تعداد صفحات برابر خواهد بود با $\lceil\frac{\$total\_items}{\$per\_page}\rceil$:
```php
$pages_count = ceil($total_items/ $per_page);
```
</details>
<details class="blue">
<summary>راهنمایی ۲</summary>
آرایهای برای ذخیرهسازی دکمهها در نظر میگیریم:
```php
$buttons = [];
```
اگر تعداد صفحات بیشتر از ۱ باشد، دکمهی `prev` شمارهی `$current_page - 1` را اضافه میکنیم:
```php
if ($current_page > 1) {
$buttons[] = ['text' => 'prev', 'number' => $current_page - 1];
}
```
پس از اضافه کردن دکمههای شماره و `...` (در صورت نیاز)، اگر تعداد صفحات بیشتر از شمارهی صفحهی فعلی باشد، دکمهی `next` با شمارهی `$current_page + 1` را اضافه میکنیم:
```php
if ($current_page < $pages_count) {
$buttons[] = ['text' => 'next', 'number' => $current_page + 1];
}
```
</details>
<details class="blue">
<summary>راهنمایی ۳</summary>
میدانیم حداکثر دو دکمهی `...` در بین دکمهها موجود خواهند بود که یکی از این دکمهها در بین دکمههای سمت چپ دکمهی صفحهی فعلی و دیگری در بین دکمههای سمت راست دکمهی صفحهی فعلی خواهد بود. دو *flag* برای این دو دکمه در نظر میگیریم که هرگاه این دکمهها درج شوند، *flag* شان `true` میشود.
```php
$leftDots = false;
$rightDots = false;
```
پیمایش را از شمارهی ۱ تا تعداد صفحات انجام میدهیم. اگر مقدار شمارهی فعلی ۱ باشد، یا اختلاف آن با شمارهی صفحهی فعلی کمتر از ۳ باشد، یا مقدار شمارندهی فعلی برابر با تعداد صفحات باشد، دکمهای با مقدار شمارنده درج میکنیم.
در غیر اینصورت، اگر مقدار شمارنده کوچکتر از شمارهی صفحهی فعلی باشد و `$leftDots` برابر با `false` باشد، یک دکمهی `...` درج کرده و `$leftDots` را `true` میکنیم.
در غیر اینصورت، اگر مقدار شمارنده بزرگتر از شمارهی صفحهی فعلی باشد و `$rightDots` برابر با `false` باشد، یک دکمهی `...` درج کرده و `$rightDots` را `true` میکنیم.
کد این بخش بهصورت زیر خواهد بود:
```php
for ($i = 1; $i <= $pages_count; $i++) {
if ($i == 1 || abs($current_page - $i) <= 2 || $i == $pages_count) {
$buttons[] = ['text' => $i, 'number' => $i];
}
elseif ($i < $current_page && !$rightDots) {
$buttons[] = ['text' => '...'];
$rightDots = true;
}
elseif ($i > $current_page && !$leftDots) {
$buttons[] = ['text' => '...'];
$leftDots = true;
}
}
```
</details>
صفحهبندی
میلاد بهتازگی در دیجیکالا بهعنوان توسعهدهندهی junior استخدام شده است. اولین task ای که به او واگذار شده، بازنویسی بخش pagination وبسایت دیجیاستایل است. از آنجا که میلاد تجربهی انجام این کار را ندارد، از شما میخواهیم تا این بخش را برای او پیادهسازی کنید.
renderPagination: این تابع بهترتیب یک رشته حاوی قالب HTML ، تعداد مطالب موجود در وبسایت، حداکثر تعداد مطالب در هر صفحه، شمارهی صفحهی فعلی و لینک پایهی صفحات را دریافت میکند. در نهایت، بخش pagination را بهصورت یک رشته برمیگرداند.
getPaginationButtons: این تابع بهترتیب تعداد مطالب موجود در وبسایت، حداکثر تعداد مطالب در هر صفحه و شمارهی صفحهی فعلی را دریافت کرده و آرایهای شامل دکمهها جهت نمایش در بخش pagination را برمیگرداند. هر دکمه یک آرایهی associative است که شامل دو کلید text و number است. مقدار کلید text برای دکمهی رفتن به صفحهی قبلی prev و برای دکمهی رفتن به صفحهی بعدی next است. همچنین، مقدار کلید text برای دکمهی ... همان ... است. مقدار کلید number بیانگر شمارهی صفحهی موجود در لینک دکمه است؛ برای مثال اگر ۴ صفحه داشته باشیم و در حال حاضر در صفحهی ۳ باشیم، مقدار کلید number برای دکمههای prev و next بهترتیب برابر با 2 و 4 خواهد بود. بدیهی است که مقدار کلید number برای سایر دکمهها (بهجز دکمهی ...) باید برابر با مقدار کلید text باشد.
صفحات اول و آخر باید از طریق همهی صفحات در دسترس باشند.
دو صفحهی قبلی و دو صفحهی بعدی هر صفحه باید در دسترس باشند.
صفحاتی که فاصلهشان از صفحهی فعلی بزرگتر یا مساوی ۳ است با یک دکمهی ... نمایش داده میشوند.
اگر فاصلهی دو صفحه از یکدیگر ۲ واحد باشد، به جای دکمهی ... دکمهی شمارهی صفحهی بین آنها قرار میگیرد؛ برای مثال، بین دکمههای ۵ و ۷ هیچگاه دکمهی ... نمیآید.
دکمهی prev باید در صورتی نمایش داده شود که شمارهی صفحهی فعلی ۱ نباشد.
دکمهی next باید در صورتی نمایش داده شود که شمارهی صفحهی فعلی برابر با تعداد صفحات نباشد.
توجه: ترتیب آرایههای خروجی تابع getPaginationButtons باید بهصورت زیر باشد:
دکمهی prev (در صورت وجود)
دکمهی شمارهی صفحات با ترتیب صعودی (میتواند شامل دکمهی ... نیز باشد.)
فایل index.php: این فایل توابع موجود در فایل pagination.php را فراخوانی کرده و از طریق آن میتوان خروجی بخش pagination را مشاهده کرد. محتوای آن بهصورت زیر است:
پس از اضافه کردن دکمههای شماره و ... (در صورت نیاز)، اگر تعداد صفحات بیشتر از شمارهی صفحهی فعلی باشد، دکمهی next با شمارهی $current_page + 1 را اضافه میکنیم:
میدانیم حداکثر دو دکمهی ... در بین دکمهها موجود خواهند بود که یکی از این دکمهها در بین دکمههای سمت چپ دکمهی صفحهی فعلی و دیگری در بین دکمههای سمت راست دکمهی صفحهی فعلی خواهد بود. دو flag برای این دو دکمه در نظر میگیریم که هرگاه این دکمهها درج شوند، flag شان true میشود.
$leftDots=false;$rightDots=false;
PHP
پیمایش را از شمارهی ۱ تا تعداد صفحات انجام میدهیم. اگر مقدار شمارهی فعلی ۱ باشد، یا اختلاف آن با شمارهی صفحهی فعلی کمتر از ۳ باشد، یا مقدار شمارندهی فعلی برابر با تعداد صفحات باشد، دکمهای با مقدار شمارنده درج میکنیم.
در غیر اینصورت، اگر مقدار شمارنده کوچکتر از شمارهی صفحهی فعلی باشد و $leftDots برابر با false باشد، یک دکمهی ... درج کرده و $leftDots را true میکنیم.
در غیر اینصورت، اگر مقدار شمارنده بزرگتر از شمارهی صفحهی فعلی باشد و $rightDots برابر با false باشد، یک دکمهی ... درج کرده و $rightDots را true میکنیم.