195 lines
7.1 KiB
PHP
195 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1\SuperAdmin;
|
|
|
|
use App\Http\Controllers\Api\V1\ApiController;
|
|
use App\Http\Requests\SuperAdmin\StoreBarangayRequest;
|
|
use App\Http\Requests\SuperAdmin\UpdateBarangayRequest;
|
|
use App\Http\Resources\BarangayResource;
|
|
use App\Models\Barangay;
|
|
use App\Models\CityMunicipality;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use MatanYadaev\EloquentSpatial\Objects\LineString;
|
|
use MatanYadaev\EloquentSpatial\Objects\Point;
|
|
use MatanYadaev\EloquentSpatial\Objects\Polygon;
|
|
|
|
class SuperAdminBarangayController extends ApiController
|
|
{
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'city_municipality_id' => ['nullable', 'integer'],
|
|
'q' => ['nullable', 'string', 'max:100'],
|
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
|
]);
|
|
|
|
$perPage = (int) $request->input('per_page', 25);
|
|
|
|
$barangays = Barangay::query()
|
|
->with(['cityMunicipality.province'])
|
|
->withSum('households', 'household_size')
|
|
->when($request->filled('city_municipality_id'), fn ($q) => $q->where('city_municipality_id', $request->integer('city_municipality_id')))
|
|
->when($request->filled('q'), function ($q) use ($request) {
|
|
$term = '%'.$request->string('q').'%';
|
|
$q->where(function ($qq) use ($term) {
|
|
$qq->where('name', 'like', $term)
|
|
->orWhere('code', 'like', $term)
|
|
->orWhere('psgc_code', 'like', $term);
|
|
});
|
|
})
|
|
->orderBy('name')
|
|
->paginate($perPage);
|
|
|
|
return $this->ok(BarangayResource::collection($barangays));
|
|
}
|
|
|
|
public function store(StoreBarangayRequest $request): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
|
|
$boundary = $this->buildPolygon($data['boundary']);
|
|
$centroid = $this->calculateCentroid($boundary);
|
|
|
|
// Spatial validation check removed as per user request
|
|
|
|
// Code auto-generation if empty
|
|
$cityId = $data['city_municipality_id'];
|
|
$city = CityMunicipality::findOrFail($cityId);
|
|
if (empty($data['psgc_code'])) {
|
|
$prefix = substr($city->psgc_code, 0, 9);
|
|
$maxLocal = Barangay::where('psgc_code', 'like', $prefix.'%')
|
|
->whereRaw('LENGTH(psgc_code) = 12')
|
|
->orderBy('psgc_code', 'desc')
|
|
->first();
|
|
$suffix = $maxLocal ? ((int) substr($maxLocal->psgc_code, -3) + 1) : 1;
|
|
$data['psgc_code'] = $prefix.str_pad($suffix, 3, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
if (empty($data['code'])) {
|
|
$prefix = substr($city->code, 0, 12);
|
|
$maxLocal = Barangay::where('code', 'like', $prefix.'%')
|
|
->orderBy('code', 'desc')
|
|
->first();
|
|
$suffix = $maxLocal ? ((int) substr(strrchr($maxLocal->code, '-'), 1) + 1) : 1;
|
|
$data['code'] = $prefix.'-'.str_pad($suffix, 3, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
$barangay = Barangay::create([
|
|
'name' => $data['name'],
|
|
'city_municipality_id' => $cityId,
|
|
'psgc_code' => $data['psgc_code'],
|
|
'code' => $data['code'],
|
|
'urban_rural' => $data['urban_rural'],
|
|
'population' => $data['population'],
|
|
'boundary' => $boundary,
|
|
'centroid' => $centroid,
|
|
]);
|
|
|
|
return $this->created(new BarangayResource($barangay), 'Barangay created successfully');
|
|
}
|
|
|
|
public function show(Barangay $barangay): JsonResponse
|
|
{
|
|
$barangay->load(['cityMunicipality.province']);
|
|
|
|
return $this->ok(new BarangayResource($barangay));
|
|
}
|
|
|
|
public function update(UpdateBarangayRequest $request, Barangay $barangay): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
|
|
$boundary = $this->buildPolygon($data['boundary']);
|
|
$centroid = $this->calculateCentroid($boundary);
|
|
|
|
// Spatial validation check removed as per user request
|
|
|
|
// Code auto-generation if empty
|
|
$cityId = $data['city_municipality_id'];
|
|
$city = CityMunicipality::findOrFail($cityId);
|
|
if (empty($data['psgc_code'])) {
|
|
$prefix = substr($city->psgc_code, 0, 9);
|
|
$maxLocal = Barangay::where('psgc_code', 'like', $prefix.'%')
|
|
->whereRaw('LENGTH(psgc_code) = 12')
|
|
->orderBy('psgc_code', 'desc')
|
|
->first();
|
|
$suffix = $maxLocal ? ((int) substr($maxLocal->psgc_code, -3) + 1) : 1;
|
|
$data['psgc_code'] = $prefix.str_pad($suffix, 3, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
if (empty($data['code'])) {
|
|
$prefix = substr($city->code, 0, 12);
|
|
$maxLocal = Barangay::where('code', 'like', $prefix.'%')
|
|
->orderBy('code', 'desc')
|
|
->first();
|
|
$suffix = $maxLocal ? ((int) substr(strrchr($maxLocal->code, '-'), 1) + 1) : 1;
|
|
$data['code'] = $prefix.'-'.str_pad($suffix, 3, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
$barangay->update([
|
|
'name' => $data['name'],
|
|
'city_municipality_id' => $cityId,
|
|
'psgc_code' => $data['psgc_code'],
|
|
'code' => $data['code'],
|
|
'urban_rural' => $data['urban_rural'],
|
|
'population' => $data['population'],
|
|
'boundary' => $boundary,
|
|
'centroid' => $centroid,
|
|
]);
|
|
|
|
return $this->ok(new BarangayResource($barangay), 'Barangay updated successfully');
|
|
}
|
|
|
|
public function destroy(Barangay $barangay): JsonResponse
|
|
{
|
|
$barangay->delete();
|
|
|
|
return $this->ok(null, 'Barangay deleted successfully');
|
|
}
|
|
|
|
private function buildPolygon(array $points): Polygon
|
|
{
|
|
$ring = array_map(
|
|
fn ($p) => new Point((float) $p['lat'], (float) $p['lng'], 4326),
|
|
$points,
|
|
);
|
|
|
|
$first = $ring[0];
|
|
$last = $ring[count($ring) - 1];
|
|
if ($first->latitude !== $last->latitude || $first->longitude !== $last->longitude) {
|
|
$ring[] = new Point($first->latitude, $first->longitude, 4326);
|
|
}
|
|
|
|
return new Polygon([new LineString($ring)], 4326);
|
|
}
|
|
|
|
private function calculateCentroid(Polygon $polygon): Point
|
|
{
|
|
$res = DB::selectOne(
|
|
'SELECT ST_AsText(ST_SRID(ST_Centroid(ST_GeomFromText(?, 0)), 4326)) as wkt',
|
|
[$polygon->toWkt()]
|
|
);
|
|
|
|
if ($res && preg_match('/POINT\(([^ ]+) ([^ ]+)\)/', $res->wkt, $matches)) {
|
|
$lat = (float) $matches[1];
|
|
$lng = (float) $matches[2];
|
|
|
|
return new Point($lat, $lng, 4326);
|
|
}
|
|
|
|
$rings = $polygon->getGeometries();
|
|
$ring = $rings->first();
|
|
if ($ring) {
|
|
$coords = $ring->getGeometries();
|
|
$lats = $coords->map(fn ($p) => $p->latitude)->all();
|
|
$lngs = $coords->map(fn ($p) => $p->longitude)->all();
|
|
|
|
return new Point(array_sum($lats) / count($lats), array_sum($lngs) / count($lngs), 4326);
|
|
}
|
|
|
|
return new Point(0, 0, 4326);
|
|
}
|
|
}
|