Laravel по-русски

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

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

#1 14.03.2018 03:31:30

Хорошие практики - фильтры для товаров

Доброго времени суток!
Знаком с ларавел примерно 2 месяца, поэтому сразу прошу камнями не бросаться и обьяснить чайнику (мне) что к чему.
Последний месяц пишу API-приложение. Писал я себе не очем не задумываясь, а потом заметил, что у меня некоторые методы в контролере очень жырные.
И здесь я задумался о рефакторинге кода. Начинал искать разные примеры, литературу и так далее. Наткнулся на ваш замечательный форум и решил поспрашывать опытних людей поделиться умом-разумом.
Лучше всего понимаю на примерах, поэтому хочу попросить обьяснить мне на одном с моих методов.

Суть в следующем:
У меня есть метод который возвращает список товаров. Дальше, надо сделать возможным применять к ним фильтры.
Есть следующие фильтры: category, shop, price, sizes, colors и order_column, order_direction. И самое главное я могу попробовать получить товары только по одному фильтру или по нескольким или по всем сразу.
При изучении моей проблемы наткнулся на такие понятия как паттерн репозиторий и сервисы. Судя по тому, что я использую Eloquent, репозитории мне не подходят, а вот насчет сервисов я заинтересовался (на них хорошых примеров не нашел). Но как использовать эти сервисы? Что туда выносить? И как их правильно использовать?

Также, уже понял, что все запросы можно вынести в модель (аля fat model, skiny controller). Но, как избавиться от всех этих if'ов и максимально сделать код читабельным? Ведь некоторые параметры могут прийти, а некоторые нет.
Также хотелось спросить за вынесенеи валидации в Form Request, как это сделать к параметрам которые содержаться в URI:
(пример: example.com/api/products?category=2&shop=4&order_column=created_at&order_direction=desc), тобиш праметры находяться в ссылке.

Вот собственно код метода:

public function index()
    {
        $validator = $this->validateParams(request()->all());
        if ($validator->fails()) {
            return response()->json(['message' => 'wrong_filters'], 422);
        }
        $whereInFilters = request()->only('sizes', 'colors');
        $products = Product::with('colors', 'sizes', 'currency', 'images');

        if (request()->has('shop')) {
            $products->where("shop_id", request('shop'));
        }
        if (request()->has('category')) {
            $categoryModel = Category::find(request('category'));
            $categories = $categoryModel->descendants()->pluck('id');
            $categories[] = $categoryModel->getKey();
            $products->whereIn('category_id', $categories);
        }

        foreach ($whereInFilters as $filter => $value) {
            $products->whereHas($filter, function ($query) use ($filter, $value) {
                $query->whereIn("{$filter}.id", json_decode($value));
            });
        }

        if (request()->has('price')) {
            $products->whereBetween('price', json_decode(request('price')));
        }

        if (request()->has('order_column')) {
            $products->orderBy(request('order_column'), request('order_direction'));
        }

        $products = $products->paginate(request()->has('per_page') ? request('per_page') : null);
        return response()->json($products, 200);
    }

    /**
     * Validate path params
     *
     * @param $params
     * @return \Illuminate\Validation\Validator
     */
    public function validateParams($params)
    {
        $validator = Validator::make($params, [
            'shop' => 'integer|exists:shops,id',
            'category' => 'integer|exists:categories,id',
            'sizes' => 'json|size:2',
            'sizes.*' => 'integer',
            'colors' => 'json',
            'colors.*' => 'integer',
            'price' => 'json',
            'order_column' => 'required_with:order_direction|string',
            'order_direction' => 'required_with:order_column|in:asc,desc',
        ]);

        return $validator;
    }

Буду очень благодарен если поможете неопытному новичку своими советами)

Не в сети

#2 14.03.2018 20:45:33

Re: Хорошие практики - фильтры для товаров

Дружище, привет.

по вопросу валидации - ты можешь легко вынести ее в FormRequest, так как все Get параметры точно так же доступны в Request как и Post параметры. То есть ты можешь делать $request->shop, $request->category. ну или $this->category, $this->shop если уже в FormRequest классе.

Это раз.

По поводу рефакторинга. очень хороший вопрос и проблема весьма и весьма распространенная. когда контроллер превращается в вермишель изза большого кол-ва проверок на входящие параметры. я не смогу тебе щас тут это расписать, ибо займет много времени и места. лучше погляди мои видео, где я пишу бэкенд для апи для своего стартапа (ссылка в подписи), я там уделяю большое внимание рефакторингу и best practices. и я сделаю видео на эту тему, где хорошо ее смогу осветить (спасибо за идею кстати).

А пока можешь зарефачить валидацию, это уже будет что-то. так же валидация в FormRequeste будет возвращать и список ошибок, что тоже существенный плюс.
ну и кстати, если уж и не использовать форм реквест, то используй метод validate() который зашит в сам Request. $request->validate(['shop'=> 'integer'...]); он также позволит тебе не заботиться о Response и об возвращаемых ошибках


Пишу бэкенд для своего мобильного приложения, делюсь с миром, заходите посмотреть, много всего интересного https://youtu.be/C5M6-ycJ5gs

Не в сети

#3 19.03.2018 21:38:57

Re: Хорошие практики - фильтры для товаров

привет, записал видео на эту тему, должно прояснить https://youtu.be/E7P4wf0hPwM


Пишу бэкенд для своего мобильного приложения, делюсь с миром, заходите посмотреть, много всего интересного https://youtu.be/C5M6-ycJ5gs

Не в сети

#4 07.04.2018 01:42:57

Re: Хорошие практики - фильтры для товаров

Спасибо, видосик заценил. Очень в тему! Хотелось бы увидеть от вас побольше видосиков по теме рефакторинга)

Не в сети

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