Files
Starseed/config/packages/doctrine.yaml
T
matthieu ff6086bc4d
Auto Tag Develop / tag (push) Successful in 7s
[ERP-44] Créer les entités Category et CategoryType (#15)
## Objectif
Couche Domain DDD du module Catalog (ticket M0 · position 0.2). Crée les entités `Category` et `CategoryType`, leurs repositories, et branche le pattern Timestampable + Blamable Shared.

> **Mode stacked PR** : cible `feature/ERP-43-migrer-tables-category`. Quand la MR ERP-43 sera mergée sur develop, Matthieu repointera la cible de cette MR vers develop.

## Contenu
- **`Category`** : `#[ApiResource]` (GetCollection, Get, Post, Patch, Delete), `#[Auditable]`, `TimestampableBlamableTrait` + interfaces, asserts (`NotBlank`/`Length` sur `name`, `NotNull` sur `categoryType`), soft delete via `deletedAt`. Provider/Processor branchés au ticket 0.3 (ERP-45).
- **`CategoryType`** : référentiel statique en lecture seule (GetCollection + Get), embarqué dans `Category` via le groupe `category:read`. Pas de Trait — whitelisté dans `EntitiesAreTimestampableBlamableTest::EXCLUDED` (RG-1.17).
- **Repositories** : interfaces Domain + implémentations Doctrine.
- **`config/packages/doctrine.yaml`** : mapping ORM `Catalog` inconditionnel (miroir de `Sites`) — nécessaire pour que l'ORM reconnaisse les entités. La déclaration du module (`config/modules.php`) reste pour le ticket 0.5 (ERP-47).
- Groupes : `category:read` / `category:write` + `default:read` (expose les 4 colonnes du Trait).

## Notes techniques
- Index nommés déclarés sur les entités pour matcher la migration (cf. Role/Permission/Site).
- L'index unique partiel `uq_category_name_type_active` (`LOWER(name), category_type_id WHERE deleted_at IS NULL`) reste possédé par la seule migration : Doctrine ORM ne sait pas exprimer un index fonctionnel + partiel. Seul diff résiduel de `doctrine:schema:validate`.

## Tests
- `make php-cs-fixer-allow-risky` ✓
- `make test` ✓ (248 tests, 0 échec)
- `make db-reset` ✓
- `debug:router` ✓ (7 routes exposées)
- `doctrine:schema:validate` : mapping correct

---------

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #15
Reviewed-by: Autin <tristan@yuno.malio.fr>
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-05-28 09:44:18 +00:00

125 lines
6.1 KiB
YAML

doctrine:
dbal:
# Deux connexions pointant sur le meme DSN : l'ORM utilise `default`,
# l'AuditLogWriter utilise `audit` pour ecrire hors de la transaction
# Doctrine et eviter tout entanglement transactionnel en batch.
default_connection: default
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
profiling_collect_backtrace: '%kernel.debug%'
# Exclut `audit_log` de toute operation de comparaison de schema
# (doctrine:schema:update, schema:validate, diff de migrations...).
# Cette table n'a volontairement aucune entite mappee : elle est
# append-only via DBAL brut (AuditLogWriter) pour eviter la
# recursion du listener Doctrine. Sans ce filtre, schema:update
# la considere comme "orpheline" et genere un `DROP TABLE
# audit_log` qui casse la base de test apres chaque
# `make test-db-setup`. La creation / suppression de la table
# reste pilotee par les migrations (cf. Version20260420202749).
schema_filter: '~^(?!audit_log$).+~'
audit:
url: '%env(resolve:DATABASE_URL)%'
orm:
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
identity_generation_preferences:
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
auto_mapping: true
# Mapping contrat DDD → classe concrete. Permet au module Core de
# referencer `SiteInterface` dans ses ORM mappings (User) sans importer
# la classe concrete du module Sites. Pattern officiel Doctrine pour
# les bounded contexts, remplace l'ancien import direct
# `App\Module\Sites\Domain\Entity\Site` dans User.php.
resolve_target_entities:
App\Shared\Domain\Contract\SiteInterface: App\Module\Sites\Domain\Entity\Site
# Cible des ManyToOne created_by / updated_by du TimestampableBlamableTrait.
# Permet a Shared de referencer UserInterface dans ses ORM mappings sans
# importer la classe concrete du module Core (cf. spec-back M0 § 2.8).
Symfony\Component\Security\Core\User\UserInterface: App\Module\Core\Domain\Entity\User
mappings:
Core:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Module/Core/Domain/Entity'
prefix: 'App\Module\Core\Domain\Entity'
alias: Core
# Mapping inconditionnelle du module Sites : la structure DB
# existe meme si SitesModule::class est retire de config/modules.php.
# L'activation fonctionnelle (ex: exposition des permissions, futurs
# endpoints API) passe exclusivement par config/modules.php.
Sites:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Module/Sites/Domain/Entity'
prefix: 'App\Module\Sites\Domain\Entity'
alias: Sites
# Mapping inconditionnel du module Catalog (meme logique que Sites) :
# la structure DB (category, category_type) existe meme si
# CatalogModule::class n'est pas encore wire dans config/modules.php
# (declaration du module = ticket 0.5 / ERP-47). L'ORM doit connaitre
# les entites pour que le schema soit en phase ; l'activation
# fonctionnelle passe exclusivement par config/modules.php.
Catalog:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Module/Catalog/Domain/Entity'
prefix: 'App\Module\Catalog\Domain\Entity'
alias: Catalog
controller_resolver:
auto_mapping: false
when@test:
doctrine:
dbal:
# Le suffixe "_test" doit etre propage aux deux connexions : l'ORM
# l'herite via `default`, l'AuditLogWriter via `audit`. Sans cela,
# la connexion `audit` ecrirait dans la base dev pendant que l'ORM
# ecrit dans la base test — divergence invisible en apparence mais
# fatale pour les tests du journal d'audit.
#
# `idle_connection_ttl: 1` (au lieu du defaut 600s) : en test on
# reboote le kernel a chaque test. Sans TTL court, les connexions
# orphelines s'accumulent dans PG et on finit par saturer le pool
# (max_connections=100) sur une suite de 200+ tests qui utilisent
# 2 connexions chacun (default + audit).
connections:
default:
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
idle_connection_ttl: 1
audit:
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
idle_connection_ttl: 1
orm:
mappings:
# Entite fictive SiteAware utilisee uniquement en tests du
# module Sites (ticket 4). Le mapping n'est charge qu'en
# environnement test, donc aucun impact sur les schemas
# dev/prod. La table est creee a la volee par les tests
# d'integration (via `SchemaTool::createSchema`) dans le
# setUp de SiteScopedQueryExtensionTest.
TestFixtures:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/tests/Fixtures/SiteAware'
prefix: 'App\Tests\Fixtures\SiteAware'
alias: TestFixtures
when@prod:
doctrine:
orm:
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system