feat(catalog) : M7 — entité Storage + repository + contrat de sérialisation (ERP-212) #164
Reference in New Issue
Block a user
Delete Branch "feat/erp-212-entite-storage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
M7 · ERP-212 (1.3) — Entité
Storage+ repository + contrat de sérialisationMappe l'entité
Storage(jumelle deProductM6) avec ses relations ManyToOne, le getter virtueldisplayName, les contraintes FR et les read-groups de sérialisation.Livré
Storage.php:#[Auditable],TimestampableInterface/BlamableInterface+ trait.site/storageTypeManyToOne (NOT NULL, ON DELETE RESTRICT,#[Assert\NotNull]FR).numerostring(50) (NotBlank+Length(max:50)FR).statesJSONB (Count(min:1)+Choice(multiple)sur{RECEPTION, PRODUCTION, TRIAGE}FR).deletedAtnon exposé.getDisplayName(): string=trim(label.' '.numero),#[Groups(['storage:read'])], non persisté.storage:readsur chaque champ ;site/storageTypeembarqués viasite:read/storage_type:read;createdAt/updatedAtviadefault:read. Écriturestorage:write.GetCollection/Get(catalog.storages.view) +Post/Patch(catalog.storages.manage,collectDenormalizationErrors). Pas deDelete(§ 2.8). Provider/Processor référencés (StorageProvider/StorageProcessor, créés en ERP-213 —::classnon résolu au boot, aucun endpoint frappé ici).StorageRepositoryInterface(Domain) +DoctrineStorageRepository(Infrastructure).Décisions / dérivations (au-delà de l'énoncé, requises pour
make testvert)Assert\Choice(multiple: true)retenu au lieu deAssert\All([Choice])du prompt :Assert\Alln'est pas mappé parEntityConstraintsHaveFrenchMessageTestet le ferait échouer. Équivalent fonctionnel, miroir exact deProduct::states.catalog_storageajouté àaudit.entity(entité#[Auditable]→AuditableEntitiesHaveI18nLabelTest).storagedansColumnCommentsCatalog: la table est désormais mappée → en TESTschema:updatestrip les COMMENT,app:apply-column-commentsles rejoue (sinonColumnsHaveSqlCommentTestcasse).makefiletest-db-setup : ré-application de l'index partieluq_storage_site_type_numero_activeaprèsschema:update(parité product/supplier/…).statesmappétype:'json', options:['jsonb'=>true]pour coller à la colonne JSONB + CHECK (évite l'ALTER TYPE JSON qui casseraitjsonb_array_length).Vérifications
doctrine:schema:validate: mapping correct ; seul « drift » = index partiel non exprimable en ORM + comments (rejoués) — identique à product/category, aucune dérive jsonb/type/index.make test:EntitiesAreTimestampableBlamableTest(conforme sans whitelist),EntityConstraintsHaveFrenchMessageTest,AuditableEntitiesHaveI18nLabelTest,ColumnsHaveSqlCommentTest,CollectionsArePaginatedTestverts. Échec résiduel = flaky JWT connu (Technique, passe en isolation).make php-cs-fixer-allow-risky: 0 fichier à corriger.Revue de code — M7 Stockages
🔴
statesaccepte un objet JSON → 500 au lieu de 422 —Storage.php(propriétéstates)statesest typéarrayavecAssert\Count(min:1)+Assert\Choice(multiple:true). Un POST{"states":{"x":"RECEPTION"}}se dénormalise en tableau associatif, passe la validation (count 1, valeur valide), puis Doctrinejson_encodeproduit un objet JSONB{"x":"RECEPTION"}. Le CHECKchk_storage_states_not_emptyappelle alorsjsonb_array_length()sur un non-tableau → erreur SQL remontée en 500 opaque au lieu d'un 422 propre surstates.→ Garde de forme liste :
array_values()au setter / dans le Processor, ou unAssertséquentiel garantissant un tableau séquentiel.🟡
statesaccepte les doublons — même propriétéNi le CHECK (
jsonb_array_length >= 1) niAssert\Choicen'imposent l'unicité.["TRIAGE","TRIAGE"]est accepté et persisté (l'export masque via dédup par libellé). RG-7.04 décrit un sous-ensemble → ajouterAssert\Unique.