From f87043f4265b0dd97d596ecdf6dccdbe91afc47c Mon Sep 17 00:00:00 2001 From: gakigaki Date: Mon, 25 May 2026 16:28:41 +0900 Subject: [PATCH 1/2] feat(forms): add input list search --- app/Plugins/User/Forms/FormsPlugin.php | 162 +++++++++++- config/forms.php | 9 + .../forms/default/forms_list_inputs.blade.php | 70 +++++- .../FormsListInputsSearchFeatureTest.php | 230 ++++++++++++++++++ 4 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 tests/Feature/Plugins/User/Forms/FormsListInputsSearchFeatureTest.php diff --git a/app/Plugins/User/Forms/FormsPlugin.php b/app/Plugins/User/Forms/FormsPlugin.php index 430a4aa5b..51cefaf0f 100644 --- a/app/Plugins/User/Forms/FormsPlugin.php +++ b/app/Plugins/User/Forms/FormsPlugin.php @@ -107,6 +107,7 @@ public function getPublicFunctions() 'editInput', 'thanks', 'editSpamFilter', + 'indexCount', ]; $functions['post'] = [ 'index', @@ -127,6 +128,7 @@ public function getPublicFunctions() 'addSpamList', 'deleteSpamList', 'addToSpamListFromInput', + 'indexCount', ]; return $functions; } @@ -3020,12 +3022,16 @@ public function listInputs($request, $page_id, $frame_id, $forms_id = null) // カラムの取得 $columns = FormsColumns::where('forms_id', $form->id)->orderBy('display_sequence', 'asc')->get(); + $search_condition = $this->getListInputsSearchCondition($request); + $inputs_query = FormsInputs::where('forms_id', $form->id); + $this->appendListInputsSearchWhere($inputs_query, $search_condition); // $inputs_query->orderBy('forms_inputs.id', 'asc'); $inputs_query->orderBy('forms_inputs.created_at', 'desc'); // データ取得 - $get_count = 10; + $get_count = session("view_count_spectator_{$frame_id}", $this->getListInputsDefaultPerPage()); + $get_count = $this->normalizeListInputsPerPage($get_count); $inputs = $inputs_query->paginate($get_count, ["*"], "frame_{$frame_id}_page"); // 登録データ詳細の取得 @@ -3060,9 +3066,163 @@ public function listInputs($request, $page_id, $frame_id, $forms_id = null) 'inputs' => $inputs, 'input_cols' => $input_cols, 'has_email_map' => $has_email_map, + 'search_condition' => $search_condition, + 'per_page_options' => $this->getListInputsPerPageOptions(), + 'view_count' => $get_count, ]); } + /** + * 登録一覧の件数指定 + */ + public function indexCount($request, $page_id, $frame_id) + { + session(["view_count_spectator_{$frame_id}" => $this->normalizeListInputsPerPage($request->input("view_count_spectator"))]); + + // リダイレクト先を指定しないため、画面から渡されたredirect_pathに飛ぶ + } + + /** + * 登録一覧の検索条件を画面入力から取得する。 + */ + private function getListInputsSearchCondition($request): array + { + return [ + 'keyword' => trim((string)$request->input('keyword', '')), + 'status' => $this->normalizeListInputsStatus($request->input('status')), + 'created_from' => $this->normalizeListInputsDate($request->input('created_from')), + 'created_to' => $this->normalizeListInputsDate($request->input('created_to')), + ]; + } + + /** + * 登録一覧の検索条件をクエリに反映する。 + */ + private function appendListInputsSearchWhere($inputs_query, array $search_condition): void + { + if ($search_condition['keyword'] !== '') { + $keyword = $this->escapeLikeValue($search_condition['keyword']); + $like_keyword = '%' . $keyword . '%'; + + $inputs_query->where(function ($query) use ($like_keyword) { + $query->where('forms_inputs.number_with_prefix', 'like', $like_keyword) + ->orWhere('forms_inputs.created_name', 'like', $like_keyword) + ->orWhere('forms_inputs.ip_address', 'like', $like_keyword) + ->orWhereExists(function ($sub_query) use ($like_keyword) { + $sub_query->select(DB::raw(1)) + ->from('forms_input_cols') + ->leftJoin('uploads', 'uploads.id', '=', 'forms_input_cols.value') + ->whereColumn('forms_input_cols.forms_inputs_id', 'forms_inputs.id') + ->where(function ($value_query) use ($like_keyword) { + $value_query->where('forms_input_cols.value', 'like', $like_keyword) + ->orWhere('uploads.client_original_name', 'like', $like_keyword); + }); + }); + }); + } + + if ($search_condition['status'] !== '') { + $inputs_query->where('forms_inputs.status', (int)$search_condition['status']); + } + + if ($search_condition['created_from'] !== '') { + $inputs_query->whereDate('forms_inputs.created_at', '>=', $search_condition['created_from']); + } + + if ($search_condition['created_to'] !== '') { + $inputs_query->whereDate('forms_inputs.created_at', '<=', $search_condition['created_to']); + } + } + + /** + * 登録一覧の状態検索条件を有効な値に丸める。 + */ + private function normalizeListInputsStatus($status): string + { + if (is_null($status) || $status === '') { + return ''; + } + + $allowed_statuses = array_map('strval', array_keys(FormStatusType::enum)); + $status = (string)$status; + + return in_array($status, $allowed_statuses, true) ? $status : ''; + } + + /** + * 登録一覧の日付検索条件を有効な年月日に丸める。 + */ + private function normalizeListInputsDate($date): string + { + if (!is_string($date) || $date === '') { + return ''; + } + + $date = trim($date); + if (!preg_match('/\A[0-9]{4}-[0-9]{2}-[0-9]{2}\z/', $date)) { + return ''; + } + + [$year, $month, $day] = array_map('intval', explode('-', $date)); + + return checkdate($month, $day, $year) ? $date : ''; + } + + /** + * 登録一覧の表示件数を許可された値に丸める。 + */ + private function normalizeListInputsPerPage($per_page): int + { + $per_page = (int)$per_page; + $per_page_options = $this->getListInputsPerPageOptions(); + + return in_array($per_page, $per_page_options, true) ? $per_page : $this->getListInputsDefaultPerPage(); + } + + /** + * 登録一覧の表示件数候補を設定から取得する。 + */ + private function getListInputsPerPageOptions(): array + { + $per_page_options = config('forms.list_inputs.per_page_options', []); + if (!is_array($per_page_options)) { + return [10]; + } + + $per_page_options = collect($per_page_options) + ->map(function ($per_page) { + return (int)$per_page; + }) + ->filter(function ($per_page) { + return $per_page > 0; + }) + ->unique() + ->sort() + ->values() + ->all(); + + return $per_page_options ?: [10]; + } + + /** + * 登録一覧の初期表示件数を設定から取得する。 + */ + private function getListInputsDefaultPerPage(): int + { + $default_per_page = (int)config('forms.list_inputs.default_per_page'); + $per_page_options = $this->getListInputsPerPageOptions(); + + return in_array($default_per_page, $per_page_options, true) ? $default_per_page : $per_page_options[0]; + } + + /** + * LIKE 検索用にワイルドカード文字をエスケープする。 + */ + private function escapeLikeValue(string $value): string + { + return str_replace(['\\', '%', '_'], ['\\\\', '\%', '\_'], $value); + } + /** * 登録一覧からの編集画面表示 */ diff --git a/config/forms.php b/config/forms.php index eb451fe95..5f3b08c0b 100644 --- a/config/forms.php +++ b/config/forms.php @@ -2,6 +2,15 @@ return [ + // 登録一覧設定 + 'list_inputs' => [ + // 1ページあたりの表示件数候補 + 'per_page_options' => [10, 20, 50, 100], + + // 1ページあたりの初期表示件数 + 'default_per_page' => 10, + ], + // ファイルアップロード許可設定 'upload' => [ // クライアント拡張子の許可リスト diff --git a/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php b/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php index 572762cc6..f897ce473 100644 --- a/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php +++ b/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php @@ -10,6 +10,27 @@ @section("plugin_setting_$frame->id") +@php + $search_condition = $search_condition ?? [ + 'keyword' => '', + 'status' => '', + 'created_from' => '', + 'created_to' => '', + ]; + $per_page_options = $per_page_options ?? config('forms.list_inputs.per_page_options', []); + $view_count = $view_count ?? config('forms.list_inputs.default_per_page'); + $list_inputs_url = url('/') . "/plugin/forms/listInputs/{$page->id}/{$frame_id}/{$form->id}"; + $has_search_condition = $search_condition['keyword'] !== '' + || $search_condition['status'] !== '' + || $search_condition['created_from'] !== '' + || $search_condition['created_to'] !== ''; + $pagination_appends = array_filter($search_condition, function ($value) { + return !is_null($value) && $value !== ''; + }); + $list_inputs_redirect_query = array_merge($pagination_appends, ["frame_{$frame_id}_page" => 1]); + $list_inputs_redirect_path = $list_inputs_url . '?' . http_build_query($list_inputs_redirect_query) . "#frame-{$frame_id}"; +@endphp + {{-- 登録後メッセージ表示 --}} @include('plugins.common.flash_message') @@ -59,6 +80,41 @@ function submit_register_other_plugins(id) { }) + +
{{-- (左側)件数 --}} @@ -66,6 +122,18 @@ function submit_register_other_plugins(id) {
+ {{-- (右側)表示件数変更 --}} +
+ {{ csrf_field() }} + + + +
+ {{-- (右側)ダウンロードボタン --}}