Laravel5.6, 5.7の管理画面パッケージ「Voyager」。このパッケージはかなり便利ですが、データ数が多くなると、ページ読み込みがかなり重くなります。
5秒以上待たされることも多いので、データ数が多くなるようなサイトでは、ちょっと使いづらいです。
この現象はBread画面を表示する時データを全件取得、さらにリレーションがある場合そのクエリも1データごとに発行して、、、とやっているからのようです。
画像は以前の記事で100件のテストデータを入れたProductsページです。121のクエリが発行されています。このうち100クエリはproduct-tag間のリレーションクエリです。
流石にこのままだと実用に難があるのでサーバーサイドでのペジネーションに変更します(今回はこのままProductsページを対象とします)。
/admin/bread/products/editに移動し、BREAD info のServer-side Paginationを「Yes」に
変更してください。(基本やることはこれだけです)
Productsページのテーブル上部、検索欄が変化し、クエリが121件か37件に変化しました。
表示速度も気にならないくらいに変化しました(10秒位から1秒行かないくらいに)。
ちなみに、コントローラー内での処理はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public function index(Request $request) { //色々あって $search = (object) ['value' => $request->get('s'), 'key' => $request->get('key'), 'filter' => $request->get('filter')]; $searchable = $dataType->server_side ? array_keys(SchemaManager::describeTable(app($dataType->model_name)->getTable())->toArray()) : ''; $orderBy = $request->get('order_by'); $sortOrder = $request->get('sort_order', null); if (strlen($dataType->model_name) != 0) { $relationships = $this->getRelationships($dataType); $model = app($dataType->model_name); $query = $model::select('*')->with($relationships); $this->removeRelationshipField($dataType, 'browse'); // ここからserver-side paginationでの検索条件 if ($search->value && $search->key && $search->filter) { $search_filter = ($search->filter == 'equals') ? '=' : 'LIKE'; $search_value = ($search->filter == 'equals') ? $search->value : '%'.$search->value.'%'; $query->where($search->key, $search_filter, $search_value); } if ($orderBy && in_array($orderBy, $dataType->fields())) { $querySortOrder = (!empty($sortOrder)) ? $sortOrder : 'DESC'; $dataTypeContent = call_user_func([ $query->orderBy($orderBy, $querySortOrder), $getter, ]); } elseif ($model->timestamps) { $dataTypeContent = call_user_func([$query->latest($model::CREATED_AT), $getter]); } else { $dataTypeContent = call_user_func([$query->orderBy($model->getKeyName(), 'DESC'), $getter]); } // Replace relationships' keys for labels and create READ links if a slug is provided. $dataTypeContent = $this->resolveRelations($dataTypeContent, $dataType); // ここまで } else { |
=とかcontains、idとかを選択するのが面倒なので、「name」のLIKE検索にしてしまいましょう。
/vendor/tcg/voyager/resource/views/bread/browse.blade.php内の検索用入力欄はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@if ($isServerSide) <form method="get" class="form-search"> <div id="search-input"> <select id="search_key" name="key"> @foreach($searchable as $key) <option value="{{ $key }}" @if($search->key == $key){{ 'selected' }}@endif>{{ ucwords(str_replace('_', ' ', $key)) }}</option> @endforeach </select> <select id="filter" name="filter"> <option value="contains" @if($search->filter == "contains"){{ 'selected' }}@endif>contains</option> <option value="equals" @if($search->filter == "equals"){{ 'selected' }}@endif>=</option> </select> <div class="input-group col-md-12"> <input type="text" class="form-control" placeholder="{{ __('voyager::generic.search') }}" name="s" value="{{ $search->value }}"> <span class="input-group-btn"> <button class="btn btn-info btn-lg" type="submit"> <i class="voyager-search"></i> </button> </span> </div> </div> </form> @endif |
これを変えちゃいましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@if ($isServerSide) <form method="get" class="form-search"> <div id="search-input"> <input type="hidden" name="key" value="name"> <input type="hidden" name="filter" value="contains"> <input type="text" class="form-control" placeholder="{{ __('voyager::generic.search') }}" name="s" value="{{ $search->value }}"> <span class="input-group-btn"> <button class="btn btn-info btn-lg" type="submit"> <i class="voyager-search"></i> </button> </span> </div> </form> @endif |
これで「name」のLIKE検索になりました。
その他の条件を追加したいときはController内で検索条件を整形してください。(コメントのここから〜ここまでの中でいい感じに)
※VoyagerBaseControllerやbrowse.blade.phpはvendor内にあるので、基本的にいじらない方がいいです。Voyagerはcontrollerを外部出力できるので、そちらを行なってください。
コメントを書く