187 lines
6.2 KiB
PHP
187 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Parking\Setup\Petugas;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Pegawai;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class MasterPetugasController extends Controller
|
|
{
|
|
/**
|
|
* Display a listing of the resource.
|
|
*/
|
|
public function index()
|
|
{
|
|
$petugas = Pegawai::orderBy('nomer')->get();
|
|
$levels = DB::table('level_user')->orderBy('level_code')->get();
|
|
|
|
return view('setup.petugas.petugas', compact('petugas', 'levels'));
|
|
}
|
|
|
|
/**
|
|
* Store a newly created resource in storage.
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$data = $request->validate($this->rules(), $this->messages());
|
|
// Normalisasi: string kosong jadi null (kolom date/int tidak terima '').
|
|
$data = array_map(fn ($v) => $v === '' ? null : $v, $data);
|
|
|
|
$pegawai = Pegawai::create(collect($data)->except('foto')->all());
|
|
|
|
if ($request->hasFile('foto')) {
|
|
$this->saveFoto($pegawai->id, $request->file('foto'));
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Petugas berhasil ditambahkan.',
|
|
'data' => $pegawai->fresh()->makeHidden('foto'),
|
|
], 201);
|
|
}
|
|
|
|
/**
|
|
* Display the specified resource (tanpa binary foto).
|
|
*/
|
|
public function show($id)
|
|
{
|
|
$pegawai = Pegawai::select(
|
|
'id', 'nomer', 'nama', 'alamat', 'tgl_lahir', 'tgl_masuk',
|
|
'username', 'password', 'bisalogin', 'status', 'jeniskelamin',
|
|
'agama', 'telepon', 'alamat_lahir', 'alamat_sekarang', 'nip',
|
|
'statusabsen', 'level_pegawai', 'email'
|
|
)->findOrFail($id);
|
|
|
|
$hasFoto = (bool) DB::table('pegawai')->where('id', $id)->whereNotNull('foto')->exists();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $pegawai,
|
|
'has_foto' => $hasFoto,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*/
|
|
public function update(Request $request, $id)
|
|
{
|
|
$pegawai = Pegawai::findOrFail($id);
|
|
|
|
$data = $request->validate($this->rules($pegawai->id), $this->messages());
|
|
// Normalisasi: string kosong jadi null (kolom date/int tidak terima '').
|
|
$data = array_map(fn ($v) => $v === '' ? null : $v, $data);
|
|
|
|
// Password kosong = tidak diubah (tetap pakai yang lama, plain-text ikut gaya legacy).
|
|
if (empty($data['password'])) {
|
|
unset($data['password']);
|
|
}
|
|
|
|
$pegawai->update(collect($data)->except('foto')->all());
|
|
|
|
if ($request->hasFile('foto')) {
|
|
$this->saveFoto($pegawai->id, $request->file('foto'));
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Petugas berhasil diperbarui.',
|
|
'data' => $pegawai->fresh()->makeHidden('foto'),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*/
|
|
public function destroy($id)
|
|
{
|
|
Pegawai::findOrFail($id)->delete();
|
|
|
|
return response()->json(['success' => true, 'message' => 'Petugas berhasil dihapus.']);
|
|
}
|
|
|
|
/**
|
|
* Stream foto dari kolom bytea. Fallback ke placeholder bila kosong.
|
|
*/
|
|
public function foto($id)
|
|
{
|
|
$row = DB::table('pegawai')->select('foto')->where('id', $id)->first();
|
|
|
|
$binary = $row?->foto;
|
|
if (is_resource($binary)) {
|
|
$binary = stream_get_contents($binary);
|
|
}
|
|
|
|
if (empty($binary)) {
|
|
return response()->file(public_path('images/no-image.jpg'));
|
|
}
|
|
|
|
$mime = (new \finfo(FILEINFO_MIME_TYPE))->buffer($binary) ?: 'image/jpeg';
|
|
|
|
return response($binary, 200, [
|
|
'Content-Type' => $mime,
|
|
'Content-Length' => strlen($binary),
|
|
'Cache-Control' => 'private, max-age=3600',
|
|
]);
|
|
}
|
|
|
|
protected function messages(): array
|
|
{
|
|
return [
|
|
'nomer.unique' => 'Nomer sudah dipakai petugas lain, ganti dengan yang unik.',
|
|
'username.unique' => 'Username sudah dipakai petugas lain, ganti dengan yang unik.',
|
|
'foto.image' => 'File foto harus berupa gambar.',
|
|
'foto.max' => 'Ukuran foto maksimal 2MB.',
|
|
];
|
|
}
|
|
|
|
protected function rules(?int $ignoreId = null): array
|
|
{
|
|
$uniqueUsername = Rule::unique('pegawai', 'username');
|
|
$uniqueNomer = Rule::unique('pegawai', 'nomer');
|
|
if ($ignoreId) {
|
|
$uniqueUsername->ignore($ignoreId, 'id');
|
|
$uniqueNomer->ignore($ignoreId, 'id');
|
|
}
|
|
|
|
return [
|
|
'nomer' => ['required', 'string', 'max:50', $uniqueNomer],
|
|
'nama' => 'required|string|max:50',
|
|
'username' => ['required', 'string', 'max:50', $uniqueUsername],
|
|
// Plain-text ikut gaya data legacy. Wajib saat tambah, opsional saat ubah.
|
|
'password' => ($ignoreId ? 'nullable' : 'required') . '|string|max:50',
|
|
'level_pegawai' => 'nullable|string|exists:level_user,level_code',
|
|
'bisalogin' => 'nullable|integer|in:0,1',
|
|
'status' => 'nullable|integer|in:0,1',
|
|
'jeniskelamin' => 'nullable|integer|in:0,1',
|
|
'statusabsen' => 'nullable|integer|in:0,1',
|
|
'agama' => 'nullable|string|max:50',
|
|
'telepon' => 'nullable|string|max:255',
|
|
'alamat' => 'nullable|string|max:100',
|
|
'alamat_lahir' => 'nullable|string|max:255',
|
|
'alamat_sekarang' => 'nullable|string|max:255',
|
|
'nip' => 'nullable|string|max:50',
|
|
'email' => 'nullable|string|max:64',
|
|
'tgl_lahir' => 'nullable|date',
|
|
'tgl_masuk' => 'nullable|date',
|
|
'foto' => 'nullable|image|mimes:jpg,jpeg,png,bmp|max:2048',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Simpan binary ke kolom bytea tanpa nambah kolom baru.
|
|
* bin2hex menghindari masalah escaping bytea.
|
|
*/
|
|
protected function saveFoto(int $id, $file): void
|
|
{
|
|
$binary = file_get_contents($file->getRealPath());
|
|
|
|
DB::table('pegawai')->where('id', $id)->update([
|
|
'foto' => DB::raw("decode('" . bin2hex($binary) . "', 'hex')"),
|
|
]);
|
|
}
|
|
}
|