Использование eloquent при фильтрации данных без избыточности

Я пытаюсь фильтровать данные через Eloquent в методе, который отвечает только на запросы AJAX, а затем возвращает представление вместе с отфильтрованными данными. Однако у меня есть вопрос:

Во-первых, давайте посмотрим на мой код:

public function AJAX_get_reports(Request $request)
{
    if($request->ajax())
    {
        $message = $request->get('message');
        $severity = $request->get('severity');

        if(strlen($message) > 0 && strlen($severity) > 0 )
        {
            $data = ServerReport::where('severity', '=', $severity)->where('message', '=', $message)->get();
        } elseif (strlen($message) > 0) {
            $data = ServerReport::where('message', '=', $message)->get();
        } elseif (strlen($severity) > 0) {
            $data = ServerReport::where('severity', '=', $severity)->get();
        } else {
            $data = ServerReport::all();
        }
        return Response::json(View::make('dashboard.reports.index', compact('data'))->render());

    }
}

Это был единственный способ, которым я смог это сделать, это работает, но я чувствую, что это не лучший способ сделать это, особенно если у вас есть больше полей для фильтрации, код будет принимать огромные пропорции с проверками, есть ли лучший способ сделать это?

Например, создать запрос во время проверки, а затем запустить его в конце?

if(strlen($message) > 0)
{
    // add WHERE to query
}
if(strlen($severity) > 0)
{
    // add WHERE to query
}

// Execute query and get the results

2 ответа

Решение

На мой взгляд, ваш код может быть упрощен так:

public function AJAX_get_reports(Request $request) {
    if($request->ajax()) {
        $message = $request->get('message');
        $severity = $request->get('severity');
        $report = ServerReport::select('*'); //Initiate the variable for query container, change * to the columns that needs to be returned or just leave it

        if (strlen($message) > 0) {
            $report->where('message', '=', $message); //Add message filter
        }

        if (strlen($severity) > 0) {
            $report->where('severity', '=', $severity); //Add severity filter
        }

        //Add another filters if needed

        $data = $report->get(); //Get the data from either the filtered data or every single data without any filters

        return Response::json(View::make('dashboard.reports.index', compact('data'))->render());
    }
}

Я использовал этот метод для некоторых проектов в моей компании, и все работает отлично. Дать ему шанс.

Я не уверен, что есть лучший способ сделать это, учитывая, что то, что вы создали в своем исходном коде, выглядит для меня вполне приемлемым, но, безусловно, есть варианты. Например, если у вас есть предложения WHERE, которые вы используете регулярно, вы можете использовать области действия для централизации условных построений, которые направлены на достижение определенного результата, и при необходимости составлять их. Это дает вам гибкость в будущем, чтобы изменить одно место в коде и повлиять на все остальные места, где использовалась обновленная область, в случае, если ваше условие должно быть изменено. Но это может быть больше связано с более крупными проблемами поддержки кода, чем, я думаю, вы могли бы искать в этом конкретном случае.

Лично я немного использовал ваш гипотетический метод. Это прекрасно работает для меня, когда у меня есть конечная точка API для фильтруемого ресурса, а фильтры могут быть переменными. Поиск пользователей по любой комбинации имени, фамилии и / или электронной почты, например.

Вот как это выглядит для меня:

public function getIndex(Request $request, Response $response)
{
    //Start with a copy of the model
    //I prefer to instantiate the class from the container,
    //instead of having it auto-injected using the method signature
    //just personal preference
    $users = app('App\User');

    //Filter by first name
    if ($request->has('first_name')) {
        $users->where('first_name', $request->input('first_name'));
    }

    //Filter by last name
    if ($request->has('last_name')) {
        $users->where('last_name', $request->input('last_name'));
    }

    //Filter by email
    if ($request->has('email')) {
        $users->where('email', $request->input('email'));
    }

    //If no conditions were set, get() *should* function like all()
    $data = $users->get();

    //Do what you need with the data from here on out
    //Typically I paginate the results for something like this
}

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

Один большой недостаток этого подхода заключается в том, что каждый фильтр действует независимо от других - выберите 0 или более фильтров в любой комбинации. Будет немного сложнее, если вы окажетесь в ситуации, когда вы можете фильтровать по комбинациям групп. Даже если вы можете разделить комбинации на отдельные блоки и добиться примерно одинаковых результатов.

Итак, еще раз, я думаю, что то, что у вас есть в первой части вашего вопроса, совершенно правильно, но я бы предложил код из второй части вопроса в качестве более чистого и более удобного в обслуживании варианта.

Другие вопросы по тегам