feat(machines) : ajoute le clonage par catégorie (structure seule)
Nouveau mode de clonage de machine via le paramètre `mode` de
POST /api/machines/{id}/clone :
- mode "full" (défaut) : comportement inchangé (clone complet)
- mode "structure" : ne recopie que les catégories des slots
(modelType), composant/pièce/produit concrets laissés vides
(slots à compléter), sans overrides ni custom field values
Front : sélecteur de mode dans la page de création de machine,
visible uniquement quand une machine source est choisie.
This commit is contained in:
@@ -132,6 +132,14 @@ class MachineStructureController extends AbstractController
|
||||
return $this->json(['success' => false, 'error' => 'Site introuvable.'], 404);
|
||||
}
|
||||
|
||||
// Clone mode: 'full' copies concrete components/pieces/products; 'structure'
|
||||
// only keeps the slots' categories (modelType) with empty concrete entities.
|
||||
$mode = $payload['mode'] ?? 'full';
|
||||
if (!in_array($mode, ['full', 'structure'], true)) {
|
||||
return $this->json(['success' => false, 'error' => 'mode invalide (valeurs autorisées : full, structure).'], 400);
|
||||
}
|
||||
$structureOnly = 'structure' === $mode;
|
||||
|
||||
// Create new machine
|
||||
$newMachine = new Machine();
|
||||
$newMachine->setName($payload['name']);
|
||||
@@ -156,13 +164,13 @@ class MachineStructureController extends AbstractController
|
||||
$this->cloneCustomFields($source, $newMachine);
|
||||
|
||||
// Copy component links (preserving hierarchy)
|
||||
$componentLinkMap = $this->cloneComponentLinks($source, $newMachine);
|
||||
$componentLinkMap = $this->cloneComponentLinks($source, $newMachine, $structureOnly);
|
||||
|
||||
// Copy piece links
|
||||
$pieceLinkMap = $this->clonePieceLinks($source, $newMachine, $componentLinkMap);
|
||||
$pieceLinkMap = $this->clonePieceLinks($source, $newMachine, $componentLinkMap, $structureOnly);
|
||||
|
||||
// Copy product links
|
||||
$this->cloneProductLinks($source, $newMachine, $componentLinkMap, $pieceLinkMap);
|
||||
$this->cloneProductLinks($source, $newMachine, $componentLinkMap, $pieceLinkMap, $structureOnly);
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
@@ -215,7 +223,7 @@ class MachineStructureController extends AbstractController
|
||||
/**
|
||||
* @return array<string, MachineComponentLink> Map of old link ID → new link
|
||||
*/
|
||||
private function cloneComponentLinks(Machine $source, Machine $target): array
|
||||
private function cloneComponentLinks(Machine $source, Machine $target, bool $structureOnly = false): array
|
||||
{
|
||||
$sourceLinks = $this->machineComponentLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
|
||||
$linkMap = [];
|
||||
@@ -224,6 +232,16 @@ class MachineStructureController extends AbstractController
|
||||
foreach ($sourceLinks as $link) {
|
||||
$newLink = new MachineComponentLink();
|
||||
$newLink->setMachine($target);
|
||||
|
||||
if ($structureOnly) {
|
||||
// Keep only the slot category; leave the concrete component empty.
|
||||
$newLink->setModelType($link->getModelType() ?? $link->getComposant()?->getTypeComposant());
|
||||
$this->entityManager->persist($newLink);
|
||||
$linkMap[$link->getId()] = $newLink;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$newLink->setComposant($link->getComposant());
|
||||
$newLink->setNameOverride($link->getNameOverride());
|
||||
$newLink->setReferenceOverride($link->getReferenceOverride());
|
||||
@@ -259,7 +277,7 @@ class MachineStructureController extends AbstractController
|
||||
*
|
||||
* @return array<string, MachinePieceLink> Map of old link ID → new link
|
||||
*/
|
||||
private function clonePieceLinks(Machine $source, Machine $target, array $componentLinkMap): array
|
||||
private function clonePieceLinks(Machine $source, Machine $target, array $componentLinkMap, bool $structureOnly = false): array
|
||||
{
|
||||
$sourceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
|
||||
$linkMap = [];
|
||||
@@ -267,17 +285,27 @@ class MachineStructureController extends AbstractController
|
||||
foreach ($sourceLinks as $link) {
|
||||
$newLink = new MachinePieceLink();
|
||||
$newLink->setMachine($target);
|
||||
$newLink->setPiece($link->getPiece());
|
||||
$newLink->setNameOverride($link->getNameOverride());
|
||||
$newLink->setReferenceOverride($link->getReferenceOverride());
|
||||
$newLink->setPrixOverride($link->getPrixOverride());
|
||||
$newLink->setQuantity($link->getQuantity());
|
||||
|
||||
$parent = $link->getParentLink();
|
||||
if ($parent && isset($componentLinkMap[$parent->getId()])) {
|
||||
$newLink->setParentLink($componentLinkMap[$parent->getId()]);
|
||||
}
|
||||
|
||||
if ($structureOnly) {
|
||||
// Keep only the slot category; leave the concrete piece empty.
|
||||
$newLink->setModelType($link->getModelType() ?? $link->getPiece()?->getTypePiece());
|
||||
$this->entityManager->persist($newLink);
|
||||
$linkMap[$link->getId()] = $newLink;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$newLink->setPiece($link->getPiece());
|
||||
$newLink->setNameOverride($link->getNameOverride());
|
||||
$newLink->setReferenceOverride($link->getReferenceOverride());
|
||||
$newLink->setPrixOverride($link->getPrixOverride());
|
||||
$newLink->setQuantity($link->getQuantity());
|
||||
|
||||
$this->entityManager->persist($newLink);
|
||||
|
||||
foreach ($link->getContextFieldValues() as $cfv) {
|
||||
@@ -305,6 +333,7 @@ class MachineStructureController extends AbstractController
|
||||
Machine $target,
|
||||
array $componentLinkMap,
|
||||
array $pieceLinkMap,
|
||||
bool $structureOnly = false,
|
||||
): void {
|
||||
$sourceLinks = $this->machineProductLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
|
||||
$linkMap = [];
|
||||
@@ -313,7 +342,13 @@ class MachineStructureController extends AbstractController
|
||||
foreach ($sourceLinks as $link) {
|
||||
$newLink = new MachineProductLink();
|
||||
$newLink->setMachine($target);
|
||||
$newLink->setProduct($link->getProduct());
|
||||
|
||||
if ($structureOnly) {
|
||||
// Keep only the slot category; leave the concrete product empty.
|
||||
$newLink->setModelType($link->getModelType() ?? $link->getProduct()?->getTypeProduct());
|
||||
} else {
|
||||
$newLink->setProduct($link->getProduct());
|
||||
}
|
||||
|
||||
$parentComponent = $link->getParentComponentLink();
|
||||
if ($parentComponent && isset($componentLinkMap[$parentComponent->getId()])) {
|
||||
@@ -774,7 +809,7 @@ class MachineStructureController extends AbstractController
|
||||
$pieces = [];
|
||||
foreach ($composant->getPieceSlots() as $slot) {
|
||||
$selectedPiece = $this->ensurePieceExists($slot->getSelectedPiece());
|
||||
$pieceData = [
|
||||
$pieceData = [
|
||||
'slotId' => $slot->getId(),
|
||||
'typePieceId' => $slot->getTypePiece()?->getId(),
|
||||
'typePiece' => $this->normalizeModelType($slot->getTypePiece()),
|
||||
@@ -824,6 +859,7 @@ class MachineStructureController extends AbstractController
|
||||
if (null === $piece) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->entityManager->initializeObject($piece);
|
||||
|
||||
@@ -844,6 +880,7 @@ class MachineStructureController extends AbstractController
|
||||
if (null === $cf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->entityManager->initializeObject($cf);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user