Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Страницы 1
Столкнулся с такой непонятной проблемой в роутинге. Суть такова:
Пагинация стандартная это просто SEO-шный ужас, поэтому переработана на свою, которая генерирует ссылки типа:
И все бы было замечательно если бы не одно «но» с роутингом. Сначала к примеру человек может отсортировать данные, и получится ссылка типа: http://localhost/home/sort-id/
Затем может перейти на другую страницу: http://localhost/home/sort-id/page-2/
А потом убрать сортировку: http://localhost/home/page-3/
А потом добавить сортировку: http://localhost/home/page-3/sort-id/
А еще может быть добавлен параметр: /search#id=13&age=54/ причем добавлен он может быть как в самом начале, так и в самом конце.
Отсюда следует что хотелось бы составить частичный роутинг, который бы опирался не на нумерационную часть в распарсенном REQUEST_URI, а все-таки на название. Т.е. что если есть /sort-(:any) — значит вернуть в $_GET или куда-то туда переменную $sort. При всем при этом в документации к Laravel описывается что частичная обработка роута возможна, но почему-то не отрабатывает нечто подобное:
Route::get('/sort-(:any)',function($sort){
// Да, кстати, а куда эта хрень передается? :)
// А то я новенький в Laravel... :)
});
Route::get('/page-(:num)',function($page){
});
Route::get('/search-(:any)',function($search){
});
Route::get('home', 'home@index');
Как вариант был сделан вот такой роутинг, работает, сцуко, но блин, пахнет реально быдлокодом, и думаю что это не TRUE WAY…
Route::get('home(/(:all))?', 'home/index');
В контроллере:
Для выбора сортировки
$sort['sort'] = (preg_match('/\/sort-([a-z0-9]+)/', $_SERVER['REQUEST_URI'], $m)) ? $m[1] : false;
$sort['sort_direction'] = (preg_match('/\/sort-'.$sort['field'].'-([asc|desc]+)/', $_SERVER['REQUEST_URI'], $m)) ? $m[1] : 'asc';
И собственно форк Paginator’a:
<?php namespace MyPaginator;
use Laravel\URI;
use Laravel\HTML;
use Laravel\Request;
use Laravel\Lang;
class Paginator extends \Laravel\Paginator {
public static function page($total, $per_page)
{
$page = (preg_match('/\/page-([0-9]+)/', $_SERVER['REQUEST_URI'], $m)) ? $m[1] : 1;
if (is_numeric($page) and $page > $last = ceil($total / $per_page))
{
return ($last > 0) ? $last : 1;
}
return (static::valid($page)) ? $page : 1;
}
protected function link($page, $text, $class)
{
$current = preg_replace('/\/page-([0-9]+)/', '', URI::current());
$query = '/page-'.$page.'/'; // Crop for sort ".$this->appendage($this->appends);"
// return HTML::link($current.$query, $text, compact('class'), Request::secure());
return '<li'.HTML::attributes(array('class'=>"{$class} disabled")).'>'.
HTML::link($current.$query, $text, compact('class'), Request::secure())
.'</li>';
}
/**
* Create a chronological pagination element, such as a "previous" or "next" link.
*
* @param string $element
* @param int $page
* @param string $text
* @param Closure $disabled
* @return string
*/
protected function element($element, $page, $text, $disabled)
{
$class = "{$element}_page";
if (is_null($text))
{
$text = Lang::line("pagination.{$element}")->get($this->language);
}
// Each consumer of this method provides a "disabled" Closure which can
// be used to determine if the element should be a span element or an
// actual link. For example, if the current page is the first page,
// the "first" element should be a span instead of a link.
if ($disabled($this->page, $this->last))
{
return '<li'.HTML::attributes(array('class'=>"{$class} disabled")).'><a href="#">'.$text.'</a></li>';
}
else
{
return $this->link($page, $text, $class);
}
}
}
Но так как пагинатор жестко зашит в класс \Laravel\Database, пришлось отключить внаглую (хотя, наверное, более правильно было бы заменить core и \Laravel\Database) и подключить свой бандл. Этот момент, разработчики не учли. Нельзя жестко пришивать компоненты ядра, ядро ОБЯЗАНО расширяться полностью внешними файлами, иначе при апдейте на новую версию будут реально проблемы. Вобщем, как-то грустно так из-за этого стало…
Нда, а URL никак нельзя поменять на нормальные? Если page-N ещё можно понять, то search-X и sort-Y уже даже не просто anti-SEO, а anti-human. Такие вещи должны идти после ? в URL.
- Да, кстати, а куда эта хрень передается?
Что именно? Параметр? Всё, что в скобках в URL ((:any)) передаётся в маршрут (у тебя это PHP$sort
) или в контроллер (home@index).
Не в сети
примеры URL я указал как примерные. Не важно там sort или там будет какая-то SEO-шная информация, например:
localhost/laravel/cars/audi/a4/page4/
"Search" так же будет вынесен за "?", но могут возникать различные ситуации, поэтому сразу же пытаюсь охватить все возможные при разборке фреймворка. Необходимо же знать какие существуют камни.
В любом случае page-num нельзя выносить за пределы, это однозначно.
Но в любом случае, вопрос так и не разрешен пока что, есть ли возможность выдергивать в роуте часть данных по какому-то параметру? И если это возможно и у меня в блоке он указан корректно, то может кто-то сталкивался, может есть какие-то предположения, почему оно не отрабатывает так как нужно?
Если URL такой хитрый, то нужно его парсить перед вызовом какого-нибудь контроллера или маршрута — примерно как у тебя это уже делается. Если компоненты в URL могут идти в любом порядке, то нужна одна регулярка на компонент (как у тебя), если есть определённый порядок — можно одной на всех обойтись. По твоему коду в контроллере есть только два замечания:
PHPURI::current()
PHP$sort
, но я бы для совместимости со стандартными классами после разбора URL вставил бы параметры в текущий запрос: PHPInput::merge(array('page' => matched_page, 'sort' => ...))
. Это аналогично тому, как если бы страница была запрошена как ?page=X&sort=Y&....Не в сети
Спасибо, вобщем будем пробовать... и искать новые косяки...
- Не знаю, как у тебя используется
PHP$sort
, но я бы для совместимости со стандартными классами после разбора URL вставил бы параметры в текущий запрос:PHPInput::merge(array('page' => matched_page, 'sort' => ...))
. Это аналогично тому, как если бы страница была запрошена как ?page=X&sort=Y&....
Так как стандартный вовсе не является приемлимым (хотя бы по тому же параметру «page»), то не вижу прямой необходимости передавать лишние параметры. А вот, то что данный модуль (\Laravel\Paginator) является жестко зашитым, и не имеет возможности расширения, то это надеюсь что разработчики пофиксят. Пока что же, этот момент я выделил в bundle ибо не добрался пока что к либам, да и расширять буду пагинатор (оптимизация запроса часто бывает необходимой).
Страницы 1