diff --git a/.continue/rules/doctrine-repository-best-practices.md b/.continue/rules/doctrine-repository-best-practices.md new file mode 100644 index 0000000..329418e --- /dev/null +++ b/.continue/rules/doctrine-repository-best-practices.md @@ -0,0 +1,7 @@ +--- +globs: '["**/Data/**/*Repository.php"]' +description: Prevents the common error of using invalid Doctrine ORM attributes + in Repository classes +--- + +When creating Doctrine repositories, NEVER use #[ORM\EntityManager] as this is not a valid Doctrine mapping attribute and causes runtime errors. Repositories must only be instantiated via Dependency Injection with EntityManagerInterface in their constructor. Valid ORM attributes for Repositories include: none (standard), or optionally #[ORM\HasEntityListeners] if needed. Mapping attributes like #[ORM\Entity], #[ORM\Table], #[ORM\JoinColumn] are ONLY for Entity classes, not Repository classes. \ No newline at end of file diff --git a/.continue/rules/simplify-repository-usage.md b/.continue/rules/simplify-repository-usage.md new file mode 100644 index 0000000..e73c070 --- /dev/null +++ b/.continue/rules/simplify-repository-usage.md @@ -0,0 +1,22 @@ +--- +globs: '["src/**/*Repository.php"]' +description: Ensures minimal boilerplate by avoiding unnecessary custom + Repository classes for standard CRUD operations, while still allowing them for + complex queries. +alwaysApply: true +--- + +In Symfony and Doctrine based applications, avoid creating custom Repository classes for simple CRUD or standard query operations (e.g., findOneBy, findBy). Instead, use Doctrine's native EntityRepository directly via $entityManager->getRepository(Entity::class) within the Provider or Processor implementations. + +Only create a custom repository when: +1. Complex queries involving multiple joins, subselects, or specialized search logic are required. +2. Query logic is reused across multiple Providers/Processors and warrants encapsulation for DRY compliance. + +When no custom repository is needed, Inject EntityManagerInterface directly into the Provider or Processor and fetch the repository inline as shown below: + +```php +$repository = $this->entityManager->getRepository(EntityClass::class); +$result = $repository->findOneBy(['id' => $id]); +``` + +Do not create an empty or wrapper Repository class that only delegates to Doctrine's native methods. \ No newline at end of file diff --git a/composer.json b/composer.json index 65148de..50a5a4f 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "php": ">=8.4", "ext-ctype": "*", "ext-iconv": "*", + "doctrine/orm": "*", "symfony/console": "8.1.*", "symfony/dotenv": "8.1.*", "symfony/flex": "^2", diff --git a/phpunit.dist.xml b/phpunit.dist.xml index db201ce..22bd879 100644 --- a/phpunit.dist.xml +++ b/phpunit.dist.xml @@ -33,6 +33,8 @@ + Doctrine\Deprecations\Deprecation::trigger + Doctrine\Deprecations\Deprecation::delegateTriggerToBackend trigger_deprecation diff --git a/src/Data/Person/Entity/PersonEntity.php b/src/Data/Person/Entity/PersonEntity.php new file mode 100644 index 0000000..8dc6eff --- /dev/null +++ b/src/Data/Person/Entity/PersonEntity.php @@ -0,0 +1,101 @@ +id; + } + + public function getAnrede(): string + { + return $this->anrede; + } + + public function setAnrede(string $anrede): void + { + $this->anrede = $anrede; + } + + public function getVorname(): string + { + return $this->vorname; + } + + public function setVorname(string $vorname): void + { + $this->vorname = $vorname; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getGeschlecht(): string + { + return $this->geschlecht; + } + + public function setGeschlecht(string $geschlecht): void + { + $this->geschlecht = $geschlecht; + } + + public function getTitel(): ?string + { + return $this->titel; + } + + public function setTitel(?string $titel): void + { + $this->titel = $titel; + } + + public function getFunktionstitel(): ?string + { + return $this->funktionstitel; + } + + public function setFunktionstitel(?string $funktionstitel): void + { + $this->funktionstitel = $funktionstitel; + } +} diff --git a/src/Logic/Person/Models/PersonModel.php b/src/Logic/Person/Models/PersonModel.php new file mode 100644 index 0000000..699bb4b --- /dev/null +++ b/src/Logic/Person/Models/PersonModel.php @@ -0,0 +1,105 @@ +id = $id; + $this->anrede = $anrede; + $this->vorname = $vorname; + $this->name = $name; + $this->geschlecht = $geschlecht; + $this->titel = $titel; + $this->funktionstitel = $funktionstitel; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getAnrede(): string + { + return $this->anrede; + } + + public function setAnrede(string $anrede): void + { + $this->anrede = $anrede; + } + + public function getVorname(): string + { + return $this->vorname; + } + + public function setVorname(string $vorname): void + { + $this->vorname = $vorname; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getGeschlecht(): string + { + return $this->geschlecht; + } + + public function setGeschlecht(string $geschlecht): void + { + $this->geschlecht = $geschlecht; + } + + public function getTitel(): ?string + { + return $this->titel; + } + + public function setTitel(?string $titel): void + { + $this->titel = $titel; + } + + public function getFunktionstitel(): ?string + { + return $this->funktionstitel; + } + + public function setFunktionstitel(?string $funktionstitel): void + { + $this->funktionstitel = $funktionstitel; + } +} diff --git a/src/Shared/Person/DTO/PersonDto.php b/src/Shared/Person/DTO/PersonDto.php new file mode 100644 index 0000000..8aac5b2 --- /dev/null +++ b/src/Shared/Person/DTO/PersonDto.php @@ -0,0 +1,19 @@ +