# Generate reservation code
# Definition
This action generates a unique reservation code using a non-ambiguous alphabet.
class GenerateReservationCode
{
use AsAction;
const UNAMBIGUOUS_ALPHABET = 'BCDFGHJLMNPRSTVWXYZ2456789';
public function handle(int $characters = 7): string
{
do {
$code = $this->generateCode($characters);
} while(Reservation::where('code', $code)->exists());
return $code;
}
protected function generateCode(int $characters): string
{
return substr(str_shuffle(str_repeat(static::UNAMBIGUOUS_ALPHABET, $characters)), 0, $characters);
}
}
# Using as an object
In a real-life application this action would typically be nested inside another action that create a new reservations.
class CreateNewReservation
{
use AsAction;
public function handle(User $user, Concert $concert, int $tickets = 1): Reservation
{
return $user->reservations()->create([
'concert_id' => $concert->id,
'price' => $concert->getTicketPrice() * $tickets,
'code' => GenerateReservationCode::run(),
]);
}
}
# Using as a fake instance
The advantage of using ::make()
or ::run()
is that it will resolve the action from the container. That means we can then easily swap its implementation for a mock when testing.
/** @test */
public function it_generates_a_unique_code_when_creating_a_new_reservation()
{
// Given an existing user and concert.
$user = User::factory()->create();
$concert = Concert::factory()->create();
// And given we mock the code generator.
GenerateReservationCode::shouldRun()->andReturn('ABCD234');
// When we create a new reservation for that user and that concert.
$reservation = CreateNewReservation::run($user, $concert);
// Then we saved the expected reservation code.
$this->assertSame('ABCD234', $reservation->code);
}