Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 22.10.2012 20:48:06

Vertex

Часть роутинга.

Вечер добрый.

Столкнулся с такой непонятной проблемой в роутинге. Суть такова:

  • controller: home;
  • action: index;

Пагинация стандартная это просто SEO-шный ужас, поэтому переработана на свою, которая генерирует ссылки типа:

  • page-(:num)
  • sort-(:any)

И все бы было замечательно если бы не одно «но» с роутингом. Сначала к примеру человек может отсортировать данные, и получится ссылка типа: 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 описывается что частичная обработка роута возможна, но почему-то не отрабатывает нечто подобное:

PHP
Route::get('/sort-(:any)',function($sort){
  
// Да, кстати, а куда эта хрень передается? :)
  // А то я новенький в Laravel... :)
});
Route::get('/page-(:num)',function($page){
});
Route::get('/search-(:any)',function($search){
});
Route::get('home''home@index');

#2 22.10.2012 22:24:42

Vertex

Re: Часть роутинга.

Как вариант был сделан вот такой роутинг, работает, сцуко, но блин, пахнет реально быдлокодом, и думаю что это не TRUE WAY…

В роуте:

PHP
  Route::get('home(/(:all))?''home/index');

В контроллере:
Для выбора сортировки

PHP
$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
<?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$textcompact('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) и подключить свой бандл. Этот момент, разработчики не учли. Нельзя жестко пришивать компоненты ядра, ядро ОБЯЗАНО расширяться полностью внешними файлами, иначе при апдейте на новую версию будут реально проблемы. Вобщем, как-то грустно так из-за этого стало…

#3 23.10.2012 15:32:17

Re: Часть роутинга.

Нда, а URL никак нельзя поменять на нормальные? Если page-N ещё можно понять, то search-X и sort-Y уже даже не просто anti-SEO, а anti-human. Такие вещи должны идти после ? в URL.

  1. Да, кстати, а куда эта хрень передается? ☺

Что именно? Параметр? Всё, что в скобках в URL ((:any)) передаётся в маршрут (у тебя это PHP$sort) или в контроллер (home@index).

Не в сети

#4 23.10.2012 18:12:46

Vertex

Re: Часть роутинга.

примеры URL я указал как примерные. Не важно там sort или там будет какая-то SEO-шная информация, например:
localhost/laravel/cars/audi/a4/page4/
"Search" так же будет вынесен за "?", но могут возникать различные ситуации, поэтому сразу же пытаюсь охватить все возможные при разборке фреймворка. Необходимо же знать какие существуют камни. smile
В любом случае page-num нельзя выносить за пределы, это однозначно.

Но в любом случае, вопрос так и не разрешен пока что, есть ли возможность выдергивать в роуте часть данных по какому-то параметру? И если это возможно и у меня в блоке он указан корректно, то может кто-то сталкивался, может есть какие-то предположения, почему оно не отрабатывает так как нужно?

#5 23.10.2012 20:14:26

Re: Часть роутинга.

Если URL такой хитрый, то нужно его парсить перед вызовом какого-нибудь контроллера или маршрута — примерно как у тебя это уже делается. Если компоненты в URL могут идти в любом порядке, то нужна одна регулярка на компонент (как у тебя), если есть определённый порядок — можно одной на всех обойтись. По твоему коду в контроллере есть только два замечания:

  1. URL можно получить через PHPURI::current()
  2. Не знаю, как у тебя используется PHP$sort, но я бы для совместимости со стандартными классами после разбора URL вставил бы параметры в текущий запрос: PHPInput::merge(array('page' => matched_page'sort' => ...)). Это аналогично тому, как если бы страница была запрошена как ?page=X&sort=Y&....

Не в сети

#6 23.10.2012 23:09:00

Vertex

Re: Часть роутинга.

Спасибо, вобщем будем пробовать... и искать новые косяки... smile

#7 24.10.2012 02:04:39

Vertex

Re: Часть роутинга.

  1. Не знаю, как у тебя используется PHP$sort, но я бы для совместимости со стандартными классами после разбора URL вставил бы параметры в текущий запрос: PHPInput::merge(array('page' => matched_page'sort' => ...)). Это аналогично тому, как если бы страница была запрошена как ?page=X&sort=Y&....

Так как стандартный вовсе не является приемлимым (хотя бы по тому же параметру «page»), то не вижу прямой необходимости передавать лишние параметры. А вот, то что данный модуль (\Laravel\Paginator) является жестко зашитым, и не имеет возможности расширения, то это надеюсь что разработчики пофиксят. Пока что же, этот момент я выделил в bundle ибо не добрался пока что к либам, да и расширять буду пагинатор (оптимизация запроса часто бывает необходимой).

Подвал раздела