save()`), deshalb greift der Observer auch bei * Importen. Wer die Tabelle künftig per Query-Builder in Massen ändert, muss * anschließend `php artisan press-releases:reindex-search` laufen lassen — * Model-Events greifen dort nicht. */ class PressReleaseSearchObserver { public function created(PressRelease $pressRelease): void { PressReleaseSearchIndex::syncFor($pressRelease); } /** * Nur neu indizieren, wenn sich wirklich ein durchsuchbares Feld geändert * hat — der Textkörper macht den Großteil der Datenmenge aus, ihn bei * jedem Statuswechsel neu zu schreiben wäre reine Verschwendung. * * Bewusst `updated` statt `saved` mit einer `wasRecentlyCreated`-Abfrage: * Dieses Kennzeichen bleibt für die Lebensdauer der Instanz gesetzt, ein * späteres Update auf demselben Objekt hätte den Index also trotzdem * jedes Mal neu geschrieben. */ public function updated(PressRelease $pressRelease): void { if (! $pressRelease->wasChanged(PressReleaseSearchIndex::SourceColumns)) { return; } PressReleaseSearchIndex::syncFor($pressRelease); } /** * Hartes Löschen räumt der Fremdschlüssel (cascadeOnDelete) mit ab; ein * Soft Delete lässt die Index-Zeile bewusst stehen, weil die Suche * ohnehin über `press_releases` filtert und gelöschte PMs dort schon * ausgeschlossen sind. */ public function forceDeleted(PressRelease $pressRelease): void { PressReleaseSearchIndex::query()->whereKey($pressRelease->getKey())->delete(); } }