Использование 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 или более фильтров в любой комбинации. Будет немного сложнее, если вы окажетесь в ситуации, когда вы можете фильтровать по комбинациям групп. Даже если вы можете разделить комбинации на отдельные блоки и добиться примерно одинаковых результатов.
Итак, еще раз, я думаю, что то, что у вас есть в первой части вашего вопроса, совершенно правильно, но я бы предложил код из второй части вопроса в качестве более чистого и более удобного в обслуживании варианта.