crashxd
@crashxd
Backend разработчик

Как лучше всего реализовать сортировку через get параметры?

Делаю API на Laravel.
Встала задача отдавать результаты частями (limit, offset) и с указанной сортировкой (direction, column).

Для пагинации через offset-limit использую пакет, который позволяет мне вместо стандартной пагинации Model::paginate(), вызывать пагинацию Model::offsetPaginate(). Работает через get параметры, добавляет в json meta информацию о текущей пагинации, всё как нужно.

Осталось только добавить сортировку с похожими требованиями.
Понятное дело у моделей есть функция orderBy() и её нужно вызывать перед вызовом offsetPaginate(). Но есть две нерешенные проблемы:
1. У orderBy() нет значений по умолчанию.
2. orderBy() не проверяет переданное название поля (если такого поля в таблице нет, выдаст ошибку, а хотелось бы сортировать в этом случае по полю по умолчанию).
2. Информация о текущей сортировки не добавляется к json.

Думаю над такими вариантами решения:
1. Добавить к классу модели свою функцию customOrderBy() в которой добавить значения по умолчанию, если сортировка не указана в get.
2. Добавить в модель список разрешенных для сортировки полей и в customOrderBy() проверять переданное название поля.
3. В resource API добавить в функцию with информации о сортировке.

Что подскажите?
  • Вопрос задан
  • 845 просмотров
Решения вопроса 1
@jazzus
Laravel Resource тоже добавляет в мета пагинацию со стандартным paginate(). В чем точно проблема не понял. Я делаю фильтрацию с помощью модуля
class Filter
{
  protected $builder;
  protected $request;

  public function __construct($builder, $request)
  {
    $this->builder=$builder;
    $this->request=$request;
  }

  public function run()
  {
        foreach ($this->request->all() as $filter => $value)
        {
          if (method_exists($this, $filter) and !empty($value))
          {
            $this->$filter($value);
          }
        }
        return $this->builder;
  }

//------------------Фильтры-----------------------------------

  private function name($value)
  {
     $this->builder->where('name', 'like', "%$value%");
  }

  private function type_id($value)
  {
     $this->builder->where('type_id', $value);
  }
}

модуль получает билдер и реквест из контроллера. Затем перебирает данные реквеста и если название метода класса совпадает с названием из реквеста то он обновляет билдер и в финале возвращает отфильтрованный билдер. Т.е. название методов фильтрации должны совпадать с названиями из реквеста.

Затем сортировку через переменные.
->orderBy($field, $metod);
Для сортировки создал модель Sorting где есть поле code с названиями полей сортируемых моделей типа updated_at или lists_count (для отношений withCount). Это передается в orderBy и сортируется. Т.е. вначале строится билдер, затем сортировка и пагинация. Все что получилось в итоге отдаю обратно через ресурс типа
return ProductResource::collection($products);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
theemfs
@theemfs
Кратко о себе
GET /handler?param1=value&sort=model:asc,model2:desc&...
в контроллере разбираешь параметры и строишь запрос
указанные условия, если они есть в реквесте, дефолты - если нет
валидация обязательна

если нет значений по-умолчанию и чего там не хватает - всё создать самому
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы