From 98db87eb054204c4c5dccc275405a7d31b27ab10 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Sat, 4 Apr 2026 21:06:41 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20entit=C3=A9=20Website=20li=C3=A9e=20?= =?UTF-8?q?=C3=A0=20Customer=20avec=20UUID,=20type=20et=20state=20machine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entity Website : - customer (ManyToOne, CASCADE) : client propriétaire - name : nom du site - uuid : UUID v4 auto-généré (unique, 36 chars) - type : vitrine | ecommerce - state : created → install_progress → open → suspended → closed - createdAt / updatedAt (auto sur setState) - isOpen() : vérifie si state === open WebsiteTest (5 tests, 20 assertions) : - testConstructor : valeurs par défaut, uuid 36 chars, type vitrine - testConstructorEcommerce : type ecommerce - testSetters : name, type, updatedAt - testState : transitions created→install_progress→open→suspended→closed - testUuidUnique : 2 sites ont des uuid différents Dépendance : symfony/uid ajouté pour Uuid::v4() Migration : CREATE TABLE website avec FK customer, uuid unique Co-Authored-By: Claude Opus 4.6 (1M context) --- composer.json | 1 + composer.lock | 163 ++++++++++++++++++++++++++- migrations/Version20260404190626.php | 35 ++++++ src/Entity/Website.php | 129 +++++++++++++++++++++ tests/Entity/WebsiteTest.php | 87 ++++++++++++++ 5 files changed, 414 insertions(+), 1 deletion(-) create mode 100644 migrations/Version20260404190626.php create mode 100644 src/Entity/Website.php create mode 100644 tests/Entity/WebsiteTest.php diff --git a/composer.json b/composer.json index ea4c98a..bd24a82 100644 --- a/composer.json +++ b/composer.json @@ -56,6 +56,7 @@ "symfony/string": "8.0.*", "symfony/translation": "8.0.*", "symfony/twig-bundle": "8.0.*", + "symfony/uid": "8.0.*", "symfony/validator": "8.0.*", "symfony/web-link": "8.0.*", "symfony/yaml": "8.0.*", diff --git a/composer.lock b/composer.lock index 2c31c94..c625ec3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c89df7b95449dfc734150e681bc309f2", + "content-hash": "9234633550a505d8b9b7ed8ee0118699", "packages": [ { "name": "async-aws/core", @@ -8628,6 +8628,89 @@ ], "time": "2025-06-23T16:12:55+00:00" }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/process", "version": "v8.0.5", @@ -10301,6 +10384,84 @@ ], "time": "2026-03-04T13:55:34+00:00" }, + { + "name": "symfony/uid", + "version": "v8.0.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "f63fa6096a24147283bce4d29327d285326438e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/f63fa6096a24147283bce4d29327d285326438e0", + "reference": "f63fa6096a24147283bce4d29327d285326438e0", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v8.0.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-30T15:14:47+00:00" + }, { "name": "symfony/validator", "version": "v8.0.7", diff --git a/migrations/Version20260404190626.php b/migrations/Version20260404190626.php new file mode 100644 index 0000000..eba7ebf --- /dev/null +++ b/migrations/Version20260404190626.php @@ -0,0 +1,35 @@ +addSql('CREATE TABLE website (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, uuid VARCHAR(36) NOT NULL, type VARCHAR(20) NOT NULL, state VARCHAR(20) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, customer_id INT NOT NULL, PRIMARY KEY (id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_476F5DE7D17F50A6 ON website (uuid)'); + $this->addSql('CREATE INDEX IDX_476F5DE79395C3F3 ON website (customer_id)'); + $this->addSql('ALTER TABLE website ADD CONSTRAINT FK_476F5DE79395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id) ON DELETE CASCADE NOT DEFERRABLE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE website DROP CONSTRAINT FK_476F5DE79395C3F3'); + $this->addSql('DROP TABLE website'); + } +} diff --git a/src/Entity/Website.php b/src/Entity/Website.php new file mode 100644 index 0000000..525a979 --- /dev/null +++ b/src/Entity/Website.php @@ -0,0 +1,129 @@ +customer = $customer; + $this->name = $name; + $this->type = $type; + $this->uuid = Uuid::v4()->toRfc4122(); + $this->createdAt = new \DateTimeImmutable(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getCustomer(): Customer + { + return $this->customer; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function getUuid(): string + { + return $this->uuid; + } + + public function getType(): string + { + return $this->type; + } + + public function setType(string $type): static + { + $this->type = $type; + + return $this; + } + + public function getState(): string + { + return $this->state; + } + + public function setState(string $state): static + { + $this->state = $state; + $this->updatedAt = new \DateTimeImmutable(); + + return $this; + } + + public function isOpen(): bool + { + return self::STATE_OPEN === $this->state; + } + + public function getCreatedAt(): \DateTimeImmutable + { + return $this->createdAt; + } + + public function getUpdatedAt(): ?\DateTimeImmutable + { + return $this->updatedAt; + } + + public function setUpdatedAt(?\DateTimeImmutable $updatedAt): static + { + $this->updatedAt = $updatedAt; + + return $this; + } +} diff --git a/tests/Entity/WebsiteTest.php b/tests/Entity/WebsiteTest.php new file mode 100644 index 0000000..9e4e813 --- /dev/null +++ b/tests/Entity/WebsiteTest.php @@ -0,0 +1,87 @@ +setEmail('c@t.com'); + $user->setFirstName('C'); + $user->setLastName('T'); + $user->setPassword('h'); + + return new Customer($user); + } + + public function testConstructor(): void + { + $customer = $this->createCustomer(); + $site = new Website($customer, 'Mon Site'); + + $this->assertNull($site->getId()); + $this->assertSame($customer, $site->getCustomer()); + $this->assertSame('Mon Site', $site->getName()); + $this->assertSame(36, \strlen($site->getUuid())); + $this->assertSame(Website::TYPE_VITRINE, $site->getType()); + $this->assertSame(Website::STATE_CREATED, $site->getState()); + $this->assertInstanceOf(\DateTimeImmutable::class, $site->getCreatedAt()); + $this->assertNull($site->getUpdatedAt()); + } + + public function testConstructorEcommerce(): void + { + $site = new Website($this->createCustomer(), 'Boutique', Website::TYPE_ECOMMERCE); + $this->assertSame(Website::TYPE_ECOMMERCE, $site->getType()); + } + + public function testSetters(): void + { + $site = new Website($this->createCustomer(), 'Test'); + + $site->setName('Nouveau nom'); + $this->assertSame('Nouveau nom', $site->getName()); + + $site->setType(Website::TYPE_ECOMMERCE); + $this->assertSame(Website::TYPE_ECOMMERCE, $site->getType()); + + $now = new \DateTimeImmutable(); + $site->setUpdatedAt($now); + $this->assertSame($now, $site->getUpdatedAt()); + } + + public function testState(): void + { + $site = new Website($this->createCustomer(), 'Test'); + $this->assertFalse($site->isOpen()); + + $site->setState(Website::STATE_INSTALL_PROGRESS); + $this->assertSame(Website::STATE_INSTALL_PROGRESS, $site->getState()); + $this->assertFalse($site->isOpen()); + + $site->setState(Website::STATE_OPEN); + $this->assertTrue($site->isOpen()); + $this->assertInstanceOf(\DateTimeImmutable::class, $site->getUpdatedAt()); + + $site->setState(Website::STATE_SUSPENDED); + $this->assertFalse($site->isOpen()); + + $site->setState(Website::STATE_CLOSED); + $this->assertFalse($site->isOpen()); + } + + public function testUuidUnique(): void + { + $customer = $this->createCustomer(); + $site1 = new Website($customer, 'Site 1'); + $site2 = new Website($customer, 'Site 2'); + + $this->assertNotSame($site1->getUuid(), $site2->getUuid()); + } +}