ekosistem basis data tambah field enum

This commit is contained in:
2026-05-06 15:51:59 +07:00
parent 9605ae7502
commit 61d8c41c63
9 changed files with 209 additions and 10 deletions
@@ -49,18 +49,27 @@ class KolomBasisDataController extends Controller
'kolom' => ['required', 'kolom' => ['required',
'string', 'string',
'regex:/^[a-z0-9]+(_[a-z0-9]+)*$/', 'regex:/^[a-z0-9]+(_[a-z0-9]+)*$/',
Rule::unique('ekosistem_basis_data_kolom')->where(function ($query) use ($request) { Rule::unique('ekosistem_basis_data_kolom')->where(function ($query) use ($tabelId) {
return $query->where('tabel_id', $request->tabel_id)->whereNull('deleted_at'); return $query->where('tabel_id', $tabelId)->whereNull('deleted_at');
}) })
], ],
'label' => ['required', 'string'], 'label' => ['required', 'string'],
'tipe' => ['required', 'string', Rule::in(['varchar', 'integer', 'text', 'date', 'boolean', 'datetime', 'float', 'foreign_key'])], 'tipe' => ['required', 'string',
Rule::in(['varchar', 'integer', 'text', 'date', 'boolean', 'datetime', 'float', 'foreign_key', 'enum'])],
'validasi' => ['nullable', 'json'], 'validasi' => ['nullable', 'json'],
'relasi_tabel' => ['nullable', 'string'], 'relasi_tabel' => ['nullable', 'string'],
'relasi_kolom_id' => ['nullable', 'string'], 'relasi_kolom_id' => ['nullable', 'string'],
'relasi_kolom_label' => ['nullable', 'string'], 'relasi_kolom_label' => ['nullable', 'string'],
'enum_opsi' => ['nullable', 'json'],
]); ]);
if (!empty($validated['enum_opsi'])) {
$validated['enum_opsi'] = json_decode($validated['enum_opsi'], true);
}
if (!empty($validated['validasi'])) {
$validated['validasi'] = json_decode($validated['validasi'], true);
}
KolomBasisData::create([...$validated, KolomBasisData::create([...$validated,
'tabel_id' => $tabelId, 'tabel_id' => $tabelId,
'created_by' => auth()->id(), 'created_by' => auth()->id(),
@@ -123,11 +132,13 @@ class KolomBasisDataController extends Controller
}) })
], ],
'label' => ['required', 'string'], 'label' => ['required', 'string'],
'tipe' => ['required', 'string', Rule::in(['varchar', 'integer', 'text', 'date', 'boolean', 'datetime', 'float', 'foreign_key'])], 'tipe' => ['required', 'string',
Rule::in(['varchar', 'integer', 'text', 'date', 'boolean', 'datetime', 'float', 'foreign_key', 'enum'])],
'validasi' => ['nullable', 'json'], 'validasi' => ['nullable', 'json'],
'relasi_tabel' => ['nullable', 'string'], 'relasi_tabel' => ['nullable', 'string'],
'relasi_kolom_id' => ['nullable', 'string'], 'relasi_kolom_id' => ['nullable', 'string'],
'relasi_kolom_label' => ['nullable', 'string'], 'relasi_kolom_label' => ['nullable', 'string'],
'enum_opsi' => ['nullable', 'json'],
]); ]);
$kolom->update([...$validated, $kolom->update([...$validated,
@@ -75,6 +75,23 @@ class ValueBasisDataController extends Controller
END END
) AS \"{$k->kolom}\" ) AS \"{$k->kolom}\"
"; ";
} elseif ($k->tipe == 'enum') {
$selects[] = "
MAX(
CASE
WHEN kolom_id = {$k->id}
THEN (
SELECT elem->>'label'
FROM ekosistem_basis_data_kolom k,
jsonb_array_elements(k.enum_opsi::jsonb) AS elem
WHERE k.id = kolom_id
AND elem->>'value' = value_enum
LIMIT 1
)
ELSE NULL
END
) AS \"{$k->kolom}\"
";
} else { } else {
$selects[] = " $selects[] = "
MAX( MAX(
@@ -178,6 +195,7 @@ class ValueBasisDataController extends Controller
} }
} }
$list_relasi = collect($list_relasi); $list_relasi = collect($list_relasi);
// dd($kolom->where('tipe', 'enum')->first()?->enum_opsi);
return view('ekosistem.value-basis-data.add', compact('tabel', 'kolom', 'program', 'list_relasi')); return view('ekosistem.value-basis-data.add', compact('tabel', 'kolom', 'program', 'list_relasi'));
} }
@@ -250,12 +268,63 @@ class ValueBasisDataController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
*/ */
public function show(string $id) public function show(Request $request, string $tabelId, string $id): View
{ {
// if (!Gate::any(['super_admin', 'admin'])) {
abort(403);
} }
public function edit(Request $request, string $tabelId, string $id) $tabel = TabelBasisData::find($tabelId);
if (!$tabel) {
abort(404, 'Data tabel tidak ditemukan.');
}
$kolom = KolomBasisData::where('tabel_id', $tabelId)->get();
if ($kolom->isEmpty()) {
abort(404, 'Data kolom tidak ditemukan untuk tabel ini.');
}
if (app()->has('SystemProgram')) {
$program = app('SystemProgram');
} else {
if ($request->has('program_id') && $request->query('program_id')) {
$programId = $request->query('program_id');
$program = Program::find($programId);
if (!$program) {
abort(400, 'Program tidak ditemukan.');
}
} else {
abort(400, 'Program tidak ditemukan.');
}
}
$values = ValueBasisData::query()
->where('tabel_id', $tabelId)
->where('value_id', $id)
->where('program_id', $program->id)
->get();
if ($values->isEmpty()) {
abort(404, 'Data tidak ditemukan.');
}
foreach ($values as $v) {
$k = $kolom->where('id', $v->kolom_id)->first();
if ($k->tipe == 'foreign_key') {
$v->value_relasi_label = DB::table($k->relasi_tabel)->where($k->relasi_kolom_id, $v->value_relasi)->value($k->relasi_kolom_label);
} else if ($k->tipe == 'enum') {
$opsi = collect($k->enum_opsi);
$found = $opsi->first(function ($item) use ($v) {
return (string) $item['value'] === (string) $v->value_enum;
});
$v->value_enum_label = $found['label'] ?? null;
}
}
$value_id = $id;
return view('ekosistem.value-basis-data.view', compact('tabel', 'kolom', 'program', 'values', 'value_id'));
}
public function edit(Request $request, string $tabelId, string $id): View
{ {
if (!Gate::any(['super_admin', 'admin'])) { if (!Gate::any(['super_admin', 'admin'])) {
abort(403); abort(403);
@@ -317,7 +386,7 @@ class ValueBasisDataController extends Controller
/** /**
* Update the specified resource in storage. * Update the specified resource in storage.
*/ */
public function update(Request $request, string $tabelId, string $id) public function update(Request $request, string $tabelId, string $id): RedirectResponse
{ {
if (!Gate::any(['super_admin', 'admin'])) { if (!Gate::any(['super_admin', 'admin'])) {
abort(403); abort(403);
@@ -408,7 +477,7 @@ class ValueBasisDataController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
*/ */
public function destroy(Request $request, string $tabelId, string $id) public function destroy(Request $request, string $tabelId, string $id): RedirectResponse
{ {
if (!Gate::any(['super_admin', 'admin'])) { if (!Gate::any(['super_admin', 'admin'])) {
abort(403); abort(403);
+2
View File
@@ -25,10 +25,12 @@ class KolomBasisData extends Model
'relasi_tabel', 'relasi_tabel',
'relasi_kolom_id', 'relasi_kolom_id',
'relasi_kolom_label', 'relasi_kolom_label',
'enum_opsi',
]; ];
protected $casts = [ protected $casts = [
'validasi' => 'array', 'validasi' => 'array',
'enum_opsi' => 'array',
]; ];
protected static function booted() protected static function booted()
+1
View File
@@ -31,6 +31,7 @@ class ValueBasisData extends Model
'updated_by', 'updated_by',
'deleted_by', 'deleted_by',
'value_relasi', 'value_relasi',
'value_enum',
]; ];
public function tabel(): BelongsTo public function tabel(): BelongsTo
@@ -16,6 +16,8 @@ return new class extends Migration
$table->string('relasi_tabel')->nullable(); $table->string('relasi_tabel')->nullable();
$table->string('relasi_kolom_id')->nullable(); $table->string('relasi_kolom_id')->nullable();
$table->string('relasi_kolom_label')->nullable(); $table->string('relasi_kolom_label')->nullable();
$table->jsonb('enum_opsi')->nullable();
}); });
DB::statement("alter table public.ekosistem_basis_data_kolom drop constraint ekosistem_basis_data_kolom_tipe_check;"); DB::statement("alter table public.ekosistem_basis_data_kolom drop constraint ekosistem_basis_data_kolom_tipe_check;");
@@ -29,12 +31,14 @@ return new class extends Migration
'date'::character varying, 'date'::character varying,
'datetime'::character varying, 'datetime'::character varying,
'text'::character varying, 'text'::character varying,
'foreign_key'::character varying 'foreign_key'::character varying,
'enum'::character varying
])::text[]))) ])::text[])))
"); ");
Schema::table('ekosistem_basis_data_value', function (Blueprint $table) { Schema::table('ekosistem_basis_data_value', function (Blueprint $table) {
$table->integer('value_relasi')->nullable(); $table->integer('value_relasi')->nullable();
$table->string('value_enum')->nullable();
}); });
Schema::table('ekosistem_petani_cpm', function (Blueprint $table) { Schema::table('ekosistem_petani_cpm', function (Blueprint $table) {
@@ -35,6 +35,7 @@
<option value="datetime">Datetime</option> <option value="datetime">Datetime</option>
<option value="text">Text</option> <option value="text">Text</option>
<option value="foreign_key">Relasi</option> <option value="foreign_key">Relasi</option>
<option value="enum">Enum</option>
</select> </select>
</div> </div>
<div class="mb-6 form-control-validation" id="relasi-form-tabel" style="display: none;"> <div class="mb-6 form-control-validation" id="relasi-form-tabel" style="display: none;">
@@ -49,6 +50,11 @@
<label class="form-label" for="add-kolom-relasi-kolom-label">Kolom Relasi (Label)<span class="text-danger">*</span></label> <label class="form-label" for="add-kolom-relasi-kolom-label">Kolom Relasi (Label)<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="add-kolom-relasi-kolom-label" name="relasi_kolom_label" placeholder="Cth: Nama Petani" /> <input type="text" class="form-control" id="add-kolom-relasi-kolom-label" name="relasi_kolom_label" placeholder="Cth: Nama Petani" />
</div> </div>
<div class="mb-6 form-control-validation" id="enum-form-opsi" style="display: none;">
<label class="form-label" for="add-kolom-enum-opsi" >Opsi Enum<span class="text-danger">*</span></label>
<textarea class="form-control" id="add-kolom-enum-opsi" name="enum_opsi" value="1"
placeholder='Cth: [{"label": "Satu Pilihan", "value": "satu"}, {"label": "Dua Saja", "value": "dua"}]'></textarea>
</div>
<div class="mb-6 form-control-validation"> <div class="mb-6 form-control-validation">
<label class="form-label" for="add-kolom-validasi">Validasi<span class="text-danger">*</span></label> <label class="form-label" for="add-kolom-validasi">Validasi<span class="text-danger">*</span></label>
<textarea class="form-control" id="add-kolom-validasi" name="validasi" value="1" placeholder="Cth: required"></textarea> <textarea class="form-control" id="add-kolom-validasi" name="validasi" value="1" placeholder="Cth: required"></textarea>
@@ -78,8 +84,14 @@
$('#relasi-form-kolom').hide(); $('#relasi-form-kolom').hide();
$('#relasi-form-kolom-label').hide(); $('#relasi-form-kolom-label').hide();
} }
if ($(this).val() === 'enum') {
$('#enum-form-opsi').show();
} else {
$('#enum-form-opsi').hide();
}
}); });
$.validator.addMethod("snakecase", function(value, element) { $.validator.addMethod("snakecase", function(value, element) {
return this.optional(element) || /^[a-z0-9]+(_[a-z0-9]+)*$/.test(value); return this.optional(element) || /^[a-z0-9]+(_[a-z0-9]+)*$/.test(value);
}, "Gunakan format snake_case (huruf kecil dan underscore)"); }, "Gunakan format snake_case (huruf kecil dan underscore)");
@@ -47,6 +47,12 @@
@endforeach @endforeach
@endif @endif
</select> </select>
@elseif($k->tipe == 'enum')
<select class="form-select tipe-fk @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" name="{{ $k->kolom }}">
@foreach($k->enum_opsi as $opsi)
<option value="{{ $opsi['value'] }}" {{ old($k->kolom) == $opsi['value'] ? 'selected' : '' }}>{{ $opsi['label'] }}</option>
@endforeach
</select>
@else @else
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" <input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}"
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) }}" /> name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) }}" />
@@ -64,6 +64,12 @@
@endforeach @endforeach
@endif @endif
</select> </select>
@elseif($k->tipe == 'enum')
<select class="form-select tipe-fk @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" name="{{ $k->kolom }}">
@foreach($k->enum_opsi as $opsi)
<option value="{{ $opsi['value'] }}" {{ old($k->kolom) ?? $value['value_'.$k->tipe] == $opsi['value'] ? 'selected' : '' }}>{{ $opsi['label'] }}</option>
@endforeach
</select>
@else @else
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" <input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}"
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" /> name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" />
@@ -0,0 +1,88 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="card">
<div class="card-header border-bottom mb-4">
<h5 class="card-title mb-0">Lihat Data {{ $tabel->label }}</h5>
</div>
<div class="card-body">
<form id="addUpdateDataForm" action="{{ route('tabel.data.update', [$tabel->id, $value_id, 'program_id' => $program->id]) }}" method="POST" >
@csrf
@method('PUT')
<h6 class="mb-3">Informasi {{ $tabel->label }}</h6>
@if (!$program)
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-data-program">Program<span class="text-danger">*</span></label>
<select name="program_id" class="form-select form-select-sm w-auto" onchange="this.form.submit()">
<option value="">Pilih Program</option>
@foreach($programList as $prog)
<option value="{{ $prog->id }}" {{ request('program_id') == $prog->id ? 'selected' : '' }}>{{ $prog->nama }}</option>
@endforeach
</select>
</div>
</div>
@endif
<div class="row">
@foreach($kolom as $k)
<?php
$value = $values->where('kolom_id', $k->id)->first();
?>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="add-data-{{ $k->kolom }}">{{ $k->label }}<span class="text-danger">*</span></label>
@if($k->tipe == 'varchar')
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" />
@elseif($k->tipe == 'text')
<textarea class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}">{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}</textarea>
@elseif($k->tipe == 'integer')
<input type="number" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" step="1" />
@elseif($k->tipe == 'float')
<input type="number" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" step="any" />
@elseif($k->tipe == 'date')
<input type="date" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" />
@elseif($k->tipe == 'datetime')
<input type="datetime-local" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" />
@elseif($k->tipe == 'boolean')
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ (old($k->kolom) ?? $value['value_'.$k->tipe]) == 1 ? 'Ya' : 'Tidak' }}" />
@elseif($k->tipe == 'foreign_key')
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ (old($k->kolom) ?? $value['value_relasi_label']) }}" />
@elseif($k->tipe == 'enum')
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ (old($k->kolom) ?? $value['value_enum_label']) }}" />
@else
<input type="text" class="form-control @error($k->kolom) is-invalid @enderror" id="add-data-{{ $k->kolom }}" readonly
name="{{ $k->kolom }}" placeholder="Cth: {{ $k->label }}" value="{{ old($k->kolom) ?? $value['value_'.$k->tipe] }}" />
@endif
@error($k->kolom)<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
@endforeach
</div>
<div class="mt-4 text-end">
<a href="{{ route('tabel.data.index', [$tabel->id, 'program_id' => $program->id]) }}" class="btn btn-label-secondary me-2">Kembali</a>
</div>
</form>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
'use strict';
$(document).ready(function () {
});
</script>
@endpush