refactor : simplification globale (vague 1 + 2)
- ActorProfileResolver : service unique partage par AbstractAuditSubscriber, EntityVersionService et ModelTypeCategoryConversionService (3 implementations dupliquees+divergentes) - corrige un bug latent : EntityVersionService restoraitsans le fallback Security::getUser, loggant actor=null hors session - machine-clone : clonage des contextFieldValues integre dans cloneComponentLinks/clonePieceLinks, supprime cloneContextFieldValues et son find() en boucle - helpers extraits : serializeProductSlots (EntityVersionService), updateModelTypeCategory (ModelTypeCategoryConversionService) - supprime collectCollectionUpdate() vide + ses appels (AbstractAuditSubscriber) - useMachineDetailData : retire debug ref couplee a isEditMode, componentTypeLabelMap/pieceTypeLabelMap jamais consommes, double assignation machine.productLinks - PieceItem : retire l'init pieceData dans onMounted (deja couvert par reactive() et le watcher) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
41
src/Service/ActorProfileResolver.php
Normal file
41
src/Service/ActorProfileResolver.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\Profile;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Throwable;
|
||||
|
||||
final class ActorProfileResolver
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RequestStack $requestStack,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
|
||||
public function resolve(): ?string
|
||||
{
|
||||
try {
|
||||
$session = $this->requestStack->getSession();
|
||||
if ($session instanceof SessionInterface) {
|
||||
$profileId = $session->get('profileId');
|
||||
if ($profileId) {
|
||||
return (string) $profileId;
|
||||
}
|
||||
}
|
||||
} catch (Throwable) {
|
||||
// No session available (CLI context, etc.)
|
||||
}
|
||||
|
||||
$user = $this->security->getUser();
|
||||
if ($user instanceof Profile) {
|
||||
return $user->getId();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@ use DateTimeInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Throwable;
|
||||
|
||||
final class EntityVersionService
|
||||
@@ -56,7 +55,7 @@ final class EntityVersionService
|
||||
public function __construct(
|
||||
private readonly AuditLogRepository $auditLogs,
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly RequestStack $requestStack,
|
||||
private readonly ActorProfileResolver $actorProfileResolver,
|
||||
private readonly MachineRepository $machines,
|
||||
private readonly ComposantRepository $composants,
|
||||
private readonly PieceRepository $pieces,
|
||||
@@ -187,7 +186,7 @@ final class EntityVersionService
|
||||
'restore',
|
||||
['restoredFromVersion' => $version, 'restoreMode' => $restoreMode],
|
||||
$this->buildCurrentSnapshot($entityType, $entity),
|
||||
$this->resolveActorProfileId(),
|
||||
$this->actorProfileResolver->resolve(),
|
||||
$newVersion,
|
||||
);
|
||||
$this->em->persist($restoreAuditLog);
|
||||
@@ -917,25 +916,11 @@ final class EntityVersionService
|
||||
'position' => $slot->getPosition(),
|
||||
];
|
||||
}
|
||||
$snapshot['productSlots'] = [];
|
||||
foreach ($entity->getProductSlots() as $slot) {
|
||||
$snapshot['productSlots'][] = [
|
||||
'id' => $slot->getId(), 'typeProductId' => $slot->getTypeProduct()?->getId(),
|
||||
'selectedProductId' => $slot->getSelectedProduct()?->getId(),
|
||||
'familyCode' => $slot->getFamilyCode(), 'position' => $slot->getPosition(),
|
||||
];
|
||||
}
|
||||
$snapshot['productSlots'] = $this->serializeProductSlots($entity->getProductSlots());
|
||||
}
|
||||
|
||||
if ('piece' === $entityType) {
|
||||
$snapshot['productSlots'] = [];
|
||||
foreach ($entity->getProductSlots() as $slot) {
|
||||
$snapshot['productSlots'][] = [
|
||||
'id' => $slot->getId(), 'typeProductId' => $slot->getTypeProduct()?->getId(),
|
||||
'selectedProductId' => $slot->getSelectedProduct()?->getId(),
|
||||
'familyCode' => $slot->getFamilyCode(), 'position' => $slot->getPosition(),
|
||||
];
|
||||
}
|
||||
$snapshot['productSlots'] = $this->serializeProductSlots($entity->getProductSlots());
|
||||
}
|
||||
|
||||
// Custom field values
|
||||
@@ -953,21 +938,24 @@ final class EntityVersionService
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the current actor profile ID from the session.
|
||||
* Mirrors AbstractAuditSubscriber::resolveActorProfileId().
|
||||
* @param iterable<ComposantProductSlot|PieceProductSlot> $slots
|
||||
*
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function resolveActorProfileId(): ?string
|
||||
private function serializeProductSlots(iterable $slots): array
|
||||
{
|
||||
try {
|
||||
$session = $this->requestStack->getSession();
|
||||
$profileId = $session->get('profileId');
|
||||
if ($profileId) {
|
||||
return (string) $profileId;
|
||||
}
|
||||
} catch (Throwable) {
|
||||
// No session available (CLI context, etc.)
|
||||
$serialized = [];
|
||||
foreach ($slots as $slot) {
|
||||
$serialized[] = [
|
||||
'id' => $slot->getId(),
|
||||
'typeProductId' => $slot->getTypeProduct()?->getId(),
|
||||
'selectedProductId' => $slot->getSelectedProduct()?->getId(),
|
||||
'familyCode' => $slot->getFamilyCode(),
|
||||
'position' => $slot->getPosition(),
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
return $serialized;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,23 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\Profile;
|
||||
use App\Enum\ModelCategory;
|
||||
use App\Repository\ModelTypeRepository;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Throwable;
|
||||
|
||||
final class ModelTypeCategoryConversionService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Connection $connection,
|
||||
private readonly ModelTypeRepository $modelTypes,
|
||||
private readonly RequestStack $requestStack,
|
||||
private readonly Security $security,
|
||||
private readonly ActorProfileResolver $actorProfileResolver,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -327,17 +321,7 @@ final class ModelTypeCategoryConversionService
|
||||
);
|
||||
|
||||
// 7. Update ModelType
|
||||
$this->connection->executeStatement(
|
||||
'UPDATE model_types
|
||||
SET category = :cat,
|
||||
updatedat = :now
|
||||
WHERE id = :id',
|
||||
[
|
||||
'cat' => ModelCategory::COMPONENT->value,
|
||||
'now' => new DateTimeImmutable()->format('Y-m-d H:i:s'),
|
||||
'id' => $modelTypeId,
|
||||
],
|
||||
);
|
||||
$this->updateModelTypeCategory($modelTypeId, ModelCategory::COMPONENT);
|
||||
|
||||
return $count;
|
||||
}
|
||||
@@ -406,19 +390,24 @@ final class ModelTypeCategoryConversionService
|
||||
);
|
||||
|
||||
// 7. Update ModelType
|
||||
$this->updateModelTypeCategory($modelTypeId, ModelCategory::PIECE);
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
private function updateModelTypeCategory(string $modelTypeId, ModelCategory $category): void
|
||||
{
|
||||
$this->connection->executeStatement(
|
||||
'UPDATE model_types
|
||||
SET category = :cat,
|
||||
updatedat = :now
|
||||
WHERE id = :id',
|
||||
[
|
||||
'cat' => ModelCategory::PIECE->value,
|
||||
'cat' => $category->value,
|
||||
'now' => new DateTimeImmutable()->format('Y-m-d H:i:s'),
|
||||
'id' => $modelTypeId,
|
||||
],
|
||||
);
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -457,30 +446,10 @@ final class ModelTypeCategoryConversionService
|
||||
'action' => 'convert',
|
||||
'diff' => json_encode($diff),
|
||||
'snapshot' => json_encode($snapshot),
|
||||
'actor' => $this->resolveActorProfileId(),
|
||||
'actor' => $this->actorProfileResolver->resolve(),
|
||||
'now' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
private function resolveActorProfileId(): ?string
|
||||
{
|
||||
try {
|
||||
$session = $this->requestStack->getSession();
|
||||
if ($session instanceof SessionInterface) {
|
||||
$profileId = $session->get('profileId');
|
||||
if ($profileId) {
|
||||
return (string) $profileId;
|
||||
}
|
||||
}
|
||||
} catch (Throwable) {
|
||||
}
|
||||
|
||||
$user = $this->security->getUser();
|
||||
if ($user instanceof Profile) {
|
||||
return $user->getId();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user