From 466dc98e17c99fe199fcf2c096a99255700f63b2 Mon Sep 17 00:00:00 2001 From: "kin.rinzen" Date: Fri, 23 Jan 2026 18:20:48 +0900 Subject: [PATCH] =?UTF-8?q?=E5=B8=82=E5=8C=BA=E3=83=9E=E3=82=B9=E3=82=BF?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E3=81=AE=E3=83=A1=E3=82=BD=E3=83=83=E3=83=89?= =?UTF-8?q?=E6=95=B4=E7=90=86=E3=81=97=E3=80=81=E3=83=AB=E3=83=BC=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=83=B3=E3=82=B0=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Admin/CityController.php | 209 ++++++------------ app/Http/Requests/CityRequest.php | 39 ++++ app/Services/CityService.php | 50 +++++ resources/views/admin/cities/_form.blade.php | 14 -- .../{add.blade.php => create.blade.php} | 11 +- resources/views/admin/cities/edit.blade.php | 11 +- .../{list.blade.php => index.blade.php} | 10 +- routes/web.php | 45 +++- 8 files changed, 217 insertions(+), 172 deletions(-) create mode 100644 app/Http/Requests/CityRequest.php create mode 100644 app/Services/CityService.php rename resources/views/admin/cities/{add.blade.php => create.blade.php} (73%) rename resources/views/admin/cities/{list.blade.php => index.blade.php} (93%) diff --git a/app/Http/Controllers/Admin/CityController.php b/app/Http/Controllers/Admin/CityController.php index 121eb8d..82c82a7 100644 --- a/app/Http/Controllers/Admin/CityController.php +++ b/app/Http/Controllers/Admin/CityController.php @@ -1,44 +1,50 @@ input('sort', 'city_id'); - $sortType = $request->input('sort_type', 'asc'); - $page = $request->get('page', 1); + $sort = (string) $request->input('sort', 'city_id'); + $sortType = (string) $request->input('sort_type', 'asc'); + $page = (int) $request->get('page', 1); - $query = City::query(); - - if ($request->filled('city_name')) { - $query->where('city_name', 'like', '%' . $request->input('city_name') . '%'); + // ソート許可(安全 + 規約) + $sortable = ['city_id', 'city_name', 'print_layout', 'city_remarks', 'created_at', 'updated_at']; + if (!in_array($sort, $sortable, true)) { + $sort = 'city_id'; } - // 排序处理 - if (!empty($sort)) { - $query->orderBy($sort, $sortType); + $sortType = strtolower($sortType); + if (!in_array($sortType, ['asc', 'desc'], true)) { + $sortType = 'asc'; } - $list = $query->paginate(20); + $list = $service->paginateList( + $request->input('city_name'), + $sort, + $sortType + ); - // 页码越界处理 if ($list->total() > 0 && $page > $list->lastPage()) { - return redirect()->route('city', [ + return redirect()->route('cities.index', [ 'sort' => $sort, 'sort_type' => $sortType, ]); } - return view('admin.CityMaster.list', [ - 'isMethodPost' => $request->isMethod('post'), + return view('admin.cities.index', [ 'sort' => $sort, 'sort_type' => $sortType, 'list' => $list, @@ -46,129 +52,58 @@ class CityController extends Controller ]); } - public function add(Request $request) + public function create(): View { - $inputs = [ - 'city_name' => '', - 'print_layout' => '', - 'city_user' => '', - 'city_remarks' => '', - ]; - - if ($request->isMethod('POST')) { - $rules = [ - 'city_name' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'], - 'print_layout' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'], - 'city_user' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'], - 'city_remarks' => ['nullable', 'string', 'max:20'], - ]; - $messages = [ - 'city_name.required' => '市区名は必須です。', - 'city_name.regex' => '市区名は全角で入力してください。', - 'print_layout.required' => '印字レイアウトファイルは必須です。', - 'print_layout.regex' => '印字レイアウトファイルは全角で入力してください。', - 'city_user.required' => '顧客M入力不要フィールドIDは必須です。', - 'city_user.regex' => '顧客M入力不要フィールドIDは全角で入力してください。', - 'city_remarks.max' => '備考は20文字以内で入力してください。', - ]; - $validator = Validator::make($request->all(), $rules, $messages); - - $inputs = array_merge($inputs, $request->all()); - - if (!$validator->fails()) { - $maxId = DB::table('city')->max('city_id'); - $newCityId = $maxId ? $maxId + 1 : 1; - - $city = new City(); - $city->city_id = $newCityId; - $city->fill($request->only([ - 'city_name', - 'print_layout', - 'city_user', - 'city_remarks', - ])); - - if ($city->save()) { - $request->session()->flash('success', __('登録に成功しました')); - return redirect()->route('city'); - } else { - $request->session()->flash('error', __('登録に失敗しました')); - } - } else { - $inputs['errorMsg'] = $validator->errors()->all(); - } - } - - return view('admin.CityMaster.add', $inputs); - } - - public function edit(Request $request, $pk, $view = '') - { - $city = City::find($pk); - if (!$city) { - abort(404); - } - - if ($request->isMethod('POST')) { - $rules = [ - 'city_name' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'], - 'print_layout' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'], - 'city_user' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'], - 'city_remarks' => ['nullable', 'string', 'max:20'], - ]; - $messages = [ - 'city_name.required' => '市区名は必須です。', - 'city_name.regex' => '市区名は全角で入力してください。', - 'print_layout.required' => '印字レイアウトファイルは必須です。', - 'print_layout.regex' => '印字レイアウトファイルは全角で入力してください。', - 'city_user.required' => '顧客M入力不要フィールドIDは必須です。', - 'city_user.regex' => '顧客M入力不要フィールドIDは全角で入力してください。', - 'city_remarks.max' => '備考は20文字以内で入力してください。', - ]; - $validator = Validator::make($request->all(), $rules, $messages); - - if (!$validator->fails()) { - $city->fill($request->only([ - 'city_name', - 'print_layout', - 'city_user', - 'city_remarks', - ])); - - if ($city->save()) { - $request->session()->flash('success', __('更新に成功しました')); - return redirect()->route('city'); - } else { - $request->session()->flash('error', __('更新に失敗しました')); - } - } else { - return view('admin.CityMaster.edit', [ - 'city' => $city, - 'errorMsg' => $validator->errors()->all(), - ]); - } - } - - return view($view ?: 'admin.CityMaster.edit', [ - 'city' => $city, + return view('admin.cities.create', [ + 'record' => new City(), ]); } - public function info(Request $request, $pk) + public function store(CityRequest $request, CityService $service): RedirectResponse { - return $this->edit($request, $pk, 'CityMaster.info'); + $service->create($request->validated()); + + return redirect() + ->route('cities.index') + ->with('success', __('登録に成功しました')); } - public function delete(Request $request) + public function edit(int $id): View { - $arr_pk = $request->get('pk'); - if (!$arr_pk) { - return redirect()->route('city')->with('error', __('削除する市区を選択してください。')); - } - if (City::destroy($arr_pk)) { - return redirect()->route('city')->with('success', __("削除が完了しました。")); - } else { - return redirect()->route('city')->with('error', __('削除に失敗しました。')); - } + $city = City::findOrFail($id); + + return view('admin.cities.edit', [ + 'record' => $city, + ]); } -} \ No newline at end of file + + public function update(CityRequest $request, int $id, CityService $service): RedirectResponse + { + $city = City::findOrFail($id); + + $service->update($city, $request->validated()); + + return redirect() + ->route('cities.index') + ->with('success', __('更新に成功しました')); + } + + public function destroy(Request $request): RedirectResponse + { + $ids = $request->input('pk'); + + // pk が単体でも配列でも受けられるようにする(編集画面/一覧画面両対応) + if ($ids === null || $ids === '' || $ids === []) { + return redirect() + ->route('cities.index') + ->with('error', __('削除する市区を選択してください。')); + } + $ids = is_array($ids) ? $ids : [$ids]; + + $deleted = City::destroy($ids); + + return $deleted + ? redirect()->route('cities.index')->with('success', __('削除が完了しました。')) + : redirect()->route('cities.index')->with('error', __('削除に失敗しました。')); + } +} diff --git a/app/Http/Requests/CityRequest.php b/app/Http/Requests/CityRequest.php new file mode 100644 index 0000000..073beb5 --- /dev/null +++ b/app/Http/Requests/CityRequest.php @@ -0,0 +1,39 @@ + ['required', 'string', 'max:20', 'regex:/^[^ -~。-゚]+$/u'], + 'print_layout' => ['required', 'string', 'max:255', 'regex:/^[A-Za-z0-9]+$/'], + 'city_remarks' => ['nullable', 'string', 'max:255'], + ]; + } + + public function messages(): array + { + return [ + 'city_name.required' => '市区名は必須です。', + 'city_name.regex' => '市区名は全角文字で入力してください。', + 'city_name.max' => '市区名は20文字以内で入力してください。', + + 'print_layout.required' => '印字レイアウトファイルは必須です。', + 'print_layout.regex' => '印字レイアウトファイルは半角英数字で入力してください。', + 'print_layout.max' => '印字レイアウトファイルは255文字以内で入力してください。', + + 'city_remarks.max' => '備考は255文字以内で入力してください。', + ]; + } +} diff --git a/app/Services/CityService.php b/app/Services/CityService.php new file mode 100644 index 0000000..f1ea604 --- /dev/null +++ b/app/Services/CityService.php @@ -0,0 +1,50 @@ +where('city_name', 'like', '%' . $cityName . '%'); + } + + $query->orderBy($sort, $sortType); + + return $query->paginate(Utils::item_per_page); + } + + public function create(array $validated): City + { + return City::create($this->payload($validated)); + } + + public function update(City $city, array $validated): City + { + $city->fill($this->payload($validated)); + $city->save(); + + return $city; + } + + private function payload(array $validated): array + { + return [ + 'city_name' => $validated['city_name'], + 'print_layout' => $validated['print_layout'], + 'city_remarks' => $validated['city_remarks'] ?? null, + ]; + } +} diff --git a/resources/views/admin/cities/_form.blade.php b/resources/views/admin/cities/_form.blade.php index 29620fa..69d2518 100644 --- a/resources/views/admin/cities/_form.blade.php +++ b/resources/views/admin/cities/_form.blade.php @@ -89,20 +89,6 @@ - - {{-- ▼ 備考 --}}
diff --git a/resources/views/admin/cities/add.blade.php b/resources/views/admin/cities/create.blade.php similarity index 73% rename from resources/views/admin/cities/add.blade.php rename to resources/views/admin/cities/create.blade.php index 6235b11..f9fcf87 100644 --- a/resources/views/admin/cities/add.blade.php +++ b/resources/views/admin/cities/create.blade.php @@ -11,9 +11,11 @@
@@ -30,9 +32,10 @@
+ {{-- 新規登録フォーム --}}
@csrf diff --git a/resources/views/admin/cities/edit.blade.php b/resources/views/admin/cities/edit.blade.php index 574cd86..b28b62c 100644 --- a/resources/views/admin/cities/edit.blade.php +++ b/resources/views/admin/cities/edit.blade.php @@ -13,7 +13,7 @@ @@ -33,9 +33,9 @@ {{-- 編集フォーム --}} + action="{{ route('cities.update', ['id' => $record->city_id]) }}?back={{ urlencode(request()->get('back', request()->fullUrl())) }}" + method="POST" + enctype="multipart/form-data"> @csrf @include('admin.cities._form', [ @@ -46,7 +46,7 @@ {{-- 削除フォーム(非表示) --}} @csrf @@ -59,5 +59,4 @@
- @endsection diff --git a/resources/views/admin/cities/list.blade.php b/resources/views/admin/cities/index.blade.php similarity index 93% rename from resources/views/admin/cities/list.blade.php rename to resources/views/admin/cities/index.blade.php index 34619dd..0450563 100644 --- a/resources/views/admin/cities/list.blade.php +++ b/resources/views/admin/cities/index.blade.php @@ -24,7 +24,7 @@
{{-- 並び替え用 hidden --}} - + @@ -33,7 +33,7 @@
@@ -62,7 +62,7 @@
- {{-- ▼ フラッシュメッセージ(利用者分類マスタと同じ見せ方) --}} + {{-- ▼ フラッシュメッセージ --}}
@if(Session::has('success'))
@@ -85,7 +85,7 @@ {{-- ▼ テーブル --}}
-
+ @csrf @@ -118,7 +118,7 @@
- 編集 diff --git a/routes/web.php b/routes/web.php index a829c36..aec62dd 100644 --- a/routes/web.php +++ b/routes/web.php @@ -151,12 +151,45 @@ Route::middleware('auth')->group(function () { // sou end // ou start - // 市区マスタ - Route::match(['get', 'post'], '/city', [CityController::class, 'list'])->name('city'); - Route::match(['get', 'post'], '/city/add', [CityController::class, 'add'])->name('city_add'); - Route::match(['get', 'post'], '/city/edit/{id}', [CityController::class, 'edit'])->where(['id' => '[0-9]+'])->name('city_edit'); - Route::match(['get', 'post'], '/city/info/{id}', [CityController::class, 'info'])->where(['id' => '[0-9]+'])->name('city_info'); - Route::match(['get', 'post'], '/city/delete', [CityController::class, 'delete'])->name('city_delete'); + // // 市区マスタ + // Route::match(['get', 'post'], '/city', [CityController::class, 'list'])->name('city'); + // Route::match(['get', 'post'], '/city/add', [CityController::class, 'add'])->name('city_add'); + // Route::match(['get', 'post'], '/city/edit/{id}', [CityController::class, 'edit'])->where(['id' => '[0-9]+'])->name('city_edit'); + // Route::match(['get', 'post'], '/city/info/{id}', [CityController::class, 'info'])->where(['id' => '[0-9]+'])->name('city_info'); + // Route::match(['get', 'post'], '/city/delete', [CityController::class, 'delete'])->name('city_delete'); + + // 市区マスタ(cities.*) + Route::prefix('cities')->group(function () { + + // 一覧(画面) + Route::get('/', [\App\Http\Controllers\Admin\CityController::class, 'index']) + ->name('cities.index'); + + // 新規(画面) + Route::get('/create', [\App\Http\Controllers\Admin\CityController::class, 'create']) + ->name('cities.create'); + + // 新規(登録) + Route::post('/', [\App\Http\Controllers\Admin\CityController::class, 'store']) + ->name('cities.store'); + + // 編集(画面) + Route::get('/{id}/edit', [\App\Http\Controllers\Admin\CityController::class, 'edit']) + ->whereNumber('id') + ->name('cities.edit'); + + // 編集(更新) + Route::post('/{id}', [\App\Http\Controllers\Admin\CityController::class, 'update']) + ->whereNumber('id') + ->name('cities.update'); + + // 削除(複数削除 pk[]) + Route::post('/delete', [\App\Http\Controllers\Admin\CityController::class, 'destroy']) + ->name('cities.destroy'); + }); + + + // 駐輪場マスタ Route::get('/parks', [ParkController::class, 'list'])->name('parks');