31 - Add Scenario entity, migration and repository
This commit is contained in:
parent
cda83371c4
commit
7b87c6d665
4 changed files with 246 additions and 0 deletions
29
migrations/Version20260618213556.php
Normal file
29
migrations/Version20260618213556.php
Normal 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
72
src/Entity/Scenario.php
Normal 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;
|
||||
}
|
||||
}
|
||||
18
src/Repository/ScenarioRepository.php
Normal file
18
src/Repository/ScenarioRepository.php
Normal 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);
|
||||
}
|
||||
}
|
||||
127
tests/Entity/ScenarioPersistenceTest.php
Normal file
127
tests/Entity/ScenarioPersistenceTest.php
Normal 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());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue