id(); $calendars = Calendar::query() ->select('calendars.*', 'ci.displayname as instance_displayname') // ← add ->join('calendarinstances as ci', 'ci.calendarid', '=', 'calendars.id') ->where('ci.principaluri', $principal) ->orderBy('ci.displayname') ->with(['meta']) // no need to eager-load full instances any more ->get(); return view('calendars.index', compact('calendars')); } public function create() { return view('calendars.create'); } /** * create sabre calendar + meta */ public function store(Request $request) { $data = $request->validate([ 'name' => 'required|string|max:100', 'description' => 'nullable|string|max:255', 'timezone' => 'required|string', 'color' => 'nullable|regex:/^#[0-9A-Fa-f]{6}$/', ]); // update master calendar entry $calId = DB::table('calendars')->insertGetId([ 'synctoken' => 1, 'components' => 'VEVENT', // or 'VEVENT,VTODO' if you add tasks ]); // update the calendar instance row $instance = CalendarInstance::create([ 'calendarid' => $calId, 'principaluri' => 'principals/'.auth()->id(), 'uri' => Str::uuid(), 'displayname' => $data['name'], 'description' => $data['description'] ?? null, 'calendarcolor'=> $data['color'] ?? null, 'timezone' => $data['timezone'], ]); // update calendar meta $instance->meta()->create([ 'calendar_id' => $instanceId, 'color' => $data['color'] ?? null, 'created_at' => now(), 'updated_at' => now(), ]); return redirect()->route('calendars.index'); } /** * show calendar details */ public function show(Calendar $calendar) { $this->authorize('view', $calendar); $calendar->load([ 'meta', 'instances' => fn ($q) => $q->where('principaluri', 'principals/'.auth()->id()), ]); /* grab the single instance for convenience in the view */ $instance = $calendar->instances->first(); $caldavUrl = $instance?->caldavUrl(); // null-safe /* events + meta, newest first */ $events = $calendar->events() ->with('meta') ->orderByDesc('lastmodified') ->get(); return view( 'calendars.show', compact('calendar', 'instance', 'events', 'caldavUrl') ); } /** * edit calendar page */ public function edit(Calendar $calendar) { $this->authorize('update', $calendar); $calendar->load([ 'meta', 'instances' => fn ($q) => $q->where('principaluri', 'principals/'.auth()->id()), ]); $instance = $calendar->instances->first(); // may be null but shouldn’t return view('calendars.edit', compact('calendar', 'instance')); } /** * update sabre + meta records */ public function update(Request $request, Calendar $calendar) { $this->authorize('update', $calendar); $data = $request->validate([ 'name' => 'required|string|max:100', 'description' => 'nullable|string|max:255', 'timezone' => 'required|string', 'color' => 'nullable|regex:/^#[0-9A-Fa-f]{6}$/', ]); // update the instance row $calendar->instances() ->where('principaluri', 'principals/'.auth()->id()) ->update([ 'displayname' => $data['name'], 'description' => $data['description'] ?? '', 'calendarcolor' => $data['color'] ?? null, 'timezone' => $data['timezone'], ]); // bump synctoken on master calendar row $calendar->increment('synctoken'); // update calendar meta (our table) $calendar->meta()->updateOrCreate([], [ 'color' => $data['color'] ?? null] ); return redirect() ->route('calendars.show', $calendar) ->with('toast', __('Calendar saved successfully!')); } /** * delete calendar @todo */ public function destroy(Calendar $calendar) { $this->authorize('delete', $calendar); $calendar->delete(); // cascades to meta via FK return redirect()->route('calendars.index'); } }