|string> */ public function rules(): array { return [ 'data' => 'required|array|min:1', 'data.*.nama_kategori_diet' => 'required|string' ]; } public function messages(){ return [ 'data.array' => 'Format data harus berupa array', 'data.min' => 'Minimal harus ada satu data klasifikasi menu', 'data.*.nama_kategori_diet.required' => 'Nama Klasifikasi Menu wajib diisi', 'data.*.nama_kategori_diet.string' => 'Nama Kategori Soal harus berupa teks', ]; } protected function failedValidation(Validator $validator){ throw new HttpResponseException( response()->json([ 'status' => 'VALIDATION_FAILED', 'message' => 'Validasi Gagal', 'errors' => $validator->errors()->messages(), ], 422) ); } public function withValidator($validator){ $validator->after(function ($validator){ $namaListAsli = collect($this->input('data'))->pluck('nama_kategori_diet')->filter(); $namaListLower = $namaListAsli->map(fn($n) => strtolower(trim($n))); // ✅ Cek duplikat antar input user $duplicates = $namaListLower->duplicates(); if ($duplicates->isNotEmpty()) { foreach ($namaListAsli as $index => $nama) { if ($duplicates->contains(strtolower(trim($nama)))) { $validator->errors()->add("data.$index.nama_kategori_diet", "Nama '$nama' duplikat dalam input."); } } } $namaList = $namaListAsli->map(fn($n) => strtolower(trim($n))); if($namaList->isEmpty()) return; $exists = DB::connection('dbOrderGizi') ->table('public.kategori_diet') ->where('statusenabled', true) ->whereIn(DB::raw('LOWER(nama_kategori_diet)'), $namaList->toArray()) ->selectRaw('LOWER(nama_kategori_diet) as nama') ->pluck('nama') ->toArray(); foreach ($namaListAsli as $index => $nama) { $lowerNama = strtolower(trim($nama)); if(in_array($lowerNama, $exists)){ $validator->errors()->add("data.$index.nama_kategori_diet", "Nama '$nama' Sudah digunakan."); } } }); } }