Конструктор запросов Laravel. Как сделать запрос короче?

#laravel #laravel-query-builder

#laravel #laravel-конструктор запросов

Вопрос:

Мне нужно подготовить данные для таблиц данных, и мне нужно подсчитать общее количество отфильтрованных данных запроса, но я не могу сделать это только с одним запросом из-за ограничения, поэтому я должен выполнить почти тот же запрос, но без опции ограничения для разбивки на страницы, и это увеличивает объем моего кода в 2 раза. Возможно ли сделать этот код короче и красивее?

 public function data($request)
{
    $staff = auth()->user();
    $role = Role::find($staff->role_id)->alias;
    $isAdmin = $role == 'admin';

    $columns = ['id', 'name', 'shop', 'hash', 'status'];

    $limit = $request->input('length');
    $start = $request->input('start');
    $order = $columns[$request->input('order.0.column')];
    $directions = $request->input('order.0.dir');
    $searchValue = $request->input('search.value');

    $filters = explode(',', $request->input('columns.7.search')['value']);
    foreach ($filters as $key => $value) {
        if ($value !== "") {
            array_push($shops, $value);
        }
    }
    if ($searchValue) $filters[] = $searchValue;

    $nfcs = NfcMark::offset($start)->select('nfc_marks.*')
        ->leftJoin('shops as s', 's.id', 'nfc_marks.shop_id')
        ->when(!$isAdmin, function ($q) {
            $shop_ids = $this->shopRepository->shopsIdsByOwner(auth()->user()->id);
            return $q->whereIn('shop_id', $shop_ids);
        })
        ->when($searchValue, function ($q) use ($filters) {
            foreach ($filters as $filter) {
                $q->orWhere('shops.name', 'LIKE', '%' . $filter . '%');
            }
        })
        ->limit($limit)
        ->orderBy($order, $directions)
        ->get();

    $nfcs_count = NfcMark::query()
        ->leftJoin('shops as s', 's.id', 'nfc_marks.shop_id')
        ->when(!$isAdmin, function ($q) {
            $shop_ids = $this->shopRepository->shopsIdsByOwner(auth()->user()->id);
            return $q->whereIn('shop_id', $shop_ids);
        })
        ->when($searchValue, function ($q) use ($filters) {
            foreach ($filters as $filter) {
                $q->orWhere('shops.name', 'LIKE', '%' . $filter . '%');
            }
        })->get();

    $totalFiltered = count($nfcs_count);
    $totalData = $totalFiltered;

    $data = array();

    if (!empty($nfcs)) {
        foreach ($nfcs as $item) {
            $nestedData['id'] = $item->id;
            $nestedData['name'] = $item->name;
            $nestedData['shop'] = $item->shop_id;
            $nestedData['hash'] = $item->hash;
            $nestedData['status'] = $item->status;

            $data[] = $nestedData;
        }
    }

    $json_data = array(
        "draw" => intval($request->input('draw')),
        "recordsTotal" => intval($totalData),
        "recordsFiltered" => intval($totalFiltered),
        "data" => $data
    );

    return json_encode($json_data);

}
  

Ответ №1:

Вы можете сохранить ту часть запроса, которая совпадает между ними, как конструктор, и запустить из него оба запроса, если вы чувствуете, что вам нужны оба этих запроса:

 $query = NfcMark::leftJoin('shops as s', 's.id', 'nfc_marks.shop_id')
    ->when(!$isAdmin, function ($q) {
        $q->whereIn(
            'shop_id',
            $this->shopRepository->shopsIdsByOwner(auth()->user()->id)
        );
    })
    ->when($searchValue, function ($q) use ($filters) {
        foreach ($filters as $filter) {
            $q->orWhere('shops.name', 'LIKE', '%' . $filter . '%');
        }
    });


$nfcs_count = $query->get();

$nfcs = $query->select('nfc_marks.*')
    ->offset($start)
    ->limit($limit)
    ->orderBy($order, $directions)
    ->get();
  

Вы также можете получить количество, не возвращая строки и просто используя count() вместо get()

Ответ №2:

Вы можете использовать clone для дублирования запроса, а затем запустить его с другими операторами where.

 $query1 = NfcMark::query()
        ->leftJoin('shops as s', 's.id', 'nfc_marks.shop_id')
        ->when(!$isAdmin, function ($q) {
            $shop_ids = $this->shopRepository->shopsIdsByOwner(auth()->user()->id);
            return $q->whereIn('shop_id', $shop_ids);
        })
        ->when($searchValue, function ($q) use ($filters) {
            foreach ($filters as $filter) {
                $q->orWhere('shops.name', 'LIKE', '%' . $filter . '%');
            }
        })

$query2 = clone $query1;


$nfcs_count = $query1->get() //or $query1->count();
$$nfcs = $query2
        ->limit($limit)
        ->orderBy($order, $directions)
        ->get();