feat: reduce session payload

This commit is contained in:
Björn Fromme
2026-03-16 12:03:00 +01:00
parent a1518c06fb
commit 6fd5a218a3
2 changed files with 97 additions and 8 deletions
+58
View File
@@ -325,4 +325,62 @@ class BookingDto
{ {
return AgencyLoader::INTERNAL_AGENCY_CODE === $this->agencyCode; return AgencyLoader::INTERNAL_AGENCY_CODE === $this->agencyCode;
} }
/**
* Controls session serialization to exclude the heavy Travel object graph.
*
* Replaces the full Travel object with just its integer ID. The Booking's
* travelData reference is also removed since it points to the same object.
* BookingService::hydrate() restores the Travel from cache after session read.
*
* @return array<string, mixed>
*/
public function __serialize(): array
{
$data = get_object_vars($this);
// Replace the full Travel object graph with just its ID
$data['travel'] = $this->travel->id;
// Clone Booking to avoid mutating the live object, then strip its
// travelData reference which points to the same heavy Travel graph
if (null !== $this->booking) {
$booking = clone $this->booking;
$booking->travelData = null;
$data['booking'] = $booking;
}
return $data;
}
/**
* Restores the DTO from session data with a minimal Travel placeholder.
*
* Creates a Travel object containing only the ID. BookingService::hydrate()
* replaces this with the full Travel from cache on every session read.
*
* @param array<string, mixed> $data
*/
public function __unserialize(array $data): void
{
// Extract the travel ID before the property loop — 'travel' in the
// serialized data is an int, not a Travel object
$travelId = $data['travel'];
unset($data['travel']);
// Skip keys that no longer exist as declared properties to avoid
// dynamic property creation (deprecated since PHP 8.2)
foreach ($data as $key => $value) {
if (false === property_exists($this, $key)) {
continue;
}
$this->$key = $value;
}
// Create a skeleton Travel with only the ID; BookingService::hydrate()
// replaces this with the full object from cache
$travel = new Travel();
$travel->id = $travelId;
$this->travel = $travel;
}
} }
+39 -8
View File
@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Service; namespace App\Service;
use App\BusProNet\Constants; use App\BusProNet\Constants;
@@ -80,14 +82,12 @@ class BookingService
*/ */
public function getOrCreateBookingCreateDto(Request $request): BookingDto public function getOrCreateBookingCreateDto(Request $request): BookingDto
{ {
$bookingCreateDto = $request->getSession()->get(self::BOOKING_CREATE_KEY); $bookingDto = $this->getBookingDto($request, BookingDto::MODE_CREATE);
// Return existing DTO from session if available if (null !== $bookingDto) {
if (null !== $bookingCreateDto) { return $bookingDto;
return $bookingCreateDto;
} }
// No session found - user must go through proper init flow
throw new BookingSessionNotFoundException(); throw new BookingSessionNotFoundException();
} }
@@ -105,12 +105,15 @@ class BookingService
} }
/** /**
* Retrieves the booking DTO from the session. * Retrieves the booking DTO from the session and restores the Travel object.
*
* After deserialization the DTO contains only a Travel skeleton with the ID.
* This method replaces it with the full Travel from cache via hydrate().
* *
* @param Request $request The HTTP request containing session data * @param Request $request The HTTP request containing session data
* @param string $mode The booking mode (create/edit) * @param string $mode The booking mode (create/edit)
* *
* @return BookingDto|null The booking DTO from session or null if not found * @return BookingDto|null The booking DTO or null if not found
*/ */
public function getBookingDto(Request $request, string $mode): ?BookingDto public function getBookingDto(Request $request, string $mode): ?BookingDto
{ {
@@ -121,7 +124,10 @@ class BookingService
return null; return null;
} }
return $session->get($sessionKey); $bookingDto = $session->get($sessionKey);
$this->hydrate($bookingDto);
return $bookingDto;
} }
/** /**
@@ -148,6 +154,31 @@ class BookingService
return BookingDto::MODE_EDIT === $mode ? self::BOOKING_EDIT_KEY : self::BOOKING_CREATE_KEY; return BookingDto::MODE_EDIT === $mode ? self::BOOKING_EDIT_KEY : self::BOOKING_CREATE_KEY;
} }
/**
* Restores the full Travel object from cache after session deserialization.
*
* BookingDto::__serialize() replaces Travel with just its ID to keep session
* payloads small. This method fetches the complete Travel from the
* TravelDataService cache and sets it on both the DTO and the Booking reference.
*/
private function hydrate(BookingDto $bookingDto): void
{
$travel = $this->travelDataService->getTravelData(
$bookingDto->travel->id,
$bookingDto->hotelId
);
if (null === $travel) {
return;
}
$bookingDto->travel = $travel;
if (null !== $bookingDto->booking) {
$bookingDto->booking->travelData = $travel;
}
}
/** /**
* Clears all booking-related session data. * Clears all booking-related session data.
* *