validate([ 'from' => 'nullable|date', 'to' => 'nullable|date', 'category' => 'nullable|string', 'location' => 'nullable|string', 'limit' => 'nullable|integer|min:1|max:100', ]); $from = ($validated['from'] ?? null) ? Carbon::parse($validated['from'])->startOfDay() : now()->startOfDay(); $to = ($validated['to'] ?? null) ? Carbon::parse($validated['to'])->endOfDay() : now()->addMonths(3)->endOfDay(); $limit = $validated['limit'] ?? 20; $query = Event::published() ->with(['source', 'location', 'occurrences' => function ($q) use ($from, $to) { $q->whereBetween('start_datetime', [$from, $to]) ->where('status', 'scheduled') ->orderBy('start_datetime'); }]) ->whereHas('occurrences', function ($q) use ($from, $to) { $q->whereBetween('start_datetime', [$from, $to]) ->where('status', 'scheduled'); }) ->orderBy('title'); // Filter nach Kategorie if (!empty($validated['category'])) { $query->byCategory($validated['category']); } // Filter nach Ort if (!empty($validated['location'])) { $query->byLocation($validated['location']); } $events = $query->paginate($limit); return response()->json([ 'success' => true, 'data' => $events->items(), 'pagination' => [ 'total' => $events->total(), 'per_page' => $events->perPage(), 'current_page' => $events->currentPage(), 'last_page' => $events->lastPage(), ] ]); } #[OA\Get( path: "/api/events/{event}", summary: "Einzelnes Event anzeigen", description: "Zeigt ein einzelnes veröffentlichtes Event mit allen seinen Terminen", tags: ["Events"], parameters: [ new OA\Parameter( name: "event", in: "path", required: true, description: "Event ID", schema: new OA\Schema(type: "integer") ), ], responses: [ new OA\Response( response: 200, description: "Event Details", content: new OA\JsonContent(type: "object") ), new OA\Response( response: 404, description: "Event nicht gefunden" ), ] )] public function show(Event $event) { // Nur veröffentlichte Events anzeigen if ($event->status !== 'published') { return response()->json([ 'success' => false, 'message' => 'Event nicht gefunden.', ], 404); } $event->load(['source', 'occurrences' => function ($query) { $query->where('status', 'scheduled') ->orderBy('start_datetime'); }]); return response()->json([ 'success' => true, 'data' => $event, ]); } #[OA\Get( path: "/api/events/categories/list", summary: "Verfügbare Kategorien", description: "Listet alle verfügbaren Event-Kategorien auf", tags: ["Utilities"], responses: [ new OA\Response( response: 200, description: "Liste der Kategorien", content: new OA\JsonContent( type: "object", properties: [ "success" => new OA\Property(type: "boolean"), "data" => new OA\Property(type: "array", items: new OA\Items(type: "string")) ] ) ), ] )] public function categories() { $categories = Event::published() ->distinct() ->pluck('category') ->filter() ->sort() ->values(); return response()->json([ 'success' => true, 'data' => $categories, ]); } #[OA\Get( path: "/api/events/locations/list", summary: "Verfügbare Veranstaltungsorte", description: "Listet alle verfügbaren Veranstaltungsorte mit vollständigen Adressinformationen auf", tags: ["Utilities"], responses: [ new OA\Response( response: 200, description: "Liste der Veranstaltungsorte", content: new OA\JsonContent(type: "object") ), ] )] public function locations() { $locations = Location::orderBy('city') ->orderBy('name') ->get() ->map(function ($location) { return [ 'id' => $location->id, 'name' => $location->name, 'address' => [ 'street' => $location->street, 'house_number' => $location->house_number, 'postal_code' => $location->postal_code, 'city' => $location->city, 'state' => $location->state, 'country' => $location->country, 'full_address' => $location->full_address, 'short_address' => $location->short_address, ], 'contact' => [ 'phone' => $location->phone, 'email' => $location->email, 'website' => $location->website, ], 'event_count' => $location->events()->published()->count(), ]; }); return response()->json([ 'success' => true, 'data' => $locations, ]); } }