From 5cf4b0f9eac94d6c990882af1c5ed1b220f6ab1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 4 Mar 2026 11:25:23 +0100 Subject: [PATCH] feat: shortened and filename-safe request ids --- docs/technical-documentation.md | 4 +-- src/BusProNet/ApiClient.php | 4 ++- src/EventListener/RequestIdListener.php | 8 +++++- src/Service/RequestIdGenerator.php | 22 +++++++++++++++ tests/BusProNet/ApiClientReceiveTest.php | 2 ++ tests/Service/RequestIdGeneratorTest.php | 34 ++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/Service/RequestIdGenerator.php create mode 100644 tests/Service/RequestIdGeneratorTest.php diff --git a/docs/technical-documentation.md b/docs/technical-documentation.md index 95b7dc0..5249632 100644 --- a/docs/technical-documentation.md +++ b/docs/technical-documentation.md @@ -1197,8 +1197,8 @@ Persists INFO+ level logs to `LogEntry` entity. Replaces message placeholders wi When debug mode is enabled, API requests/responses are dumped to `var/bpn/`: ``` -{request_id}_1_request.xml -{request_id}_1_response.xml +r-00m8z7k58a-8k1pvd9q_1_request.xml +r-00m8z7k58a-8k1pvd9q_1_response.xml ``` View via Admin Panel: Admin → Log → XML Dumps action. diff --git a/src/BusProNet/ApiClient.php b/src/BusProNet/ApiClient.php index 4113b55..47797df 100644 --- a/src/BusProNet/ApiClient.php +++ b/src/BusProNet/ApiClient.php @@ -22,6 +22,7 @@ use App\BusProNet\Model\Travel; use App\BusProNet\XmlParser\ApiResponseParser; use App\Form\Model\BookingDto; use App\Form\Model\RegistrationDto; +use App\Service\RequestIdGenerator; use League\Flysystem\FilesystemException; use League\Flysystem\FilesystemOperator; use Psr\Log\LoggerInterface; @@ -58,6 +59,7 @@ class ApiClient private readonly LoggerInterface $logger, private readonly BookingDataProcessor $bookingDataProcessor, private readonly RequestStack $requestStack, + private readonly RequestIdGenerator $requestIdGenerator, array $options, ) { $this->config = $this->resolveOptions($options); @@ -762,7 +764,7 @@ class ApiClient private function getRequestId(): string { $baseId = $this->requestStack->getMainRequest()?->attributes->get('request_id') - ?? date(DATE_ATOM); + ?? $this->requestIdGenerator->generateBaseId(); return $baseId.'_'.++$this->requestCounter; } diff --git a/src/EventListener/RequestIdListener.php b/src/EventListener/RequestIdListener.php index 036c373..e3abc50 100644 --- a/src/EventListener/RequestIdListener.php +++ b/src/EventListener/RequestIdListener.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\EventListener; +use App\Service\RequestIdGenerator; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; @@ -11,13 +12,18 @@ use Symfony\Component\HttpKernel\KernelEvents; #[AsEventListener(event: KernelEvents::REQUEST, priority: 255)] class RequestIdListener { + public function __construct( + private readonly RequestIdGenerator $requestIdGenerator, + ) { + } + public function __invoke(RequestEvent $event): void { if (false === $event->isMainRequest()) { return; } - $requestId = date(DATE_ATOM).uniqid(); + $requestId = $this->requestIdGenerator->generateBaseId(); $event->getRequest()->attributes->set('request_id', $requestId); } } diff --git a/src/Service/RequestIdGenerator.php b/src/Service/RequestIdGenerator.php new file mode 100644 index 0000000..76c528c --- /dev/null +++ b/src/Service/RequestIdGenerator.php @@ -0,0 +1,22 @@ +createMock(LoggerInterface::class), $this->createMock(BookingDataProcessor::class), new RequestStack(), + new RequestIdGenerator(), [ 'bpn_username' => 'test', 'bpn_password' => 'test', diff --git a/tests/Service/RequestIdGeneratorTest.php b/tests/Service/RequestIdGeneratorTest.php new file mode 100644 index 0000000..06af547 --- /dev/null +++ b/tests/Service/RequestIdGeneratorTest.php @@ -0,0 +1,34 @@ +generateBaseId(); + + self::assertMatchesRegularExpression('/^r-[0-9a-z]{10}-[0-9a-z]{8}$/', $requestId); + } + + public function testGeneratedIdsAreSortableByTime(): void + { + $generator = new RequestIdGenerator(); + + $first = $generator->generateBaseId(); + usleep(2_000); + $second = $generator->generateBaseId(); + usleep(2_000); + $third = $generator->generateBaseId(); + + self::assertTrue($first < $second); + self::assertTrue($second < $third); + } +}