31 - Add Scenario entity, migration and repository

This commit is contained in:
myrmidex 2026-06-18 23:49:24 +02:00
parent cda83371c4
commit 7b87c6d665
4 changed files with 246 additions and 0 deletions

View file

@ -0,0 +1,29 @@
<?php
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260618213556 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE scenario (id UUID NOT NULL, distribution_mode VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description TEXT DEFAULT NULL, PRIMARY KEY (id))');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE scenario');
}
}

72
src/Entity/Scenario.php Normal file
View file

@ -0,0 +1,72 @@
<?php
namespace App\Entity;
use App\Enum\DistributionMode;
use App\Repository\ScenarioRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\UuidV7;
#[ORM\Entity(repositoryClass: ScenarioRepository::class)]
class Scenario
{
#[ORM\Id]
#[ORM\Column(type: 'uuid')]
private UuidV7 $id;
#[ORM\Column(enumType: DistributionMode::class)]
private DistributionMode $distributionMode = DistributionMode::EVEN;
#[ORM\Column(length: 255)]
private string $name;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
public function __construct()
{
$this->id = new UuidV7();
}
public function getId(): UuidV7
{
return $this->id;
}
public function getDistributionMode(): DistributionMode
{
return $this->distributionMode;
}
public function getName(): string
{
return $this->name;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDistributionMode(DistributionMode $distributionMode): static
{
$this->distributionMode = $distributionMode;
return $this;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\Scenario;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Scenario>
*/
class ScenarioRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Scenario::class);
}
}

View file

@ -0,0 +1,127 @@
<?php
namespace App\Tests\Entity;
use App\Entity\Scenario;
use App\Enum\DistributionMode;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Uid\UuidV7;
final class ScenarioPersistenceTest extends KernelTestCase
{
private EntityManagerInterface $em;
protected function setUp(): void
{
self::bootKernel();
$this->em = self::getContainer()->get(EntityManagerInterface::class);
}
public function testItPersistsAScenarioWithAUuidId(): void
{
$scenario = new Scenario();
$scenario->setName('Household Budget');
$this->em->persist($scenario);
$this->em->flush();
$id = $scenario->getId();
self::assertInstanceOf(UuidV7::class, $id);
$this->em->clear();
$reloaded = $this->em->find(Scenario::class, $id);
self::assertNotNull($reloaded, 'Scenario must be retrievable from the database after an identity-map clear.');
self::assertInstanceOf(UuidV7::class, $reloaded->getId());
self::assertSame('Household Budget', $reloaded->getName());
}
public function testDistributionModeDefaultsToEvenWhenNotExplicitlySet(): void
{
$scenario = new Scenario();
$scenario->setName('Default Mode Scenario');
$this->em->persist($scenario);
$this->em->flush();
$id = $scenario->getId();
$this->em->clear();
$reloaded = $this->em->find(Scenario::class, $id);
self::assertNotNull($reloaded);
self::assertSame(
DistributionMode::EVEN,
$reloaded->getDistributionMode(),
'distribution_mode must default to EVEN when not explicitly set.',
);
}
public function testItRoundTripsAnExplicitlySetPriorityDistributionMode(): void
{
$scenario = new Scenario();
$scenario->setName('Priority Mode Scenario');
$scenario->setDistributionMode(DistributionMode::PRIORITY);
$this->em->persist($scenario);
$this->em->flush();
$id = $scenario->getId();
$this->em->clear();
$reloaded = $this->em->find(Scenario::class, $id);
self::assertNotNull($reloaded);
self::assertInstanceOf(
DistributionMode::class,
$reloaded->getDistributionMode(),
'distribution_mode must hydrate as a DistributionMode enum instance, not a raw string.',
);
self::assertSame(
DistributionMode::PRIORITY,
$reloaded->getDistributionMode(),
'An explicitly set PRIORITY distribution_mode must survive a flush + clear + reload round-trip.',
);
}
public function testDescriptionRoundTripsWhenSet(): void
{
$scenario = new Scenario();
$scenario->setName('Described Scenario');
$scenario->setDescription('Covers rent, groceries, and the emergency buffer.');
$this->em->persist($scenario);
$this->em->flush();
$id = $scenario->getId();
$this->em->clear();
$reloaded = $this->em->find(Scenario::class, $id);
self::assertNotNull($reloaded);
self::assertSame('Covers rent, groceries, and the emergency buffer.', $reloaded->getDescription());
}
public function testDescriptionIsNullableAndRemainsNullWhenNotSet(): void
{
$scenario = new Scenario();
$scenario->setName('Undescribed Scenario');
$this->em->persist($scenario);
$this->em->flush();
$id = $scenario->getId();
$this->em->clear();
$reloaded = $this->em->find(Scenario::class, $id);
self::assertNotNull($reloaded);
self::assertNull($reloaded->getDescription());
}
}