767 lines
31 KiB
PHP
767 lines
31 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Controller;
|
||
|
||
use App\Entity\Composant;
|
||
use App\Entity\CustomField;
|
||
use App\Entity\Machine;
|
||
use App\Entity\MachineComponentLink;
|
||
use App\Entity\MachinePieceLink;
|
||
use App\Entity\MachineProductLink;
|
||
use App\Entity\ModelType;
|
||
use App\Entity\Piece;
|
||
use App\Entity\Product;
|
||
use App\Entity\TypeMachineComponentRequirement;
|
||
use App\Entity\TypeMachinePieceRequirement;
|
||
use App\Entity\TypeMachineProductRequirement;
|
||
use App\Repository\ComposantRepository;
|
||
use App\Repository\MachineComponentLinkRepository;
|
||
use App\Repository\MachinePieceLinkRepository;
|
||
use App\Repository\MachineProductLinkRepository;
|
||
use App\Repository\MachineRepository;
|
||
use App\Repository\PieceRepository;
|
||
use App\Repository\ProductRepository;
|
||
use App\Repository\TypeMachineComponentRequirementRepository;
|
||
use App\Repository\TypeMachinePieceRequirementRepository;
|
||
use App\Repository\TypeMachineProductRequirementRepository;
|
||
use Doctrine\Common\Collections\Collection;
|
||
use Doctrine\ORM\EntityManagerInterface;
|
||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||
use Symfony\Component\HttpFoundation\Request;
|
||
use Symfony\Component\Routing\Attribute\Route;
|
||
|
||
#[Route('/api/machines')]
|
||
class MachineSkeletonController extends AbstractController
|
||
{
|
||
public function __construct(
|
||
private readonly EntityManagerInterface $entityManager,
|
||
private readonly MachineRepository $machineRepository,
|
||
private readonly MachineComponentLinkRepository $machineComponentLinkRepository,
|
||
private readonly MachinePieceLinkRepository $machinePieceLinkRepository,
|
||
private readonly MachineProductLinkRepository $machineProductLinkRepository,
|
||
private readonly ComposantRepository $composantRepository,
|
||
private readonly PieceRepository $pieceRepository,
|
||
private readonly ProductRepository $productRepository,
|
||
private readonly TypeMachineComponentRequirementRepository $componentRequirementRepository,
|
||
private readonly TypeMachinePieceRequirementRepository $pieceRequirementRepository,
|
||
private readonly TypeMachineProductRequirementRepository $productRequirementRepository,
|
||
) {}
|
||
|
||
#[Route('/{id}/skeleton', name: 'machine_skeleton_get', methods: ['GET'])]
|
||
public function getSkeleton(string $id): JsonResponse
|
||
{
|
||
$machine = $this->machineRepository->find($id);
|
||
if (!$machine instanceof Machine) {
|
||
return $this->json(['success' => false, 'error' => 'Machine not found.'], 404);
|
||
}
|
||
|
||
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $machine]);
|
||
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $machine]);
|
||
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $machine]);
|
||
|
||
return $this->json($this->normalizeMachineSkeletonResponse(
|
||
$machine,
|
||
$componentLinks,
|
||
$pieceLinks,
|
||
$productLinks
|
||
));
|
||
}
|
||
|
||
#[Route('/{id}/skeleton', name: 'machine_skeleton_update', methods: ['PATCH'])]
|
||
public function updateSkeleton(string $id, Request $request): JsonResponse
|
||
{
|
||
$machine = $this->machineRepository->find($id);
|
||
if (!$machine instanceof Machine) {
|
||
return $this->json(['success' => false, 'error' => 'Machine not found.'], 404);
|
||
}
|
||
|
||
$payload = json_decode($request->getContent(), true);
|
||
if (!is_array($payload)) {
|
||
return $this->json(['success' => false, 'error' => 'Invalid JSON payload.'], 400);
|
||
}
|
||
|
||
$componentLinksPayload = $this->normalizePayloadList($payload['componentLinks'] ?? []);
|
||
$pieceLinksPayload = $this->normalizePayloadList($payload['pieceLinks'] ?? []);
|
||
$productLinksPayload = $this->normalizePayloadList($payload['productLinks'] ?? []);
|
||
|
||
$componentLinks = $this->applyComponentLinks($machine, $componentLinksPayload);
|
||
if ($componentLinks instanceof JsonResponse) {
|
||
return $componentLinks;
|
||
}
|
||
|
||
$pieceLinks = $this->applyPieceLinks($machine, $pieceLinksPayload, $componentLinks);
|
||
if ($pieceLinks instanceof JsonResponse) {
|
||
return $pieceLinks;
|
||
}
|
||
|
||
$productLinks = $this->applyProductLinks($machine, $productLinksPayload, $componentLinks, $pieceLinks);
|
||
if ($productLinks instanceof JsonResponse) {
|
||
return $productLinks;
|
||
}
|
||
|
||
$this->entityManager->flush();
|
||
|
||
return $this->json($this->normalizeMachineSkeletonResponse(
|
||
$machine,
|
||
$componentLinks,
|
||
$pieceLinks,
|
||
$productLinks
|
||
));
|
||
}
|
||
|
||
private function normalizePayloadList(mixed $value): array
|
||
{
|
||
if (!is_array($value)) {
|
||
return [];
|
||
}
|
||
|
||
return array_values(array_filter($value, static fn ($item) => is_array($item)));
|
||
}
|
||
|
||
private function applyComponentLinks(Machine $machine, array $payload): array|JsonResponse
|
||
{
|
||
$existing = $this->indexLinksById($this->machineComponentLinkRepository->findBy(['machine' => $machine]));
|
||
$keepIds = [];
|
||
$pendingParents = [];
|
||
$links = [];
|
||
|
||
foreach ($payload as $entry) {
|
||
$linkId = $this->resolveIdentifier($entry, ['id', 'linkId']);
|
||
$link = $linkId && isset($existing[$linkId]) ? $existing[$linkId] : new MachineComponentLink();
|
||
if (!$linkId) {
|
||
$linkId = $this->generateCuid();
|
||
}
|
||
if (!$link->getId()) {
|
||
$link->setId($linkId);
|
||
}
|
||
|
||
$composantId = $this->resolveIdentifier($entry, ['composantId', 'componentId', 'idComposant']);
|
||
if (!$composantId) {
|
||
return $this->json(['success' => false, 'error' => 'Composant requis pour le squelette.'], 400);
|
||
}
|
||
$composant = $this->composantRepository->find($composantId);
|
||
if (!$composant instanceof Composant) {
|
||
return $this->json(['success' => false, 'error' => 'Composant introuvable.'], 404);
|
||
}
|
||
|
||
$link->setMachine($machine);
|
||
$link->setComposant($composant);
|
||
|
||
$requirementId = $this->resolveIdentifier($entry, ['requirementId', 'typeMachineComponentRequirementId']);
|
||
if ($requirementId) {
|
||
$requirement = $this->componentRequirementRepository->find($requirementId);
|
||
if ($requirement instanceof TypeMachineComponentRequirement) {
|
||
$link->setTypeMachineComponentRequirement($requirement);
|
||
}
|
||
}
|
||
|
||
$this->applyOverrides($link, $entry['overrides'] ?? null);
|
||
|
||
$pendingParents[$linkId] = $this->resolveIdentifier($entry, [
|
||
'parentComponentLinkId',
|
||
'parentLinkId',
|
||
'parentMachineComponentLinkId',
|
||
]);
|
||
|
||
$this->entityManager->persist($link);
|
||
$links[$linkId] = $link;
|
||
$keepIds[] = $linkId;
|
||
}
|
||
|
||
foreach ($pendingParents as $linkId => $parentId) {
|
||
if (!$parentId) {
|
||
continue;
|
||
}
|
||
if (!isset($links[$linkId])) {
|
||
continue;
|
||
}
|
||
$parent = $links[$parentId] ?? $existing[$parentId] ?? null;
|
||
if ($parent instanceof MachineComponentLink) {
|
||
$links[$linkId]->setParentLink($parent);
|
||
}
|
||
}
|
||
|
||
$this->removeMissingLinks($existing, $keepIds);
|
||
|
||
return array_values($links);
|
||
}
|
||
|
||
private function applyPieceLinks(Machine $machine, array $payload, array $componentLinks): array|JsonResponse
|
||
{
|
||
$existing = $this->indexLinksById($this->machinePieceLinkRepository->findBy(['machine' => $machine]));
|
||
$componentIndex = $this->indexLinksById($componentLinks);
|
||
$keepIds = [];
|
||
$pendingParents = [];
|
||
$links = [];
|
||
|
||
foreach ($payload as $entry) {
|
||
$linkId = $this->resolveIdentifier($entry, ['id', 'linkId']);
|
||
$link = $linkId && isset($existing[$linkId]) ? $existing[$linkId] : new MachinePieceLink();
|
||
if (!$linkId) {
|
||
$linkId = $this->generateCuid();
|
||
}
|
||
if (!$link->getId()) {
|
||
$link->setId($linkId);
|
||
}
|
||
|
||
$pieceId = $this->resolveIdentifier($entry, ['pieceId']);
|
||
if (!$pieceId) {
|
||
return $this->json(['success' => false, 'error' => 'Pièce requise pour le squelette.'], 400);
|
||
}
|
||
$piece = $this->pieceRepository->find($pieceId);
|
||
if (!$piece instanceof Piece) {
|
||
return $this->json(['success' => false, 'error' => 'Pièce introuvable.'], 404);
|
||
}
|
||
|
||
$link->setMachine($machine);
|
||
$link->setPiece($piece);
|
||
|
||
$requirementId = $this->resolveIdentifier($entry, ['requirementId', 'typeMachinePieceRequirementId']);
|
||
if ($requirementId) {
|
||
$requirement = $this->pieceRequirementRepository->find($requirementId);
|
||
if ($requirement instanceof TypeMachinePieceRequirement) {
|
||
$link->setTypeMachinePieceRequirement($requirement);
|
||
}
|
||
}
|
||
|
||
$this->applyOverrides($link, $entry['overrides'] ?? null);
|
||
|
||
$pendingParents[$linkId] = $this->resolveIdentifier($entry, [
|
||
'parentComponentLinkId',
|
||
'parentLinkId',
|
||
'parentMachineComponentLinkId',
|
||
]);
|
||
|
||
$this->entityManager->persist($link);
|
||
$links[$linkId] = $link;
|
||
$keepIds[] = $linkId;
|
||
}
|
||
|
||
foreach ($pendingParents as $linkId => $parentId) {
|
||
if (!$parentId) {
|
||
continue;
|
||
}
|
||
if (!isset($links[$linkId])) {
|
||
continue;
|
||
}
|
||
$parent = $componentIndex[$parentId] ?? null;
|
||
if ($parent instanceof MachineComponentLink) {
|
||
$links[$linkId]->setParentLink($parent);
|
||
}
|
||
}
|
||
|
||
$this->removeMissingLinks($existing, $keepIds);
|
||
|
||
return array_values($links);
|
||
}
|
||
|
||
private function applyProductLinks(
|
||
Machine $machine,
|
||
array $payload,
|
||
array $componentLinks,
|
||
array $pieceLinks,
|
||
): array|JsonResponse {
|
||
$existing = $this->indexLinksById($this->machineProductLinkRepository->findBy(['machine' => $machine]));
|
||
$componentIndex = $this->indexLinksById($componentLinks);
|
||
$pieceIndex = $this->indexLinksById($pieceLinks);
|
||
$keepIds = [];
|
||
$pendingParents = [];
|
||
$links = [];
|
||
|
||
foreach ($payload as $entry) {
|
||
$linkId = $this->resolveIdentifier($entry, ['id', 'linkId']);
|
||
$link = $linkId && isset($existing[$linkId]) ? $existing[$linkId] : new MachineProductLink();
|
||
if (!$linkId) {
|
||
$linkId = $this->generateCuid();
|
||
}
|
||
if (!$link->getId()) {
|
||
$link->setId($linkId);
|
||
}
|
||
|
||
$productId = $this->resolveIdentifier($entry, ['productId']);
|
||
if (!$productId) {
|
||
return $this->json(['success' => false, 'error' => 'Produit requis pour le squelette.'], 400);
|
||
}
|
||
$product = $this->productRepository->find($productId);
|
||
if (!$product instanceof Product) {
|
||
return $this->json(['success' => false, 'error' => 'Produit introuvable.'], 404);
|
||
}
|
||
|
||
$link->setMachine($machine);
|
||
$link->setProduct($product);
|
||
|
||
$requirementId = $this->resolveIdentifier($entry, ['requirementId', 'typeMachineProductRequirementId']);
|
||
if ($requirementId) {
|
||
$requirement = $this->productRequirementRepository->find($requirementId);
|
||
if ($requirement instanceof TypeMachineProductRequirement) {
|
||
$link->setTypeMachineProductRequirement($requirement);
|
||
}
|
||
}
|
||
|
||
$pendingParents[$linkId] = [
|
||
'parentComponentLinkId' => $this->resolveIdentifier($entry, ['parentComponentLinkId']),
|
||
'parentPieceLinkId' => $this->resolveIdentifier($entry, ['parentPieceLinkId']),
|
||
'parentLinkId' => $this->resolveIdentifier($entry, ['parentLinkId']),
|
||
];
|
||
|
||
$this->entityManager->persist($link);
|
||
$links[$linkId] = $link;
|
||
$keepIds[] = $linkId;
|
||
}
|
||
|
||
foreach ($pendingParents as $linkId => $parentIds) {
|
||
if (!isset($links[$linkId])) {
|
||
continue;
|
||
}
|
||
if (!empty($parentIds['parentComponentLinkId']) && isset($componentIndex[$parentIds['parentComponentLinkId']])) {
|
||
$links[$linkId]->setParentComponentLink($componentIndex[$parentIds['parentComponentLinkId']]);
|
||
}
|
||
if (!empty($parentIds['parentPieceLinkId']) && isset($pieceIndex[$parentIds['parentPieceLinkId']])) {
|
||
$links[$linkId]->setParentPieceLink($pieceIndex[$parentIds['parentPieceLinkId']]);
|
||
}
|
||
if (!empty($parentIds['parentLinkId']) && isset($links[$parentIds['parentLinkId']])) {
|
||
$links[$linkId]->setParentLink($links[$parentIds['parentLinkId']]);
|
||
}
|
||
}
|
||
|
||
$this->removeMissingLinks($existing, $keepIds);
|
||
|
||
return array_values($links);
|
||
}
|
||
|
||
private function normalizeMachineSkeletonResponse(
|
||
Machine $machine,
|
||
array $componentLinks,
|
||
array $pieceLinks,
|
||
array $productLinks,
|
||
): array {
|
||
$normalizedComponentLinks = $this->normalizeComponentLinks($componentLinks);
|
||
$componentIndex = $this->indexNormalizedLinks($normalizedComponentLinks);
|
||
$normalizedPieceLinks = $this->normalizePieceLinks($pieceLinks);
|
||
|
||
// Build component hierarchy – track which IDs are children
|
||
$childIds = [];
|
||
foreach ($normalizedComponentLinks as $link) {
|
||
$parentId = $link['parentComponentLinkId'] ?? null;
|
||
if ($parentId && isset($componentIndex[$parentId])) {
|
||
$componentIndex[$parentId]['childLinks'][] = $link;
|
||
$childIds[$link['id']] = true;
|
||
}
|
||
}
|
||
|
||
// Add pieces to components recursively
|
||
$this->attachPiecesToComponents($componentIndex, $normalizedPieceLinks);
|
||
|
||
// Only return root-level components (exclude children already nested)
|
||
$rootComponents = array_filter(
|
||
$componentIndex,
|
||
static fn (array $link) => !isset($childIds[$link['id']]),
|
||
);
|
||
|
||
return [
|
||
'machine' => $this->normalizeMachine($machine),
|
||
'componentLinks' => array_values($rootComponents),
|
||
'pieceLinks' => $normalizedPieceLinks,
|
||
'productLinks' => $this->normalizeProductLinks($productLinks),
|
||
];
|
||
}
|
||
|
||
private function attachPiecesToComponents(array &$componentIndex, array $pieceLinks): void
|
||
{
|
||
foreach ($pieceLinks as $pieceLink) {
|
||
$parentId = $pieceLink['parentComponentLinkId'] ?? null;
|
||
if ($parentId && isset($componentIndex[$parentId])) {
|
||
$componentIndex[$parentId]['pieceLinks'][] = $pieceLink;
|
||
}
|
||
}
|
||
|
||
// Recursively attach to child components
|
||
foreach ($componentIndex as &$component) {
|
||
if (!empty($component['childLinks'])) {
|
||
$this->attachPiecesToChildComponents($component['childLinks'], $pieceLinks);
|
||
}
|
||
}
|
||
}
|
||
|
||
private function attachPiecesToChildComponents(array &$childLinks, array $pieceLinks): void
|
||
{
|
||
foreach ($childLinks as &$child) {
|
||
$childId = $child['id'] ?? $child['linkId'] ?? null;
|
||
if ($childId) {
|
||
foreach ($pieceLinks as $pieceLink) {
|
||
$parentId = $pieceLink['parentComponentLinkId'] ?? null;
|
||
if ($parentId === $childId) {
|
||
$child['pieceLinks'][] = $pieceLink;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Recursively process nested children
|
||
if (!empty($child['childLinks'])) {
|
||
$this->attachPiecesToChildComponents($child['childLinks'], $pieceLinks);
|
||
}
|
||
}
|
||
}
|
||
|
||
private function normalizeMachine(Machine $machine): array
|
||
{
|
||
$site = $machine->getSite();
|
||
$typeMachine = $machine->getTypeMachine();
|
||
|
||
return [
|
||
'id' => $machine->getId(),
|
||
'name' => $machine->getName(),
|
||
'reference' => $machine->getReference(),
|
||
'prix' => $machine->getPrix(),
|
||
'siteId' => $site->getId(),
|
||
'site' => [
|
||
'id' => $site->getId(),
|
||
'name' => $site->getName(),
|
||
],
|
||
'typeMachineId' => $typeMachine?->getId(),
|
||
'typeMachine' => $typeMachine ? [
|
||
'id' => $typeMachine->getId(),
|
||
'name' => $typeMachine->getName(),
|
||
'category' => $typeMachine->getCategory(),
|
||
'description' => $typeMachine->getDescription(),
|
||
'customFields' => $this->normalizeCustomFields($typeMachine->getCustomFields()),
|
||
'componentRequirements' => $typeMachine->getComponentRequirements()
|
||
->map(fn (TypeMachineComponentRequirement $req) => $this->normalizeComponentRequirement($req))
|
||
->toArray(),
|
||
'pieceRequirements' => $typeMachine->getPieceRequirements()
|
||
->map(fn (TypeMachinePieceRequirement $req) => $this->normalizePieceRequirement($req))
|
||
->toArray(),
|
||
'productRequirements' => $typeMachine->getProductRequirements()
|
||
->map(fn (TypeMachineProductRequirement $req) => $this->normalizeProductRequirement($req))
|
||
->toArray(),
|
||
] : null,
|
||
'constructeurs' => $this->normalizeConstructeurs($machine->getConstructeurs()),
|
||
'documents' => null,
|
||
'customFieldValues' => null,
|
||
];
|
||
}
|
||
|
||
private function normalizeCustomFields(Collection $customFields): array
|
||
{
|
||
$items = [];
|
||
foreach ($customFields as $customField) {
|
||
if (!$customField instanceof CustomField) {
|
||
continue;
|
||
}
|
||
$items[] = [
|
||
'id' => $customField->getId(),
|
||
'name' => $customField->getName(),
|
||
'type' => $customField->getType(),
|
||
'required' => $customField->isRequired(),
|
||
'options' => $customField->getOptions(),
|
||
'defaultValue' => $customField->getDefaultValue(),
|
||
'orderIndex' => $customField->getOrderIndex(),
|
||
];
|
||
}
|
||
|
||
return $items;
|
||
}
|
||
|
||
private function normalizeComponentLinks(array $links): array
|
||
{
|
||
return array_map(function (MachineComponentLink $link): array {
|
||
$composant = $link->getComposant();
|
||
$requirement = $link->getTypeMachineComponentRequirement();
|
||
$parentLink = $link->getParentLink();
|
||
$parentRequirementId = $parentLink?->getTypeMachineComponentRequirement()?->getId();
|
||
|
||
return [
|
||
'id' => $link->getId(),
|
||
'linkId' => $link->getId(),
|
||
'machineId' => $link->getMachine()->getId(),
|
||
'composantId' => $composant->getId(),
|
||
'composant' => $this->normalizeComposant($composant),
|
||
'typeMachineComponentRequirementId' => $requirement?->getId(),
|
||
'typeMachineComponentRequirement' => $requirement ? $this->normalizeComponentRequirement($requirement) : null,
|
||
'parentLinkId' => $parentLink?->getId(),
|
||
'parentComponentLinkId' => $parentLink?->getId(),
|
||
'parentComponentId' => $parentLink?->getComposant()->getId(),
|
||
'parentMachineComponentRequirementId' => $parentRequirementId,
|
||
'overrides' => $this->normalizeOverrides($link),
|
||
'childLinks' => [],
|
||
'pieceLinks' => [],
|
||
];
|
||
}, $links);
|
||
}
|
||
|
||
private function normalizePieceLinks(array $links): array
|
||
{
|
||
return array_map(function (MachinePieceLink $link): array {
|
||
$piece = $link->getPiece();
|
||
$requirement = $link->getTypeMachinePieceRequirement();
|
||
$parentLink = $link->getParentLink();
|
||
$parentRequirementId = $parentLink?->getTypeMachineComponentRequirement()?->getId();
|
||
|
||
return [
|
||
'id' => $link->getId(),
|
||
'linkId' => $link->getId(),
|
||
'machineId' => $link->getMachine()->getId(),
|
||
'pieceId' => $piece->getId(),
|
||
'piece' => $this->normalizePiece($piece),
|
||
'typeMachinePieceRequirementId' => $requirement?->getId(),
|
||
'typeMachinePieceRequirement' => $requirement ? $this->normalizePieceRequirement($requirement) : null,
|
||
'parentLinkId' => $parentLink?->getId(),
|
||
'parentComponentLinkId' => $parentLink?->getId(),
|
||
'parentComponentId' => $parentLink?->getComposant()->getId(),
|
||
'parentMachineComponentRequirementId' => $parentRequirementId,
|
||
'overrides' => $this->normalizeOverrides($link),
|
||
];
|
||
}, $links);
|
||
}
|
||
|
||
private function normalizeProductLinks(array $links): array
|
||
{
|
||
return array_map(function (MachineProductLink $link): array {
|
||
$product = $link->getProduct();
|
||
$requirement = $link->getTypeMachineProductRequirement();
|
||
|
||
return [
|
||
'id' => $link->getId(),
|
||
'linkId' => $link->getId(),
|
||
'machineId' => $link->getMachine()->getId(),
|
||
'productId' => $product->getId(),
|
||
'product' => $this->normalizeProduct($product),
|
||
'typeMachineProductRequirementId' => $requirement?->getId(),
|
||
'typeMachineProductRequirement' => $requirement ? $this->normalizeProductRequirement($requirement) : null,
|
||
'parentLinkId' => $link->getParentLink()?->getId(),
|
||
'parentComponentLinkId' => $link->getParentComponentLink()?->getId(),
|
||
'parentPieceLinkId' => $link->getParentPieceLink()?->getId(),
|
||
];
|
||
}, $links);
|
||
}
|
||
|
||
private function normalizeComposant(Composant $composant): array
|
||
{
|
||
return [
|
||
'id' => $composant->getId(),
|
||
'name' => $composant->getName(),
|
||
'reference' => $composant->getReference(),
|
||
'prix' => $composant->getPrix(),
|
||
'typeComposantId' => $composant->getTypeComposant()?->getId(),
|
||
'typeComposant' => $this->normalizeModelType($composant->getTypeComposant()),
|
||
'productId' => $composant->getProduct()?->getId(),
|
||
'product' => $composant->getProduct() ? $this->normalizeProduct($composant->getProduct()) : null,
|
||
'constructeurs' => $this->normalizeConstructeurs($composant->getConstructeurs()),
|
||
'documents' => [],
|
||
'customFields' => [],
|
||
];
|
||
}
|
||
|
||
private function normalizePiece(Piece $piece): array
|
||
{
|
||
return [
|
||
'id' => $piece->getId(),
|
||
'name' => $piece->getName(),
|
||
'reference' => $piece->getReference(),
|
||
'prix' => $piece->getPrix(),
|
||
'typePieceId' => $piece->getTypePiece()?->getId(),
|
||
'typePiece' => $this->normalizeModelType($piece->getTypePiece()),
|
||
'productId' => $piece->getProduct()?->getId(),
|
||
'product' => $piece->getProduct() ? $this->normalizeProduct($piece->getProduct()) : null,
|
||
'constructeurs' => $this->normalizeConstructeurs($piece->getConstructeurs()),
|
||
'documents' => [],
|
||
'customFields' => [],
|
||
];
|
||
}
|
||
|
||
private function normalizeProduct(Product $product): array
|
||
{
|
||
return [
|
||
'id' => $product->getId(),
|
||
'name' => $product->getName(),
|
||
'reference' => $product->getReference(),
|
||
'supplierPrice' => $product->getSupplierPrice(),
|
||
'typeProductId' => $product->getTypeProduct()?->getId(),
|
||
'typeProduct' => $this->normalizeModelType($product->getTypeProduct()),
|
||
'constructeurs' => $this->normalizeConstructeurs($product->getConstructeurs()),
|
||
'documents' => [],
|
||
'customFields' => [],
|
||
];
|
||
}
|
||
|
||
private function normalizeModelType(?ModelType $type): ?array
|
||
{
|
||
if (!$type instanceof ModelType) {
|
||
return null;
|
||
}
|
||
|
||
return [
|
||
'id' => $type->getId(),
|
||
'name' => $type->getName(),
|
||
'code' => $type->getCode(),
|
||
'category' => $type->getCategory()->value,
|
||
];
|
||
}
|
||
|
||
private function normalizeComponentRequirement(TypeMachineComponentRequirement $requirement): array
|
||
{
|
||
return [
|
||
'id' => $requirement->getId(),
|
||
'label' => $requirement->getLabel(),
|
||
'minCount' => $requirement->getMinCount(),
|
||
'maxCount' => $requirement->getMaxCount(),
|
||
'required' => $requirement->isRequired(),
|
||
'typeComposantId' => $requirement->getTypeComposant()->getId(),
|
||
'typeComposant' => $this->normalizeModelType($requirement->getTypeComposant()),
|
||
];
|
||
}
|
||
|
||
private function normalizePieceRequirement(TypeMachinePieceRequirement $requirement): array
|
||
{
|
||
return [
|
||
'id' => $requirement->getId(),
|
||
'label' => $requirement->getLabel(),
|
||
'minCount' => $requirement->getMinCount(),
|
||
'maxCount' => $requirement->getMaxCount(),
|
||
'required' => $requirement->isRequired(),
|
||
'typePieceId' => $requirement->getTypePiece()->getId(),
|
||
'typePiece' => $this->normalizeModelType($requirement->getTypePiece()),
|
||
];
|
||
}
|
||
|
||
private function normalizeProductRequirement(TypeMachineProductRequirement $requirement): array
|
||
{
|
||
return [
|
||
'id' => $requirement->getId(),
|
||
'label' => $requirement->getLabel(),
|
||
'minCount' => $requirement->getMinCount(),
|
||
'maxCount' => $requirement->getMaxCount(),
|
||
'required' => $requirement->isRequired(),
|
||
'typeProductId' => $requirement->getTypeProduct()->getId(),
|
||
'typeProduct' => $this->normalizeModelType($requirement->getTypeProduct()),
|
||
];
|
||
}
|
||
|
||
private function normalizeConstructeurs(Collection $constructeurs): array
|
||
{
|
||
$items = [];
|
||
foreach ($constructeurs as $constructeur) {
|
||
$items[] = [
|
||
'id' => $constructeur->getId(),
|
||
'name' => $constructeur->getName(),
|
||
'email' => $constructeur->getEmail(),
|
||
'phone' => $constructeur->getPhone(),
|
||
];
|
||
}
|
||
|
||
return $items;
|
||
}
|
||
|
||
private function normalizeOverrides(object $link): ?array
|
||
{
|
||
$name = method_exists($link, 'getNameOverride') ? $link->getNameOverride() : null;
|
||
$reference = method_exists($link, 'getReferenceOverride') ? $link->getReferenceOverride() : null;
|
||
$prix = method_exists($link, 'getPrixOverride') ? $link->getPrixOverride() : null;
|
||
|
||
if (null === $name && null === $reference && null === $prix) {
|
||
return null;
|
||
}
|
||
|
||
return [
|
||
'name' => $name,
|
||
'reference' => $reference,
|
||
'prix' => $prix,
|
||
];
|
||
}
|
||
|
||
private function applyOverrides(object $link, mixed $overrides): void
|
||
{
|
||
if (!is_array($overrides)) {
|
||
return;
|
||
}
|
||
|
||
if (array_key_exists('name', $overrides) && method_exists($link, 'setNameOverride')) {
|
||
$link->setNameOverride($this->stringOrNull($overrides['name']));
|
||
}
|
||
if (array_key_exists('reference', $overrides) && method_exists($link, 'setReferenceOverride')) {
|
||
$link->setReferenceOverride($this->stringOrNull($overrides['reference']));
|
||
}
|
||
if (array_key_exists('prix', $overrides) && method_exists($link, 'setPrixOverride')) {
|
||
$link->setPrixOverride($this->stringOrNull($overrides['prix']));
|
||
}
|
||
}
|
||
|
||
private function stringOrNull(mixed $value): ?string
|
||
{
|
||
if (null === $value) {
|
||
return null;
|
||
}
|
||
$string = trim((string) $value);
|
||
|
||
return '' === $string ? null : $string;
|
||
}
|
||
|
||
private function resolveIdentifier(array $entry, array $keys): ?string
|
||
{
|
||
foreach ($keys as $key) {
|
||
if (!array_key_exists($key, $entry)) {
|
||
continue;
|
||
}
|
||
$value = $entry[$key];
|
||
if (null === $value || '' === $value) {
|
||
continue;
|
||
}
|
||
|
||
return (string) $value;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* @param array<array-key, object> $links
|
||
*
|
||
* @return array<string, object>
|
||
*/
|
||
private function indexLinksById(array $links): array
|
||
{
|
||
$indexed = [];
|
||
foreach ($links as $link) {
|
||
if (method_exists($link, 'getId') && $link->getId()) {
|
||
$indexed[$link->getId()] = $link;
|
||
}
|
||
}
|
||
|
||
return $indexed;
|
||
}
|
||
|
||
private function indexNormalizedLinks(array $links): array
|
||
{
|
||
$indexed = [];
|
||
foreach ($links as $link) {
|
||
if (is_array($link) && isset($link['id'])) {
|
||
$indexed[$link['id']] = $link;
|
||
}
|
||
}
|
||
|
||
return $indexed;
|
||
}
|
||
|
||
private function removeMissingLinks(array $existing, array $keepIds): void
|
||
{
|
||
$keep = array_flip($keepIds);
|
||
foreach ($existing as $link) {
|
||
if (!method_exists($link, 'getId')) {
|
||
continue;
|
||
}
|
||
$id = $link->getId();
|
||
if ($id && !isset($keep[$id])) {
|
||
$this->entityManager->remove($link);
|
||
}
|
||
}
|
||
}
|
||
|
||
private function generateCuid(): string
|
||
{
|
||
return 'cl'.bin2hex(random_bytes(12));
|
||
}
|
||
}
|