Skip to content

Entity Creation Guide

Anleitung zum Erstellen von Entities in der Appiyon-Plattform.

Übersicht

Entities sind die Kern-Datenstrukturen der Anwendung. Sie repräsentieren persistente Domänen-Objekte.

Layer-Zuordnung

Entities werden je nach Funktion in verschiedenen Layern platziert:

  • Infrastructure: System-Administration (Admin, AdminSession, etc.)
  • Shared: Gemeinsame Utilities (AuditLog)
  • Foundation: Basis-Bausteine (Tenant, User)
  • Core: Kontext-freie Primitives (Country, Language)
  • Domain: Business-Logik (App, Developer, Category, etc.)

Entity-Struktur

Basis-Template

php
<?php

declare(strict_types=1);

namespace App\Appi\[Layer]\[Module]\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'table_name')]
class EntityName
{
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'IDENTITY')]
    #[ORM\Column(type: Types::INTEGER)]
    private ?int $id = null;

    #[ORM\Column(type: Types::STRING, length: 255)]
    private string $name;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $createdAt;

    public function __construct(string $name)
    {
        $this->name = $name;
        $this->createdAt = new \DateTimeImmutable();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }

    public function getCreatedAt(): \DateTimeImmutable
    {
        return $this->createdAt;
    }
}

Wichtige Patterns

1. Soft Deletes

Für Audit-Trail-Integrität sollten wichtige Entities Soft Deletes unterstützen:

php
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
private ?\DateTimeImmutable $deletedAt = null;

public function delete(): void
{
    $this->deletedAt = new \DateTimeImmutable();
}

public function isDeleted(): bool
{
    return $this->deletedAt !== null;
}

2. Timestamps

Standard-Timestamps für Created/Updated:

php
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
private \DateTimeImmutable $createdAt;

#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
private \DateTimeImmutable $updatedAt;

public function __construct()
{
    $this->createdAt = new \DateTimeImmutable();
    $this->updatedAt = new \DateTimeImmutable();
}

public function touch(): void
{
    $this->updatedAt = new \DateTimeImmutable();
}

3. Unique Constraints

php
#[ORM\Entity]
#[ORM\Table(name: 'admins')]
#[ORM\UniqueConstraint(name: 'admins_email_unique', columns: ['email'])]
class Admin
{
    #[ORM\Column(type: Types::STRING, length: 255)]
    private string $email;
}

4. Indices für Performance

php
#[ORM\Entity]
#[ORM\Table(name: 'admin_sessions')]
#[ORM\Index(name: 'idx_admin_sessions_admin_id', columns: ['admin_id'])]
#[ORM\Index(name: 'idx_admin_sessions_last_activity', columns: ['last_activity'])]
class AdminSession
{
    // ...
}

5. Foreign Keys mit Relations

php
#[ORM\ManyToOne(targetEntity: Admin::class)]
#[ORM\JoinColumn(name: 'admin_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
private Admin $admin;

6. ULID Support

php
use Symfony\Component\Uid\Ulid;

#[ORM\Column(type: 'ulid', unique: true)]
private Ulid $ulid;

public function __construct()
{
    $this->ulid = new Ulid();
}

ID-Strategien

IDENTITY (Auto-Increment)

Standard für PostgreSQL:

php
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
#[ORM\Column(type: Types::INTEGER)]
private ?int $id = null;

UUID/ULID

Für verteilte Systeme:

php
use Symfony\Component\Uid\Ulid;

#[ORM\Id]
#[ORM\Column(type: 'ulid')]
private Ulid $id;

public function __construct()
{
    $this->id = new Ulid();
}

Value Objects in Entities

Entities sollten Value Objects für komplexe Validierung nutzen:

php
use App\Appi\Infrastructure\Admin\ValueObject\AdminEmail;
use App\Appi\Infrastructure\Admin\ValueObject\AdminPassword;

#[ORM\Column(type: Types::STRING, length: 255)]
private string $email;

#[ORM\Column(type: Types::STRING, length: 255)]
private string $password;

public function __construct(
    string $name,
    AdminEmail $email,
    AdminPassword $password
) {
    $this->name = $name;
    $this->email = $email->getValue();
    $this->password = $password->getHash();
}

Migration erstellen

Nach Entity-Erstellung:

bash
php bin/console doctrine:migrations:diff

Dies erstellt automatisch eine Migration im entsprechenden Layer-Ordner.

Best Practices

  1. Immutability: Konstruktor setzt initiale Werte, Setter nur wo nötig
  2. Type Safety: Immer strict types verwenden
  3. Validation: In Value Objects auslagern, nicht in Entity
  4. Business Logic: In Use Cases, nicht in Entity
  5. Naming: Singular für Entity-Namen (Admin, nicht Admins)
  6. Table Names: Plural für Tabellen-Namen (admins, nicht admin)

Beispiel: Admin Entity

Siehe vollständiges Beispiel in: src/Appi/Infrastructure/Admin/Entity/Admin.php

php
#[ORM\Entity]
#[ORM\Table(name: 'admins')]
#[ORM\UniqueConstraint(name: 'admins_email_unique', columns: ['email'])]
class Admin
{
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'IDENTITY')]
    #[ORM\Column(type: Types::INTEGER)]
    private ?int $id = null;

    #[ORM\Column(type: Types::STRING, length: 255)]
    private string $name;

    #[ORM\Column(type: Types::STRING, length: 255)]
    private string $email;

    #[ORM\Column(type: Types::STRING, length: 255)]
    private string $password;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $emailVerifiedAt = null;

    #[ORM\Column(type: Types::STRING, length: 100, nullable: true)]
    private ?string $rememberToken = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $deletedAt = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $createdAt;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $updatedAt;

    // Constructor, Getters, Setters...
}

Checkliste

  • [ ] Namespace korrekt für Layer und Modul
  • [ ] declare(strict_types=1); am Dateianfang
  • [ ] ORM Attributes korrekt gesetzt
  • [ ] Indices für häufige Queries
  • [ ] Unique Constraints wo nötig
  • [ ] Soft Delete wenn Audit-relevant
  • [ ] Timestamps (createdAt, updatedAt)
  • [ ] Constructor mit Required Fields
  • [ ] Value Objects für Validierung genutzt
  • [ ] PHPDoc für komplexe Typen
  • [ ] Migration erstellt und getestet

Built with VitePress