From a502acd2343f1b0acfa719c18a944a1c43ccf7d7 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 25 Jan 2026 11:40:41 +0100 Subject: [PATCH] Support multiple product requirements on pieces --- migrations/Version20260125102000.php | 27 +++++++ src/Entity/Piece.php | 58 ++++++++++++++ .../PieceProductSyncSubscriber.php | 80 +++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 migrations/Version20260125102000.php create mode 100644 src/EventSubscriber/PieceProductSyncSubscriber.php diff --git a/migrations/Version20260125102000.php b/migrations/Version20260125102000.php new file mode 100644 index 0000000..e180350 --- /dev/null +++ b/migrations/Version20260125102000.php @@ -0,0 +1,27 @@ +addSql('ALTER TABLE pieces ADD productIds JSON DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE pieces DROP productIds'); + } +} + diff --git a/src/Entity/Piece.php b/src/Entity/Piece.php index a8e6ec7..63d4bb1 100644 --- a/src/Entity/Piece.php +++ b/src/Entity/Piece.php @@ -55,6 +55,10 @@ class Piece #[Groups(['piece:read'])] private ?Product $product = null; + #[ORM\Column(type: Types::JSON, nullable: true, name: 'productIds')] + #[Groups(['piece:read'])] + private ?array $productIds = null; + /** * @var Collection */ @@ -190,6 +194,60 @@ class Piece { $this->product = $product; + if ($product && empty($this->productIds)) { + $productId = $product->getId(); + $this->productIds = $productId ? [$productId] : null; + } + + if (!$product && empty($this->productIds)) { + $this->productIds = null; + } + + return $this; + } + + /** + * @return string[] + */ + public function getProductIds(): array + { + if (!is_array($this->productIds)) { + return []; + } + + return array_values( + array_filter( + array_map( + static fn ($value) => is_string($value) ? trim($value) : '', + $this->productIds, + ), + static fn (string $value) => $value !== '', + ), + ); + } + + public function setProductIds(?array $productIds): static + { + if (!is_array($productIds)) { + $this->productIds = null; + + return $this; + } + + $normalized = array_values( + array_unique( + array_filter( + array_map( + static fn ($value) => is_string($value) ? trim($value) : '', + $productIds, + ), + static fn (string $value) => $value !== '', + ), + ), + ); + + $this->productIds = $normalized === [] ? null : $normalized; + return $this; } diff --git a/src/EventSubscriber/PieceProductSyncSubscriber.php b/src/EventSubscriber/PieceProductSyncSubscriber.php new file mode 100644 index 0000000..b0c51ec --- /dev/null +++ b/src/EventSubscriber/PieceProductSyncSubscriber.php @@ -0,0 +1,80 @@ +getObject(); + if (!$entity instanceof Piece) { + return; + } + + $this->syncPrimaryProduct($entity); + } + + public function preUpdate(PreUpdateEventArgs $args): void + { + $entity = $args->getObject(); + if (!$entity instanceof Piece) { + return; + } + + $this->syncPrimaryProduct($entity); + + $em = $args->getObjectManager(); + $meta = $em->getClassMetadata(Piece::class); + $em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $entity); + } + + private function syncPrimaryProduct(Piece $piece): void + { + $productIds = $piece->getProductIds(); + + if ($productIds === []) { + // If no explicit list is provided, keep the legacy relation as-is. + return; + } + + $primaryId = $productIds[0] ?? null; + if (!$primaryId) { + $piece->setProduct(null); + + return; + } + + $currentProductId = $piece->getProduct()?->getId(); + if ($currentProductId === $primaryId) { + return; + } + + $primaryProduct = $this->productRepository->find($primaryId); + $piece->setProduct($primaryProduct); + } +} +