validate([ 'status' => ['nullable', 'in:active,maintenance,closed'], '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); $dumpsites = Dumpsite::query() ->with('cityMunicipality') ->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status'))) ->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(fn ($qq) => $qq->where('name', 'like', $term) ->orWhere('code', 'like', $term) ->orWhere('address_line', 'like', $term)); }) ->orderBy('name') ->paginate($perPage); return $this->ok( DumpsiteResource::collection($dumpsites), null, [ 'page' => $dumpsites->currentPage(), 'per_page' => $dumpsites->perPage(), 'total' => $dumpsites->total(), 'last_page' => $dumpsites->lastPage(), ], ); } public function store(StoreDumpsiteRequest $request): JsonResponse { $data = $request->validated(); $payload = $this->mapPayload($data); $payload['name'] = $data['name']; $payload['code'] = $data['code']; $payload['address_line'] = $data['address_line']; $payload['city_municipality_id'] = $data['city_municipality_id'] ?? null; $payload['accepted_waste_types'] = $data['accepted_waste_types'] ?? null; $payload['operating_hours'] = $data['operating_hours'] ?? null; $payload['capacity_tons'] = $data['capacity_tons'] ?? null; $payload['contact_person'] = $data['contact_person'] ?? null; $payload['contact_phone'] = $data['contact_phone'] ?? null; $payload['permit_number'] = $data['permit_number'] ?? null; $payload['status'] = $data['status'] ?? Dumpsite::STATUS_ACTIVE; $dumpsite = Dumpsite::create($payload); return $this->created( new DumpsiteResource($dumpsite->fresh()->load('cityMunicipality')), 'Dumpsite created', ); } public function show(Dumpsite $dumpsite): JsonResponse { $dumpsite->load('cityMunicipality.province.region'); return $this->ok(new DumpsiteResource($dumpsite)); } public function update(UpdateDumpsiteRequest $request, Dumpsite $dumpsite): JsonResponse { $data = $request->validated(); $payload = $this->mapPayload($data); // Carry through scalar/json fields that mapPayload doesn't touch. foreach ([ 'name', 'code', 'address_line', 'city_municipality_id', 'accepted_waste_types', 'operating_hours', 'capacity_tons', 'contact_person', 'contact_phone', 'permit_number', 'status', ] as $key) { if (array_key_exists($key, $data)) { $payload[$key] = $data[$key]; } } $dumpsite->update($payload); return $this->ok( new DumpsiteResource($dumpsite->fresh()->load('cityMunicipality')), 'Dumpsite updated', ); } public function destroy(Dumpsite $dumpsite): JsonResponse { $dumpsite->delete(); return $this->ok(null, 'Dumpsite deleted'); } /** * Translate lat/lng + boundary_polygon[{lat,lng}, ...] inputs into * spatial Polygon/Point objects suitable for assignment to the model. */ private function mapPayload(array $data): array { $payload = []; if (isset($data['lat'], $data['lng'])) { $payload['coordinates'] = new Point((float) $data['lat'], (float) $data['lng'], 4326); } if (array_key_exists('boundary_polygon', $data)) { $payload['boundary_polygon'] = $data['boundary_polygon'] ? $this->buildPolygon($data['boundary_polygon']) : null; } return $payload; } 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); } }