input('sort', 'city_id'); $sortType = $request->input('sort_type', 'asc'); $page = (int)$request->get('page', 1); $menuAccessService = app(\App\Services\MenuAccessService::class); // メニューアクセス制御: 非ソーリンユーザーは所属自治体のみ表示 $query = City::query(); if (!$menuAccessService->isSorin()) { $operator = auth()->user(); if ($operator && isset($operator->management_id)) { $query->where('management_id', $operator->management_id); } } if ($request->filled('city_name')) { $query->where('city_name', 'like', '%' . $request->input('city_name') . '%'); } if (!empty($sort)) { $query->orderBy($sort, $sortType); } $list = $query->paginate(50); // インデックス超過処理 if ($list->total() > 0 && $page > $list->lastPage()) { return redirect()->route('city', [ 'sort' => $sort, 'sort_type' => $sortType, ]); } return view('admin.cities.list', [ 'sort' => $sort, 'sort_type' => $sortType, 'list' => $list, 'page' => $page, ]); } /** 新規画面 */ public function add(Request $request) { $record = new City(); return view('admin.cities.add', [ 'record' => $record, 'errorMsg' => [], ]); } /** 登録 */ public function store(Request $request) { [$rules, $messages] = $this->rulesAndMessages(); $validator = Validator::make($request->all(), $rules, $messages); $record = new City(); if ($validator->fails()) { $record->fill($request->only(['city_name', 'print_layout', 'city_remarks'])); return view('admin.cities.add', [ 'record' => $record, 'errorMsg' => $validator->errors()->all(), ]); } $maxId = DB::table('city')->max('city_id'); $newCityId = $maxId ? $maxId + 1 : 1; $record->city_id = $newCityId; $record->fill($request->only([ 'city_name', 'print_layout', 'city_remarks', ])); if ($record->save()) { return redirect()->route('city')->with('success', __('登録に成功しました')); } return back()->withInput()->with('error', __('登録に失敗しました')); } /** 編集画面 */ public function edit(Request $request, $id) { $record = City::find($id); if (!$record) { abort(404); } $this->authorizeCityAccess($record); return view('admin.cities.edit', [ 'record' => $record, 'errorMsg' => [], ]); } /** 更新 */ public function update(Request $request, $id) { $record = City::find($id); if (!$record) { abort(404); } $this->authorizeCityAccess($record); [$rules, $messages] = $this->rulesAndMessages(); $validator = Validator::make($request->all(), $rules, $messages); if ($validator->fails()) { // 画面に戻る時に入力を保持 $record->fill($request->only(['city_name', 'print_layout', 'city_remarks'])); return view('admin.cities.edit', [ 'record' => $record, 'errorMsg' => $validator->errors()->all(), ]); } $record->fill($request->only([ 'city_name', 'print_layout', 'city_remarks', ])); if ($record->save()) { return redirect()->route('city')->with('success', __('更新に成功しました')); } return back()->withInput()->with('error', __('更新に失敗しました')); } public function delete(Request $request) { $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', __("削除が完了しました。")); } return redirect()->route('city')->with('error', __('削除に失敗しました。')); } private function rulesAndMessages(): array { $rules = [ // 市区名:全角 / 必須 / 最大20文字 'city_name' => [ 'required', 'string', 'max:20', 'regex:/^[^ -~。-゚]+$/u', ], // 印字レイアウトファイル:半角英数字 / 必須 / 最大255文字 'print_layout' => [ 'required', 'string', 'max:255', 'regex:/^[A-Za-z0-9]+$/', ], // 備考:任意 / 最大255文字 'city_remarks' => [ 'nullable', 'string', 'max:255', ], ]; $messages = [ 'city_name.required' => '市区名は必須です。', 'city_name.regex' => '市区名は全角文字で入力してください。', 'city_name.max' => '市区名は20文字以内で入力してください。', 'print_layout.required' => '印字レイアウトファイルは必須です。', 'print_layout.regex' => '印字レイアウトファイルは半角英数字で入力してください。', 'print_layout.max' => '印字レイアウトファイルは255文字以内で入力してください。', 'city_remarks.max' => '備考は255文字以内で入力してください。', ]; return [$rules, $messages]; } private function authorizeCityAccess(City $city): void { $menuAccessService = app(\App\Services\MenuAccessService::class); if (!$menuAccessService->canAccessCity($city->city_id)) { abort(403, 'この自治体へのアクセス権限がありません。'); } } /** * 自治体ダッシュボード(そのまま残すなら、別途 route 追加が必要) */ public function dashboard(Request $request, $city_id) { $city = City::find($city_id); if (!$city) { return redirect()->route('city')->with('error', '指定された自治体が見つかりません。'); } $parks = \App\Models\Park::where('city_id', $city_id)->get(); $parkIds = $parks->pluck('park_id')->toArray(); $contractsCount = 0; $usersCount = 0; $waitingCount = 0; if (!empty($parkIds)) { $contractsCount = \App\Models\RegularContract::whereIn('park_id', $parkIds)->count(); $userIds = \App\Models\RegularContract::whereIn('park_id', $parkIds) ->distinct() ->pluck('user_id') ->toArray(); $usersCount = count(array_filter($userIds)); $waitingCount = DB::table('reserve') ->whereIn('park_id', $parkIds) ->where('valid_flag', 1) ->whereNotNull('reserve_order') ->where('reserve_order', '>', 0) ->count(); } $stats = [ 'parks_count' => $parks->count(), 'contracts_count' => $contractsCount, 'users_count' => $usersCount, 'waiting_count' => $waitingCount, ]; return view('admin.CityMaster.dashboard', compact('city', 'parks', 'stats')); } }