Gute Frage. Da gibt es theoretisch viele verschiedene Möglichkeiten.
Auf die Idee, eine Middleware dafür einzusetzen, wäre ich jetzt eher nicht gekommen.
Da würde ich dir spontan also eher von abraten. Ist aber sicher auch irgendwie möglich.
Folgend stelle ich mal die wesentlichen Optionen dar. Je nach deinen konkreten Anforderungen kannst du dir dann die passende Variante raussuchen.
Option 1: Eloquent Accessor definieren
Ein Eloquent Accessor ist im Prinzip eine spezielle Methode, die du deinem entsprechenden Eloquent-Model hinzufügen kannst.
Das besondere an der Methode ist, dass sich dadurch praktisch ein Datenbankattribut faken lässt, was sich bei jeder Abfrage ändern kann bzw. neu berechnet wird und daher nicht gewöhnlich als Feld in der Datenbank eingetragen ist.
Wenn du dein Eloquent Model also sowieso schon an die Views, wo du die Anzahl aller neuen Mails jetzt benötigst, weitergibst, dann kannst du das Model so ganz einfach erweitern bzw. mit "on the fly" berechneten/abgefragten Werten bestücken.
Dein Fall geht allerdings etwas über den klassischen Anwendungsfall hinaus, wie er in der Doku beschrieben ist.
Mein Laravel-Wissen ist leider schon wieder ein bisschen eingestaubt, ich denke aber trotzdem, dass das folgende Code-Beispiel (auch im Kontext des Eloquent Accessor's) funktioniert.
public function getNewMailsCountAttribute()
{
return self::where('status', '=', '0')->where('read', '=', '0')->where('user_id', Auth::user()->id)->count();
}
Wenn du das Ganze dann noch als Attribut an dein Model anhängen lässt, kannst du das ganz normal, wie bei anderen Attributen, abrufen.
protected $appends = [
'new_mails_count',
];
Link zur Dokumentation:
https://laravel.com/docs/7.x/eloquent-mutators#defining-an-accessor
Option 2: View::share() in einem Service Provider
Am Nächsten an deine Idee einer globalen Variable kommt wohl diese Option ran.
In Laravel sind ja gewisse Sache grundsätzlich für Views freigegeben, sodass du beispielsweise immer auf den jeweiligen authentifizierten User Zugriff hast.
Das gleiche Prinzip kannst du dir ebenfalls zunutze machen.
In einem beliebigen/eigenen Service Provider in der
boot()
-Methode, bspw.
AppServiceProvider
, kannst du über die View-Facade die Methode
View::share()
aufrufen und so beliebige Werte/Daten an alle Views weitergeben.
public function boot()
{
View::share('newMailsCount', Mail::where('status', '=', '0')->where('read', '=', '0')->where('user_id', Auth::user()->id)->count());
}
Edit: Nachträgliche Korrektur: Ein Service Provider ist bei Daten, die auf dem authentifizierten Nutzer oder sonstigen Session-Infos beruhen, nicht einsetzbar.
Diese Option funktioniert also im konkreten Beispielfall nicht, sonst ist es aber ein recht guter Weg.
Wenn der Zugriff auf Session-Daten erforderlich ist, kann stattdessen eine Middleware als Ort für den
View::share()
-Aufruf eingesetzt werden.
Nähere Infos im weiteren Verlauf des Themas.
Link zur Doku:
https://laravel.com/docs/7.x/views#passing-data-to-views
Option 3: View Composer
View Composer ermöglichen es dir, alle benötigten Daten an einem zentralen Ort für die jeweiligen Views bereitzustellen.
Der View Composer wird entsprechend immer beim Rendern einer View aufgerufen.
Das sorgt dafür, dass die dafür nötige Logik nicht im Controller geschrieben werden muss und es gleichzeitig deutlich flexiblere und umfangreichere Möglichkeiten des Umgangs mit der Datenweitergabe an Views im Vergleich zu Option 1 und 2 gibt.
Auch hier brauchen wir erstmal wieder einen Service Provider (
ViewServiceProvider
), worüber wir unsere View Composer registrieren und bestimmten (oder auch allen) Views zuordnen.
public function boot() {
View::composer(
[ 'view-1', 'view-2', ... ],
MailViewComposer::class
);
}
Die eigentliche Logik wird dann in diesem Fall als Klasse
MailViewComposer
abstrahiert. Alternativ wäre auch eine Closure/anonyme Funktion möglich.
namespace App\Http\View\Composers;
class MailViewComposer
{
protected $mail;
public function __construct(Mail $mail)
{
$this->mail = $user;
}
public function compose(View $view)
{
$view->with('newMailCount', Mail::where('status', '=', '0')->where('read', '=', '0')->where('user_id', Auth::user()->id)->count());
}
}
Link zur Doku:
https://laravel.com/docs/7.x/views#view-composers
Gut, das sind, glaube ich, die wesentlichen Optionen.
Ich hoffe, ich habe keine groben Schnitzer eingebaut. Ist, wie gesagt, schon länger her, dass ich intensiver mit Laravel zu tun hatte.
Der Code versteht sich zudem natürlich nur als Ausschnitt und ist nicht vollständig.
Zum Ende noch ein kleiner Tipp, um deine Abfrage für die Anzahl der neuen Mails ein bisschen schöner zu gestalten:
Wenn du mittels
where()
einen Vergleich mit dem Operator
=
anstellst, musst du diesen nicht explizit angeben.
Dadurch, dass du die Attribute
status
und
read
wahrscheinlich als einstelliger
tinyint
(in Laravel-Migrations-Sprache
boolean
) in der DB speicherst, solltest du zudem auch ein Integer-Wert übergeben (Anführungszeichen weg).
Genauso würde wohl auch ein
bool
funktionieren.
Mail::where('status', 0)->where('read', 0)->where('user_id', Auth::user()->id)->count()
Ansonsten ist die Abfrage, wenn man das an mehreren Stellen schreiben muss, recht lang.
Da bietet es sich an, eine gesonderte Methode im Eloquent Model anzulegen, z.B. so:
public function newMailsCount(User $user) : int {
self::where('status', 0)->where('read', 0)->where('user_id', $user->id)->count();
}