feat: entité CustomerContact pour contacts additionnels d'un client

Entity CustomerContact :
- customer (ManyToOne, CASCADE) : client parent
- firstName, lastName : nom/prénom du contact
- email : adresse email (nullable)
- phone : téléphone (nullable)
- role : fonction dans l'entreprise (Gérant, Comptable, etc.)
- isBillingEmail : si true, reçoit les factures par email
- createdAt / updatedAt : timestamps
- getFullName() : prénom + nom

CustomerContactTest (2 tests, 19 assertions) :
- testConstructor : valeurs par défaut
- testSetters : tous les setters/getters

Migration : CREATE TABLE customer_contact avec FK customer ON DELETE CASCADE

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-04-04 11:13:33 +02:00
parent 5369682f35
commit 7ae63dd996
3 changed files with 256 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260404091315 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 customer_contact (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, email VARCHAR(255) DEFAULT NULL, phone VARCHAR(20) DEFAULT NULL, role VARCHAR(100) DEFAULT NULL, is_billing_email BOOLEAN 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 INDEX IDX_50BF42869395C3F3 ON customer_contact (customer_id)');
$this->addSql('ALTER TABLE customer_contact ADD CONSTRAINT FK_50BF42869395C3F3 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 customer_contact DROP CONSTRAINT FK_50BF42869395C3F3');
$this->addSql('DROP TABLE customer_contact');
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class CustomerContact
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(targetEntity: Customer::class)]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private Customer $customer;
#[ORM\Column(length: 255)]
private string $firstName;
#[ORM\Column(length: 255)]
private string $lastName;
#[ORM\Column(length: 255, nullable: true)]
private ?string $email = null;
#[ORM\Column(length: 20, nullable: true)]
private ?string $phone = null;
#[ORM\Column(length: 100, nullable: true)]
private ?string $role = null;
#[ORM\Column]
private bool $isBillingEmail = false;
#[ORM\Column]
private \DateTimeImmutable $createdAt;
#[ORM\Column(nullable: true)]
private ?\DateTimeImmutable $updatedAt = null;
public function __construct(Customer $customer, string $firstName, string $lastName)
{
$this->customer = $customer;
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->createdAt = new \DateTimeImmutable();
}
public function getId(): ?int
{
return $this->id;
}
public function getCustomer(): Customer
{
return $this->customer;
}
public function getFirstName(): string
{
return $this->firstName;
}
public function setFirstName(string $firstName): static
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): string
{
return $this->lastName;
}
public function setLastName(string $lastName): static
{
$this->lastName = $lastName;
return $this;
}
public function getFullName(): string
{
return $this->firstName.' '.$this->lastName;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): static
{
$this->email = $email;
return $this;
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): static
{
$this->phone = $phone;
return $this;
}
public function getRole(): ?string
{
return $this->role;
}
public function setRole(?string $role): static
{
$this->role = $role;
return $this;
}
public function isBillingEmail(): bool
{
return $this->isBillingEmail;
}
public function setIsBillingEmail(bool $isBillingEmail): static
{
$this->isBillingEmail = $isBillingEmail;
return $this;
}
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;
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Tests\Entity;
use App\Entity\Customer;
use App\Entity\CustomerContact;
use App\Entity\User;
use PHPUnit\Framework\TestCase;
class CustomerContactTest extends TestCase
{
private function createCustomer(): Customer
{
$user = new User();
$user->setEmail('c@t.com');
$user->setFirstName('C');
$user->setLastName('T');
$user->setPassword('h');
return new Customer($user);
}
public function testConstructor(): void
{
$customer = $this->createCustomer();
$contact = new CustomerContact($customer, 'Jean', 'Dupont');
$this->assertNull($contact->getId());
$this->assertSame($customer, $contact->getCustomer());
$this->assertSame('Jean', $contact->getFirstName());
$this->assertSame('Dupont', $contact->getLastName());
$this->assertSame('Jean Dupont', $contact->getFullName());
$this->assertNull($contact->getEmail());
$this->assertNull($contact->getPhone());
$this->assertNull($contact->getRole());
$this->assertFalse($contact->isBillingEmail());
$this->assertInstanceOf(\DateTimeImmutable::class, $contact->getCreatedAt());
$this->assertNull($contact->getUpdatedAt());
}
public function testSetters(): void
{
$contact = new CustomerContact($this->createCustomer(), 'A', 'B');
$contact->setFirstName('Marie');
$this->assertSame('Marie', $contact->getFirstName());
$contact->setLastName('Martin');
$this->assertSame('Martin', $contact->getLastName());
$this->assertSame('Marie Martin', $contact->getFullName());
$contact->setEmail('marie@entreprise.fr');
$this->assertSame('marie@entreprise.fr', $contact->getEmail());
$contact->setPhone('0612345678');
$this->assertSame('0612345678', $contact->getPhone());
$contact->setRole('Comptable');
$this->assertSame('Comptable', $contact->getRole());
$contact->setIsBillingEmail(true);
$this->assertTrue($contact->isBillingEmail());
$now = new \DateTimeImmutable();
$contact->setUpdatedAt($now);
$this->assertSame($now, $contact->getUpdatedAt());
}
}