Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Сделал для себя решение для того, чтобы убрать из пагинатора зеркало страницы /?page=1 (оно зеркалит /) и убрал вывод пустой страницы при запросе аля /?page=99999.
Выкладываю, чтобы вы покритиковали и сказали как можно было сделать проще и изящнее. В итоге буду не против, если кто-то выложит это в виде статьи, если я не сделаю этого в течении месяца после создания данной темы.
Изначально хотел просто подменить view (resources/views/vendor/pagination/default.blade.php), но уткнулся в то, что в LengthAwarePaginator нет метода для получения предыдущей страницы, есть только метод для получения url предыдущей страницы ($paginator->previousPageUrl()). Если пробовать разбирать через него, то это будет плохим способом, т.к. изначально пагинатор может выводиться на разных страницах, соответственно переписывать все пути - не кошерно.
Потом наткнулся на комментарий @FreeWebber и понял, что это можно сделать через наследования, придется только чуть-чуть поколдовать.
Пронаследовал Illuminate\Pagination\LengthAwarePaginator и изменил метод url() - сделал, чтобы при визите на любую страницу с ?page=X, где X > 1 - у первой страницы (page=1) не добавлялся GET-параметр "page=1":
<?php
namespace App\Utils;
use Illuminate\Support\Str;
use Illuminate\Pagination\LengthAwarePaginator;
class SEOFriendlyPaginator extends LengthAwarePaginator {
public function url($page)
{
if ($page <= 0) {
$page = 1;
}
$parameters = array();
if ($page > 1) {
$parameters = [$this->pageName => $page];
}
if (count($this->query) > 0) {
$parameters = array_merge($this->query, $parameters);
}
$url = $this->path;
$params_delimiter = (Str::contains($this->path, '?') ? '&' : '?');
$params_query = http_build_query($parameters, '', '&');
$fragment = $this->buildFragment();
if (!empty($params_query)) {
$url .= $params_delimiter . $params_query;
}
if (!empty($fragment)) {
$url .= $fragment;
}
return $url;
}
}
Затем в своем Controller использовал этот пагинатор и:
1. Сделал редирект с /?page=1 на /
2. Сделал вывод 404 ошибки, если каким-то образом у нас хотят получить страницу, которой не существует (аля /?page=99999)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Article;
use App\Utils\SEOFriendlyPaginator;
class SectionController extends Controller
{
public function home(Request $request) {
$per_page = config('project.per_page'); // добавил соответствующий конфиг
$page = $request->input('page');
$items = Article::filtered(); // здесь применяется мой собственный scope - filtered, это что-то вроде published, но с нужной мне сортировкой
$total = $items->count();
if (!is_null($page)) {
if ($page == 1) {
return redirect(route('home'), 301); // здесь я делаю редирект на роут 'home', не придумал как сделать редирект через $request
}
if ($page > ceil($total / $per_page)) {
abort(404);
}
} else {
$page = 1;
}
$items = $items->skip(($page - 1) * $per_page)->take($per_page)->get(); // берем только нужные элементы
$items = new SEOFriendlyPaginator($items, $total, $per_page, $page);
return view('sections.index', [
'items' => $items
]);
}
}
И в дальнейшем во view я теперь делаю:
@foreach ($items as $item)
{{-- вывод каждого элемента --}}
@endforeach
{{-- Вывод пагинатора --}}
{{ $items->links() }}
Всё. Как уже и писал выше - предложения, критика и советы - приветствуются!
Изменено Lord_Alfred (16.04.2017 23:09:33)
Не в сети
Хм. Столкнулся с тем, что мой пагинатор корректно работает только для /. В категориях он уже не знает о правильном пути, что странно (в пагинации всегда /?page=X, а не /category?page=X, как подразумевается).
Я думал, что в нём $this->path уже подразумевает "разруливание" таких ситуаций. Пойду думать как проще всего это обойти без костылей, если не напишу решения - буду благодарен за совет.
-----------
UPD:
Инициализацию пагинатора в контроллере следует сменить с:
new SEOFriendlyPaginator($items, $total, $per_page, $page);
на
new SEOFriendlyPaginator($items, $total, $per_page, $page, ['path' => $request->getPathInfo()]);
-----------
UPD2:
Тогда и редирект можно сменить
с
return redirect(route('home'), 301);
на
return redirect($request->getPathInfo(), 301);
Изменено Lord_Alfred (16.04.2017 23:25:25)
Не в сети
UPD3:
Чтобы предотвратить зеркало /?page=0 и убрать возможность заходить на страницы с page < 0, нужно в контроллере изменить
if ($page > ceil($total / $per_page)) {
На:
if (($page > ceil($total / $per_page)) || ($page < 1)) {
Не в сети
Опубликовал в виде статьи: https://laravel.ru/posts/768
Надеюсь, что здесь приветствуется такое
Не в сети