Files
Gnuboard7/app/Extension/HookContextCapture.php
T
2026-04-20 20:37:49 +09:00

101 lines
3.5 KiB
PHP

<?php
namespace App\Extension;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
/**
* 훅 리스너 큐 디스패치 시 요청 컨텍스트 캡처/복원 헬퍼.
*
* 큐 워커는 별도 프로세스이므로 Auth, Request, App 로케일이 모두 리셋된다.
* 디스패치 시점(원래 요청 컨텍스트)에 capture()로 스냅샷을 만들고,
* Job::handle() 진입 시 restore()로 복원하여 리스너가 평소처럼 동작하도록 한다.
*
* 코어 기본 항목: user_id, ip_address, user_agent, locale, path
* 확장점:
* - capture() 마지막에 'hook.context.capture' 필터 발화 (플러그인 키 추가 가능)
* - restore() 진입 직후 'hook.context.restore' 액션 발화 (플러그인 복원 로직)
*/
class HookContextCapture
{
/**
* 현재 요청 컨텍스트를 스냅샷으로 캡처합니다.
*
* dispatch 클로저에서 호출되므로 Auth/Request가 살아있는 상태입니다.
*
* @return array<string, mixed>
*/
public static function capture(): array
{
$request = request();
$context = [
'user_id' => Auth::id(),
'ip_address' => $request?->ip(),
'user_agent' => $request?->userAgent(),
'locale' => App::getLocale(),
'path' => $request?->path(),
];
return HookManager::applyFilters('hook.context.capture', $context);
}
/**
* 캡처된 컨텍스트를 큐 워커 환경에 복원합니다.
*
* Job::handle() 진입 직후 호출됩니다. Job 종료 시 컨테이너가 폐기되므로
* 별도 원복(finally) 처리는 불필요합니다.
*
* @param array<string, mixed> $context
*/
public static function restore(array $context): void
{
// 확장 복원 로직 (코어보다 먼저 실행 — 플러그인이 코어 동작에 영향 주는 컨텍스트 설정 가능)
HookManager::doAction('hook.context.restore', $context);
// 로케일
if (! empty($context['locale'])) {
App::setLocale($context['locale']);
}
// 인증 사용자
// 주의: Sanctum의 RequestGuard는 onceUsingId()를 지원하지 않으므로
// User를 직접 조회하여 setUser()로 주입합니다. (Job 종료 시 컨테이너 폐기되어 자동 해제)
if (! empty($context['user_id'])) {
$user = User::find($context['user_id']);
if ($user !== null) {
Auth::setUser($user);
}
}
// Request 재구성 (IP, User-Agent, Path)
// ResolvesActivityLogType::resolveLogType() 등이 request()->path() / is('api/admin/*') 를
// 큐 워커 컨텍스트에서 호출하기 때문에 path 복원이 필수입니다.
$server = [];
if (! empty($context['ip_address'])) {
$server['REMOTE_ADDR'] = $context['ip_address'];
}
if (! empty($context['user_agent'])) {
$server['HTTP_USER_AGENT'] = $context['user_agent'];
}
if (! empty($context['path'])) {
$server['REQUEST_URI'] = '/'.ltrim($context['path'], '/');
}
if ($server !== []) {
$request = Request::create(
$server['REQUEST_URI'] ?? '/',
'GET',
[],
[],
[],
$server,
);
app()->instance('request', $request);
}
}
}