presseportale/app/Http/Middleware/LogApiUsage.php
Kevin Adametz 31d407d3ad Optimierung 3.4: Performance (Logging terminable, Single-Purchase memoisiert)
- LogApiUsage als terminable Middleware: der ApiUsageLog-INSERT laeuft nach
  gesendeter Antwort und verlaengert nicht mehr die Request-Dauer. Startzeit
  wird ueber ein Request-Attribut uebergeben (terminate() laeuft auf frischer
  Instanz).
- User::openSinglePurchaseCount() memoisiert die offenen Einmalkaeufe pro
  Request. Vorher wurde derselbe grantingSubmission-Count im Status-Widget
  mehrfach (Quota-Total, Quota-Remaining, openSinglePurchases) plus ein
  exists() in hasActiveBooking abgesetzt -> jetzt eine Query.
- CustomerCompanyContext::selectedCompany() nutzt eine einzige first()-Query
  statt exists()+first(); das Verwerfen nicht (mehr) erreichbarer Auswahlen
  bleibt erhalten.
- LegacySubscriptionService::cancelBundleFor() ist ein einziges Bulk-Update
  statt Update-pro-Iteration (UserPaymentOption hat keine Observer/Events).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:05:07 +00:00

60 lines
2 KiB
PHP

<?php
namespace App\Http\Middleware;
use App\Models\ApiUsageLog;
use Closure;
use Illuminate\Http\Request;
use Laravel\Sanctum\PersonalAccessToken;
use Symfony\Component\HttpFoundation\Response;
class LogApiUsage
{
private const StartedAtKey = 'api_usage_started_at';
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$request->attributes->set(self::StartedAtKey, microtime(true));
return $next($request);
}
/**
* Der INSERT läuft erst nach gesendeter Antwort (terminable Middleware) und
* verlängert damit nicht mehr die wahrgenommene Request-Dauer. Der Startwert
* wird über die Request-Attribute übergeben, da `terminate()` auf einer
* frischen Middleware-Instanz aufgerufen wird.
*/
public function terminate(Request $request, Response $response): void
{
$startedAt = (float) $request->attributes->get(self::StartedAtKey, microtime(true));
$this->writeLog($request, $response, $startedAt);
}
private function writeLog(Request $request, Response $response, float $startedAt): void
{
$token = $request->user()?->currentAccessToken();
$tokenId = $token instanceof PersonalAccessToken && (int) $token->getKey() > 0
? (int) $token->getKey()
: null;
ApiUsageLog::query()->create([
'user_id' => $request->user()?->id,
'personal_access_token_id' => $tokenId,
'method' => $request->method(),
'path' => '/'.$request->path(),
'route_name' => $request->route()?->getName(),
'status_code' => $response->getStatusCode(),
'ip_address' => $request->ip(),
'user_agent' => mb_substr((string) $request->userAgent(), 0, 512),
'duration_ms' => (int) round((microtime(true) - $startedAt) * 1000),
'requested_at' => now(),
]);
}
}