53 lines
2.0 KiB
PHP
53 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Concerns;
|
|
|
|
use App\Models\Operator;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
/**
|
|
* The one place a console Livewire component resolves "who is signed in"
|
|
* and decides what happens when the answer is nobody.
|
|
*
|
|
* A Livewire action reaches its component through its own request to
|
|
* /livewire/update, separate from the request that first rendered the page —
|
|
* a modal especially, reachable without the page's own route middleware (see
|
|
* R20 in CLAUDE.md). An operator whose session has ended by the time an
|
|
* action runs still reaches this code, and Auth::guard('operator')->user()
|
|
* comes back null. Four components each dereferenced it unguarded
|
|
* ($operator->password, ->id, ->two_factor_recovery_codes, …), turning that
|
|
* into a 500 instead of a sign-in prompt.
|
|
*
|
|
* currentOperator() cannot throw its way out of the null case. Livewire only
|
|
* turns $this->redirect() into a browser navigation once the calling action
|
|
* returns NORMALLY: the redirect is queued as component state and picked up
|
|
* during Livewire's own dehydrate step (Livewire\Features\SupportRedirects),
|
|
* which runs strictly after the called method returns — an uncaught
|
|
* exception during the call skips it entirely and Livewire ships back a bare
|
|
* error response instead (confirmed by reading
|
|
* Livewire\Mechanisms\HandleComponents::update() and
|
|
* Livewire\Mechanisms\HandleRequests::handleUpdate(), which catches nothing
|
|
* but \TypeError). So this returns null and every caller checks for it:
|
|
*
|
|
* if (! $operator = $this->currentOperator()) {
|
|
* return;
|
|
* }
|
|
*
|
|
* That one-line guard is the only thing left for a caller to get wrong; the
|
|
* redirect target and the mechanism live here once, so the four cannot drift
|
|
* apart the way the original unguarded dereferences did.
|
|
*/
|
|
trait ResolvesOperator
|
|
{
|
|
protected function currentOperator(): ?Operator
|
|
{
|
|
$operator = Auth::guard('operator')->user();
|
|
|
|
if ($operator === null) {
|
|
$this->redirect(route('admin.login'));
|
|
}
|
|
|
|
return $operator;
|
|
}
|
|
}
|