forked from admin/services_core
204 lines
6.4 KiB
PHP
204 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Wilayah;
|
|
|
|
use App\Models\WilayahDesa;
|
|
use App\Models\WilayahKabupaten;
|
|
use App\Models\WilayahKecamatan;
|
|
use App\Models\WilayahProvinsi;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class WilayahService
|
|
{
|
|
private const MODELS = [
|
|
'provinsi' => WilayahProvinsi::class,
|
|
'kabupaten' => WilayahKabupaten::class,
|
|
'kecamatan' => WilayahKecamatan::class,
|
|
'desa' => WilayahDesa::class,
|
|
];
|
|
|
|
private const PARENTS = [
|
|
'kabupaten' => 'provinsi_id',
|
|
'kecamatan' => 'kabupaten_id',
|
|
'desa' => 'kecamatan_id',
|
|
];
|
|
|
|
private const RELATIONS = [
|
|
'provinsi' => [],
|
|
'kabupaten' => ['provinsi'],
|
|
'kecamatan' => ['kabupaten.provinsi'],
|
|
'desa' => ['kecamatan.kabupaten.provinsi'],
|
|
];
|
|
|
|
public function list(string $tingkat, array $filters = [])
|
|
{
|
|
$model = $this->model($tingkat);
|
|
|
|
return $model::query()
|
|
->with(self::RELATIONS[$tingkat])
|
|
->when($filters['search'] ?? null, function ($query, $search) {
|
|
$value = mb_strtolower($search);
|
|
$query->where(function ($scope) use ($value) {
|
|
$scope->whereRaw('LOWER(kode) LIKE ?', ["%{$value}%"])
|
|
->orWhereRaw('LOWER(nama) LIKE ?', ["%{$value}%"]);
|
|
});
|
|
})
|
|
->when(
|
|
isset(self::PARENTS[$tingkat]) && ! empty($filters[self::PARENTS[$tingkat]]),
|
|
fn ($query) => $query->where(
|
|
self::PARENTS[$tingkat],
|
|
$filters[self::PARENTS[$tingkat]]
|
|
)
|
|
)
|
|
->orderBy(
|
|
$filters['sort_by'] ?? 'nama',
|
|
$filters['sort_direction'] ?? 'asc'
|
|
)
|
|
->paginate($filters['per_page'] ?? 10);
|
|
}
|
|
|
|
public function options(string $tingkat, array $filters = [], ?int $parentId = null)
|
|
{
|
|
$model = $this->model($tingkat);
|
|
$parentColumn = self::PARENTS[$tingkat] ?? null;
|
|
|
|
return $model::query()
|
|
->select(['id', 'kode', 'nama'])
|
|
->when(
|
|
$parentColumn && $parentId,
|
|
fn ($query) => $query->where($parentColumn, $parentId)
|
|
)
|
|
->when($filters['search'] ?? null, function ($query, $search) {
|
|
$value = mb_strtolower($search);
|
|
$query->where(function ($scope) use ($value) {
|
|
$scope->whereRaw('LOWER(kode) LIKE ?', ["%{$value}%"])
|
|
->orWhereRaw('LOWER(nama) LIKE ?', ["%{$value}%"]);
|
|
});
|
|
})
|
|
->orderBy('nama')
|
|
->get();
|
|
}
|
|
|
|
public function create(string $tingkat, array $data): Model
|
|
{
|
|
$model = $this->model($tingkat);
|
|
|
|
return $model::create($this->payload($tingkat, $data))
|
|
->load(self::RELATIONS[$tingkat]);
|
|
}
|
|
|
|
public function find(string $tingkat, int $id): Model
|
|
{
|
|
$model = $this->model($tingkat);
|
|
|
|
return $model::with(self::RELATIONS[$tingkat])->findOrFail($id);
|
|
}
|
|
|
|
public function update(string $tingkat, int $id, array $data): Model
|
|
{
|
|
$wilayah = $this->find($tingkat, $id);
|
|
$wilayah->update($this->payload($tingkat, $data));
|
|
|
|
return $wilayah->fresh(self::RELATIONS[$tingkat]);
|
|
}
|
|
|
|
public function delete(string $tingkat, int $id): void
|
|
{
|
|
$wilayah = $this->find($tingkat, $id);
|
|
$childRelation = match ($tingkat) {
|
|
'provinsi' => 'kabupaten',
|
|
'kabupaten' => 'kecamatan',
|
|
'kecamatan' => 'desa',
|
|
default => null,
|
|
};
|
|
|
|
if ($childRelation && $wilayah->{$childRelation}()->exists()) {
|
|
throw ValidationException::withMessages([
|
|
'wilayah' => "Wilayah {$tingkat} tidak dapat dihapus karena masih memiliki data di bawahnya.",
|
|
]);
|
|
}
|
|
|
|
$wilayah->delete();
|
|
}
|
|
|
|
public function alamatLengkap(array $filters): array
|
|
{
|
|
if (! empty($filters['desa_id'])) {
|
|
$desa = WilayahDesa::with('kecamatan.kabupaten.provinsi')->findOrFail($filters['desa_id']);
|
|
|
|
return $this->addressPayload(
|
|
$desa->kecamatan?->kabupaten?->provinsi,
|
|
$desa->kecamatan?->kabupaten,
|
|
$desa->kecamatan,
|
|
$desa
|
|
);
|
|
}
|
|
|
|
if (! empty($filters['kecamatan_id'])) {
|
|
$kecamatan = WilayahKecamatan::with('kabupaten.provinsi')->findOrFail($filters['kecamatan_id']);
|
|
|
|
return $this->addressPayload(
|
|
$kecamatan->kabupaten?->provinsi,
|
|
$kecamatan->kabupaten,
|
|
$kecamatan
|
|
);
|
|
}
|
|
|
|
if (! empty($filters['kabupaten_id'])) {
|
|
$kabupaten = WilayahKabupaten::with('provinsi')->findOrFail($filters['kabupaten_id']);
|
|
|
|
return $this->addressPayload($kabupaten->provinsi, $kabupaten);
|
|
}
|
|
|
|
$provinsi = WilayahProvinsi::findOrFail($filters['provinsi_id']);
|
|
|
|
return $this->addressPayload($provinsi);
|
|
}
|
|
|
|
private function model(string $tingkat): string
|
|
{
|
|
abort_unless(isset(self::MODELS[$tingkat]), 404, 'Tingkat wilayah tidak ditemukan.');
|
|
|
|
return self::MODELS[$tingkat];
|
|
}
|
|
|
|
private function payload(string $tingkat, array $data): array
|
|
{
|
|
$fields = ['kode', 'nama'];
|
|
if (isset(self::PARENTS[$tingkat])) {
|
|
$fields[] = self::PARENTS[$tingkat];
|
|
}
|
|
|
|
return collect($data)->only($fields)->all();
|
|
}
|
|
|
|
private function addressPayload(
|
|
?WilayahProvinsi $provinsi,
|
|
?WilayahKabupaten $kabupaten = null,
|
|
?WilayahKecamatan $kecamatan = null,
|
|
?WilayahDesa $desa = null
|
|
): array {
|
|
$node = fn ($item) => $item ? [
|
|
'id' => $item->id,
|
|
'kode' => $item->kode,
|
|
'nama' => $item->nama,
|
|
] : null;
|
|
|
|
$parts = array_filter([
|
|
$desa ? "Desa/Kelurahan {$desa->nama}" : null,
|
|
$kecamatan ? "Kecamatan {$kecamatan->nama}" : null,
|
|
$kabupaten?->nama,
|
|
$provinsi ? $provinsi->nama : null,
|
|
]);
|
|
|
|
return [
|
|
'desa' => $node($desa),
|
|
'kecamatan' => $node($kecamatan),
|
|
'kabupaten' => $node($kabupaten),
|
|
'provinsi' => $node($provinsi),
|
|
'alamat_wilayah' => implode(', ', $parts),
|
|
];
|
|
}
|
|
}
|