feat: dummy data fill
closes #869c3khk0
This commit is contained in:
@@ -4,11 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Controller\Booking\Create;
|
namespace App\Controller\Booking\Create;
|
||||||
|
|
||||||
|
use App\BusProNet\Constants;
|
||||||
use App\Controller\Booking\Traits\BookingCreateTrait;
|
use App\Controller\Booking\Traits\BookingCreateTrait;
|
||||||
use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
||||||
use App\Controller\Booking\Traits\ParticipantCardFlowTrait;
|
use App\Controller\Booking\Traits\ParticipantCardFlowTrait;
|
||||||
use App\Form\BookingCreateStep2Type;
|
use App\Form\BookingCreateStep2Type;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
|
use App\Form\Service\DummyDataFillService;
|
||||||
use App\Form\Service\ParticipantFieldOptionsProvider;
|
use App\Form\Service\ParticipantFieldOptionsProvider;
|
||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
@@ -18,6 +20,7 @@ use App\Service\ParticipantPrepopulationService;
|
|||||||
use App\Service\RoomAssignmentService;
|
use App\Service\RoomAssignmentService;
|
||||||
use App\Service\TravelDataService;
|
use App\Service\TravelDataService;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
@@ -43,6 +46,7 @@ class Step2Controller extends AbstractController
|
|||||||
private readonly ParticipantCardDataService $participantCardService,
|
private readonly ParticipantCardDataService $participantCardService,
|
||||||
private readonly ParticipantFieldOptionsProvider $fieldOptionsProvider,
|
private readonly ParticipantFieldOptionsProvider $fieldOptionsProvider,
|
||||||
private readonly ParticipantPrepopulationService $prepopulationService,
|
private readonly ParticipantPrepopulationService $prepopulationService,
|
||||||
|
private readonly DummyDataFillService $dummyDataFillService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +150,22 @@ class Step2Controller extends AbstractController
|
|||||||
|
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
// Detect dummy data fill token — render pre-filled form immediately, skipping validation
|
||||||
|
$isDummyDataFill = $this
|
||||||
|
->dummyDataFillService
|
||||||
|
->isTokenMatch($bookingDto->participants[$index], $bookingDto->getMode())
|
||||||
|
;
|
||||||
|
if (true === $form->isSubmitted() && true === $isDummyDataFill) {
|
||||||
|
$this->dummyDataFillService->fill($bookingDto->participants[$index], $index);
|
||||||
|
$bookingDto->bookingStatus = Constants::BOOKING_STATUS_OPEN;
|
||||||
|
$this->bookingService->saveBookingDto($request, $bookingDto, BookingDto::MODE_CREATE);
|
||||||
|
|
||||||
|
// Recreate form with filled DTO so the view shows the dummy data
|
||||||
|
$form = $this->createParticipantForm($bookingDto, $index);
|
||||||
|
|
||||||
|
return $this->renderParticipantForm($form, $index, $bookingDto);
|
||||||
|
}
|
||||||
|
|
||||||
// Collect notifications from field handlers (run during PRE_SUBMIT)
|
// Collect notifications from field handlers (run during PRE_SUBMIT)
|
||||||
$notifications = $this->collectAndClearNotifications($bookingDto);
|
$notifications = $this->collectAndClearNotifications($bookingDto);
|
||||||
|
|
||||||
@@ -160,18 +180,7 @@ class Step2Controller extends AbstractController
|
|||||||
return $this->redirectToRoute('app_booking_create_step_2');
|
return $this->redirectToRoute('app_booking_create_step_2');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get complete summary data (pricing, rooms, CMS data)
|
return $this->renderParticipantForm($form, $index, $bookingDto);
|
||||||
$summaryData = $this->summaryDataService->getSummaryData($bookingDto);
|
|
||||||
|
|
||||||
$templateData = [
|
|
||||||
'form' => $form->createView(),
|
|
||||||
'participantIndex' => $index,
|
|
||||||
'bookingDto' => $bookingDto,
|
|
||||||
'summaryData' => $summaryData,
|
|
||||||
'refreshRouteName' => 'app_booking_create_step_2_participant_refresh',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->render('booking/create/step_2_participant.html.twig', $templateData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,4 +216,18 @@ class Step2Controller extends AbstractController
|
|||||||
'app_booking_create_step_2_participant_refresh'
|
'app_booking_create_step_2_participant_refresh'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function renderParticipantForm(
|
||||||
|
FormInterface $form,
|
||||||
|
int $index,
|
||||||
|
BookingDto $bookingDto,
|
||||||
|
): Response {
|
||||||
|
return $this->render('booking/create/step_2_participant.html.twig', [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'participantIndex' => $index,
|
||||||
|
'bookingDto' => $bookingDto,
|
||||||
|
'summaryData' => $this->summaryDataService->getSummaryData($bookingDto),
|
||||||
|
'refreshRouteName' => 'app_booking_create_step_2_participant_refresh',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Form\Service;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\Address;
|
||||||
|
use App\Form\Model\BookingDto;
|
||||||
|
use App\Form\Model\ParticipantDto;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills participant forms with generated dummy data for testing and demo workflows.
|
||||||
|
*
|
||||||
|
* When a special token is entered in the lastName field during booking creation,
|
||||||
|
* this service detects it and fills contact data fields with generated values
|
||||||
|
* based on the participant number and current time. Only active in create mode.
|
||||||
|
*/
|
||||||
|
class DummyDataFillService
|
||||||
|
{
|
||||||
|
public const TOKEN = '#KUN#';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the participant's lastName matches the fill token.
|
||||||
|
*
|
||||||
|
* Only matches in create mode to prevent accidental triggering during
|
||||||
|
* editing of existing bookings.
|
||||||
|
*
|
||||||
|
* @param ParticipantDto $participant The participant to check
|
||||||
|
* @param string $mode The booking mode (create or edit)
|
||||||
|
*
|
||||||
|
* @return bool True if the token matches and mode is create
|
||||||
|
*/
|
||||||
|
public function isTokenMatch(ParticipantDto $participant, string $mode): bool
|
||||||
|
{
|
||||||
|
if (BookingDto::MODE_CREATE !== $mode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::TOKEN === $participant->lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the participant DTO with generated dummy personal data.
|
||||||
|
*
|
||||||
|
* Generates firstName, lastName, email, mobile, date of birth and address
|
||||||
|
* values based on the participant number (1-based). The lastName includes
|
||||||
|
* the current time for easy identification of test bookings.
|
||||||
|
*
|
||||||
|
* @param ParticipantDto $participant The participant DTO to fill
|
||||||
|
* @param int $participantIndex The zero-based participant index
|
||||||
|
*/
|
||||||
|
public function fill(ParticipantDto $participant, int $participantIndex): void
|
||||||
|
{
|
||||||
|
$participantNumber = $participantIndex + 1;
|
||||||
|
$now = CarbonImmutable::now();
|
||||||
|
|
||||||
|
$participant->firstName = sprintf('Vorname %d', $participantNumber);
|
||||||
|
$participant->lastName = sprintf('Muster %d %s', $participantNumber, $now->format('H:i'));
|
||||||
|
$participant->mobile = '0171/111111';
|
||||||
|
$participant->email = sprintf('teilnehmer.in%[email protected]', $participantNumber);
|
||||||
|
$participant->dateOfBirth = $now->subYears(20)->toImmutable();
|
||||||
|
|
||||||
|
$address = new Address();
|
||||||
|
$address->street = 'Musterstr. 123';
|
||||||
|
$address->postCode = '99999';
|
||||||
|
$address->city = 'MusterOrt';
|
||||||
|
$address->country = 'Deutschland';
|
||||||
|
$participant->address = $address;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Form\Service;
|
||||||
|
|
||||||
|
use App\Form\Model\BookingDto;
|
||||||
|
use App\Form\Model\ParticipantDto;
|
||||||
|
use App\Form\Service\DummyDataFillService;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DummyDataFillServiceTest extends TestCase
|
||||||
|
{
|
||||||
|
private DummyDataFillService $service;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->service = new DummyDataFillService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTokenMatchInCreateMode(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->lastName = DummyDataFillService::TOKEN;
|
||||||
|
|
||||||
|
$this->assertTrue($this->service->isTokenMatch($participant, BookingDto::MODE_CREATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTokenMatchReturnsFalseInEditMode(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->lastName = DummyDataFillService::TOKEN;
|
||||||
|
|
||||||
|
$this->assertFalse($this->service->isTokenMatch($participant, BookingDto::MODE_EDIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNonMatchingLastNameReturnsFalse(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->lastName = 'Schmidt';
|
||||||
|
|
||||||
|
$this->assertFalse($this->service->isTokenMatch($participant, BookingDto::MODE_CREATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNullLastNameReturnsFalse(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->lastName = null;
|
||||||
|
|
||||||
|
$this->assertFalse($this->service->isTokenMatch($participant, BookingDto::MODE_CREATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsFirstNameWithParticipantNumber(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant, 0);
|
||||||
|
|
||||||
|
$this->assertSame('Vorname 1', $participant->firstName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsLastNameWithParticipantNumberAndTime(): void
|
||||||
|
{
|
||||||
|
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 14, 30));
|
||||||
|
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant, 0);
|
||||||
|
|
||||||
|
$this->assertSame('Muster 1 14:30', $participant->lastName);
|
||||||
|
|
||||||
|
CarbonImmutable::setTestNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsMobilePhone(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant, 0);
|
||||||
|
|
||||||
|
$this->assertSame('0171/111111', $participant->mobile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsEmailWithParticipantNumber(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant, 0);
|
||||||
|
|
||||||
|
$this->assertSame('[email protected]', $participant->email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillUsesOneBasedParticipantNumber(): void
|
||||||
|
{
|
||||||
|
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 9, 5));
|
||||||
|
|
||||||
|
$participant0 = new ParticipantDto();
|
||||||
|
$participant1 = new ParticipantDto();
|
||||||
|
$participant4 = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant0, 0);
|
||||||
|
$this->service->fill($participant1, 1);
|
||||||
|
$this->service->fill($participant4, 4);
|
||||||
|
|
||||||
|
$this->assertSame('Vorname 1', $participant0->firstName);
|
||||||
|
$this->assertSame('Muster 1 09:05', $participant0->lastName);
|
||||||
|
$this->assertSame('[email protected]', $participant0->email);
|
||||||
|
|
||||||
|
$this->assertSame('Vorname 2', $participant1->firstName);
|
||||||
|
$this->assertSame('Muster 2 09:05', $participant1->lastName);
|
||||||
|
$this->assertSame('[email protected]', $participant1->email);
|
||||||
|
|
||||||
|
$this->assertSame('Vorname 5', $participant4->firstName);
|
||||||
|
$this->assertSame('Muster 5 09:05', $participant4->lastName);
|
||||||
|
$this->assertSame('[email protected]', $participant4->email);
|
||||||
|
|
||||||
|
CarbonImmutable::setTestNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsDateOfBirthToTwentyYearsAgo(): void
|
||||||
|
{
|
||||||
|
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 3, 10, 12, 0));
|
||||||
|
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant, 0);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(\DateTimeImmutable::class, $participant->dateOfBirth);
|
||||||
|
$this->assertSame('2006-03-10', $participant->dateOfBirth->format('Y-m-d'));
|
||||||
|
|
||||||
|
CarbonImmutable::setTestNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsAddress(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant, 0);
|
||||||
|
|
||||||
|
$this->assertNotNull($participant->address);
|
||||||
|
$this->assertSame('Musterstr. 123', $participant->address->street);
|
||||||
|
$this->assertSame('99999', $participant->address->postCode);
|
||||||
|
$this->assertSame('MusterOrt', $participant->address->city);
|
||||||
|
$this->assertSame('Deutschland', $participant->address->country);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillSetsAddressForAllParticipants(): void
|
||||||
|
{
|
||||||
|
$participant0 = new ParticipantDto();
|
||||||
|
$participant3 = new ParticipantDto();
|
||||||
|
|
||||||
|
$this->service->fill($participant0, 0);
|
||||||
|
$this->service->fill($participant3, 3);
|
||||||
|
|
||||||
|
$this->assertNotNull($participant0->address);
|
||||||
|
$this->assertNotNull($participant3->address);
|
||||||
|
$this->assertSame('Musterstr. 123', $participant3->address->street);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user