From 77c5d25ceaeaaa2f52b4bd1d98b49071ea9933d6 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Thu, 12 Mar 2026 18:03:32 +0100 Subject: [PATCH] feat(skeleton) : wire skeleton writes to SkeletonStructureService ModelType.setStructure() now stores data in pendingStructure instead of writing to JSON columns. A new ModelTypeProcessor intercepts API Platform POST/PUT/PATCH operations and delegates skeleton writes to SkeletonStructureService, which persists to relation tables. Co-Authored-By: Claude Opus 4.6 --- src/Entity/ModelType.php | 30 ++++++++++---------- src/State/ModelTypeProcessor.php | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 src/State/ModelTypeProcessor.php diff --git a/src/Entity/ModelType.php b/src/Entity/ModelType.php index 606ea2c..239ed30 100644 --- a/src/Entity/ModelType.php +++ b/src/Entity/ModelType.php @@ -17,6 +17,7 @@ use ApiPlatform\Metadata\Put; use App\Entity\Trait\CuidEntityTrait; use App\Enum\ModelCategory; use App\Repository\ModelTypeRepository; +use App\State\ModelTypeProcessor; use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; @@ -35,9 +36,9 @@ use Symfony\Component\Serializer\Attribute\Groups; operations: [ new Get(security: "is_granted('ROLE_VIEWER')"), new GetCollection(security: "is_granted('ROLE_VIEWER')"), - new Post(security: "is_granted('ROLE_GESTIONNAIRE')"), - new Put(security: "is_granted('ROLE_GESTIONNAIRE')"), - new Patch(security: "is_granted('ROLE_GESTIONNAIRE')"), + new Post(security: "is_granted('ROLE_GESTIONNAIRE')", processor: ModelTypeProcessor::class), + new Put(security: "is_granted('ROLE_GESTIONNAIRE')", processor: ModelTypeProcessor::class), + new Patch(security: "is_granted('ROLE_GESTIONNAIRE')", processor: ModelTypeProcessor::class), new Delete(security: "is_granted('ROLE_GESTIONNAIRE')"), ], paginationClientItemsPerPage: true, @@ -199,11 +200,6 @@ class ModelType { $this->category = $category; - if (null !== $this->pendingStructure) { - $this->applyStructureForCategory($this->pendingStructure, $category); - $this->pendingStructure = null; - } - return $this; } @@ -280,17 +276,21 @@ class ModelType #[Groups(['model_type:write'])] public function setStructure(?array $structure): static { - if (!isset($this->category)) { - $this->pendingStructure = $structure; - - return $this; - } - - $this->applyStructureForCategory($structure, $this->category); + $this->pendingStructure = $structure; return $this; } + public function getPendingStructure(): ?array + { + return $this->pendingStructure; + } + + public function clearPendingStructure(): void + { + $this->pendingStructure = null; + } + /** * @return Collection */ diff --git a/src/State/ModelTypeProcessor.php b/src/State/ModelTypeProcessor.php new file mode 100644 index 0000000..bcd6949 --- /dev/null +++ b/src/State/ModelTypeProcessor.php @@ -0,0 +1,47 @@ + $uriVariables + * @param array $context + */ + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed + { + if (!$data instanceof ModelType) { + return $this->decorated->process($data, $operation, $uriVariables, $context); + } + + $pendingStructure = $data->getPendingStructure(); + + // Persist the entity first (handles all non-skeleton fields) + $result = $this->decorated->process($data, $operation, $uriVariables, $context); + + // If structure was provided in the payload, write it to skeleton relation tables + if (null !== $pendingStructure) { + $this->skeletonStructureService->updateSkeletonRequirements($data, $pendingStructure); + $data->clearPendingStructure(); + $this->entityManager->flush(); + } + + return $result; + } +}