From 80f64f3ffc928f56994c0db1965d7adde6fead8a Mon Sep 17 00:00:00 2001 From: Ruslan Baidan Date: Tue, 20 Aug 2024 12:29:38 +0200 Subject: [PATCH] Fixed the export and import issues, snapshots restoring, recommendations import with positions. --- src/Entity/Anr.php | 11 +++- src/Entity/Instance.php | 6 ++- src/Entity/InstanceRiskOwner.php | 21 ++++---- src/Entity/Measure.php | 16 +++--- src/Entity/Snapshot.php | 2 +- .../Traits/ExportResponseControllerTrait.php | 7 ++- src/Export/Service/AnrExportService.php | 23 +++++--- .../OperationalInstanceRiskExportTrait.php | 1 + .../Traits/RecommendationExportTrait.php | 6 ++- .../InformationRiskImportProcessor.php | 5 +- .../Processor/InstanceRiskImportProcessor.php | 2 + .../Processor/ObjectImportProcessor.php | 52 +++++++++++++++---- ...OperationalInstanceRiskImportProcessor.php | 10 ++-- .../RecommendationImportProcessor.php | 7 ++- .../ImportDataStructureAdapterTrait.php | 30 ++++++++--- src/Service/AnrInstanceRiskOpService.php | 31 ++++++----- src/Service/AnrObjectService.php | 1 + src/Service/AnrService.php | 12 ++--- src/Service/InstanceRiskOwnerService.php | 2 +- src/Service/SnapshotService.php | 49 ++++++++++------- 20 files changed, 196 insertions(+), 98 deletions(-) diff --git a/src/Entity/Anr.php b/src/Entity/Anr.php index 2b046d08..c8fbc4b3 100755 --- a/src/Entity/Anr.php +++ b/src/Entity/Anr.php @@ -73,7 +73,7 @@ class Anr extends AnrSuperClass /** * @var Snapshot|null * - * @ORM\OneToOne(targetEntity="Snapshot", mappedBy="anr") + * @ORM\OneToOne(targetEntity="Snapshot", mappedBy="anr", cascade={"remove"}) */ protected $snapshot; @@ -377,6 +377,15 @@ public function addReferencedSnapshot(Snapshot $snapshot): self return $this; } + public function removeReferencedSnapshot(Snapshot $snapshot): self + { + if ($this->referencedSnapshots->contains($snapshot)) { + $this->referencedSnapshots->removeElement($snapshot); + } + + return $this; + } + public function getRecommendationSets() { return $this->recommendationSets; diff --git a/src/Entity/Instance.php b/src/Entity/Instance.php index 98bd8123..11d773d7 100755 --- a/src/Entity/Instance.php +++ b/src/Entity/Instance.php @@ -87,8 +87,10 @@ public function addInstanceMetadata(InstanceMetadata $instanceMetadata): self public function getInstanceMetadataByMetadataFieldLink(AnrInstanceMetadataField $metadataField): ?InstanceMetadata { foreach ($this->instanceMetadata as $instanceMetadata) { - if ($instanceMetadata->getAnrInstanceMetadataField()->getLabel() === $metadataField->getLabel()) { - return $instanceMetadata->getAnrInstanceMetadataField(); + if ($this->id === $instanceMetadata->getInstance()->getId() + && $instanceMetadata->getAnrInstanceMetadataField()->getLabel() === $metadataField->getLabel() + ) { + return $instanceMetadata; } } diff --git a/src/Entity/InstanceRiskOwner.php b/src/Entity/InstanceRiskOwner.php index 606f2280..e3b26052 100644 --- a/src/Entity/InstanceRiskOwner.php +++ b/src/Entity/InstanceRiskOwner.php @@ -34,17 +34,6 @@ class InstanceRiskOwner * @ORM\GeneratedValue(strategy="IDENTITY") */ protected $id; - - /** - * @var Anr - * - * @ORM\ManyToOne(targetEntity="Anr") - * @ORM\JoinColumns({ - * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", onDelete="CASCADE") - * }) - */ - protected $anr; - /** * @var InstanceRisk[]|ArrayCollection * @@ -59,6 +48,16 @@ class InstanceRiskOwner */ protected $operationalInstanceRisks; + /** + * @var Anr + * + * @ORM\ManyToOne(targetEntity="Anr") + * @ORM\JoinColumns({ + * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", onDelete="CASCADE") + * }) + */ + protected $anr; + /** * @var string * diff --git a/src/Entity/Measure.php b/src/Entity/Measure.php index 23c0949c..f34c7927 100755 --- a/src/Entity/Measure.php +++ b/src/Entity/Measure.php @@ -38,14 +38,6 @@ class Measure extends MeasureSuperClass */ protected $uuid; - /** - * @var Anr - * - * @ORM\ManyToOne(targetEntity="Anr") - * @ORM\JoinColumns({@ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false)}) - */ - protected $anr; - /** * @var ArrayCollection|Amv[] * @@ -100,6 +92,14 @@ class Measure extends MeasureSuperClass */ protected $soa; + /** + * @var Anr + * + * @ORM\ManyToOne(targetEntity="Anr") + * @ORM\JoinColumns({@ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false)}) + */ + protected $anr; + public function getId() { return $this->id; diff --git a/src/Entity/Snapshot.php b/src/Entity/Snapshot.php index b4fde9ab..2c8f44ce 100755 --- a/src/Entity/Snapshot.php +++ b/src/Entity/Snapshot.php @@ -49,7 +49,7 @@ class Snapshot * * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ - * @ORM\JoinColumn(name="anr_reference_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") + * @ORM\JoinColumn(name="anr_reference_id", referencedColumnName="id", nullable=false) * }) */ protected $anrReference; diff --git a/src/Export/Controller/Traits/ExportResponseControllerTrait.php b/src/Export/Controller/Traits/ExportResponseControllerTrait.php index 3e754cf1..90441fa6 100644 --- a/src/Export/Controller/Traits/ExportResponseControllerTrait.php +++ b/src/Export/Controller/Traits/ExportResponseControllerTrait.php @@ -9,22 +9,21 @@ use Laminas\Diactoros\Response; use Psr\Http\Message\ResponseInterface; - use function strlen; trait ExportResponseControllerTrait { private function prepareExportResponse(string $filename, string $output, bool $isEncrypted): ResponseInterface { - $dataType = 'application/json'; $contentType = 'application/json; charset=utf-8'; $extension = '.json'; if ($isEncrypted) { - $dataType = 'text/plain'; $contentType = 'text/plain; charset=utf-8'; $extension = '.bin'; } - $stream = fopen('data://' . $dataType . ',' . $output, 'rb+'); + $stream = fopen('php://memory', 'rb+'); + fwrite($stream, $output); + rewind($stream); return new Response($stream, 200, [ 'Content-Type' => $contentType, diff --git a/src/Export/Service/AnrExportService.php b/src/Export/Service/AnrExportService.php index 445dd29a..a17aae7e 100644 --- a/src/Export/Service/AnrExportService.php +++ b/src/Export/Service/AnrExportService.php @@ -109,8 +109,14 @@ private function prepareExportData(Entity\Anr $anr, array $exportParams): array !$withKnowledgeBase ) : [], 'library' => $withLibrary ? $this->prepareLibraryData($anr, !$withKnowledgeBase) : [], - 'instances' => $this - ->prepareInstancesData($anr, !$withLibrary, $withEval, $withControls, $withRecommendations), + 'instances' => $this->prepareInstancesData( + $anr, + !$withLibrary, + !$withKnowledgeBase, + $withEval, + $withControls, + $withRecommendations + ), 'anrInstanceMetadataFields' => $this->prepareAnrInstanceMetadataFieldsData($anr), 'scales' => $withEval ? $this->prepareScalesData($anr) : [], 'operationalRiskScales' => $withEval ? $this->prepareOperationalRiskScalesData($anr) : [], @@ -165,7 +171,7 @@ private function prepareKnowledgeBaseData( 'informationRisks' => $this->prepareInformationRisksData($anr, $withEval, $withControls), 'rolfTags' => $this->prepareRolfTagsData($anr), 'operationalRisks' => $this->prepareOperationalRisksData($anr, $withControls), - 'recommendationSets' => $withRecommendations ? $this->prepareRecommendationSetsData($anr) : [], + 'recommendationSets' => $this->prepareRecommendationSetsData($anr, $withRecommendations), ]; } @@ -266,14 +272,14 @@ private function prepareReferentialsData(Entity\Anr $anr): array return $result; } - private function prepareRecommendationSetsData(Entity\Anr $anr): array + private function prepareRecommendationSetsData(Entity\Anr $anr, bool $includePositions): array { $result = []; /** @var Entity\RecommendationSet $recommendationSet */ foreach ($this->recommendationSetTable->findByAnr($anr) as $recommendationSet) { $recommendationsData = []; foreach ($recommendationSet->getRecommendations() as $recommendation) { - $recommendationsData[] = $this->prepareRecommendationData($recommendation, false); + $recommendationsData[] = $this->prepareRecommendationData($recommendation, false, $includePositions); } if (!empty($recommendationsData)) { $result[] = [ @@ -348,7 +354,8 @@ private function prepareCategoryData( private function prepareInstancesData( Entity\Anr $anr, - bool $includeObjectDataInTheResult, + bool $includeObjectData, + bool $includeCompleteInformationRisksData, bool $withEval, bool $withControls, bool $withRecommendations @@ -360,8 +367,8 @@ private function prepareInstancesData( $result[] = $this->prepareInstanceData( $instance, $languageIndex, - $includeObjectDataInTheResult, - false, + $includeObjectData, + $includeCompleteInformationRisksData, $withEval, $withControls, $withRecommendations, diff --git a/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php b/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php index e5b53c1e..fae7602b 100644 --- a/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php +++ b/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php @@ -51,6 +51,7 @@ private function prepareOperationalInstanceRiskData( 'operationalRisk' => $operationalRisk !== null ? $this->prepareOperationalRiskData($operationalRisk, $languageIndex, $withControls) : null, + 'riskCacheCode' => $operationalInstanceRisk->getRiskCacheCode(), 'riskCacheLabel' => $operationalInstanceRisk->getRiskCacheLabel($languageIndex), 'riskCacheDescription' => $operationalInstanceRisk->getRiskCacheDescription($languageIndex), 'brutProb' => $withEval ? $operationalInstanceRisk->getBrutProb() : -1, diff --git a/src/Export/Service/Traits/RecommendationExportTrait.php b/src/Export/Service/Traits/RecommendationExportTrait.php index 0f2e3122..89931e10 100644 --- a/src/Export/Service/Traits/RecommendationExportTrait.php +++ b/src/Export/Service/Traits/RecommendationExportTrait.php @@ -13,7 +13,8 @@ trait RecommendationExportTrait { private function prepareRecommendationData( Entity\Recommendation $recommendation, - bool $includeRecommendationSetData = true + bool $includeRecommendationSetData = true, + bool $includePosition = true ): array { $result = [ 'uuid' => $recommendation->getUuid(), @@ -32,6 +33,9 @@ private function prepareRecommendationData( 'label' => $recommendation->getRecommendationSet()->getLabel(), ]; } + if ($includePosition) { + $result['position'] = $recommendation->getPosition(); + } return $result; } diff --git a/src/Import/Processor/InformationRiskImportProcessor.php b/src/Import/Processor/InformationRiskImportProcessor.php index 39ccd4f4..508d2924 100644 --- a/src/Import/Processor/InformationRiskImportProcessor.php +++ b/src/Import/Processor/InformationRiskImportProcessor.php @@ -60,6 +60,9 @@ public function processInformationRiskData(Entity\Anr $anr, array $informationRi 'setOnlyExactPosition' => true, 'position' => ++$this->maxPositionsPerAsset[$asset->getUuid()], ], false, false); + + $this->importCacheHelper + ->addItemToArrayCache('amvs_by_uuid', $informationRisk, $informationRisk->getUuid()); } $saveInformationRisk = false; @@ -80,8 +83,6 @@ public function processInformationRiskData(Entity\Anr $anr, array $informationRi if ($saveInformationRisk) { $this->amvTable->save($informationRisk, false); - $this->importCacheHelper - ->addItemToArrayCache('amvs_by_uuid', $informationRisk, $informationRisk->getUuid()); } return $informationRisk; diff --git a/src/Import/Processor/InstanceRiskImportProcessor.php b/src/Import/Processor/InstanceRiskImportProcessor.php index 17d54163..bbc3d2a2 100644 --- a/src/Import/Processor/InstanceRiskImportProcessor.php +++ b/src/Import/Processor/InstanceRiskImportProcessor.php @@ -54,11 +54,13 @@ private function processInstanceRiskData(Entity\Instance $instance, array $insta /** @var Entity\Anr $anr */ $anr = $instance->getAnr(); if (!empty($instanceRiskData['informationRisk'])) { + /* The case of normal instance risk, where threat and vulnerability are taken from AMV. */ $amv = $this->informationRiskImportProcessor ->processInformationRiskData($anr, $instanceRiskData['informationRisk']); $threat = null; $vulnerability = null; } else { + /* The case of specific instance risk that has no relation to AMV. */ $amv = null; $threat = $this->threatImportProcessor->processThreatData($anr, $instanceRiskData['threat']); $vulnerability = $this->vulnerabilityImportProcessor diff --git a/src/Import/Processor/ObjectImportProcessor.php b/src/Import/Processor/ObjectImportProcessor.php index 139571e8..b257e0be 100644 --- a/src/Import/Processor/ObjectImportProcessor.php +++ b/src/Import/Processor/ObjectImportProcessor.php @@ -7,6 +7,7 @@ namespace Monarc\FrontOffice\Import\Processor; +use Monarc\Core\Entity\InstanceRiskOpSuperClass; use Monarc\Core\Entity\InstanceRiskSuperClass; use Monarc\Core\Entity\ObjectSuperClass; use Monarc\FrontOffice\Entity; @@ -22,15 +23,18 @@ public function __construct( private Table\MonarcObjectTable $monarcObjectTable, private Table\ObjectObjectTable $objectObjectTable, private Table\InstanceRiskTable $instanceRiskTable, + private Table\InstanceRiskOpTable $instanceRiskOpTable, private Table\AmvTable $amvTable, private ImportCacheHelper $importCacheHelper, private Service\AnrObjectService $anrObjectService, private Service\AnrObjectObjectService $anrObjectObjectService, private Service\AnrInstanceRiskService $anrInstanceRiskService, + private Service\AnrInstanceRiskOpService $anrInstanceRiskOpService, private AssetImportProcessor $assetImportProcessor, private RolfTagImportProcessor $rolfTagImportProcessor, private ObjectCategoryImportProcessor $objectCategoryImportProcessor, - private InformationRiskImportProcessor $informationRiskImportProcessor + private InformationRiskImportProcessor $informationRiskImportProcessor, + private OperationalRiskScaleImportProcessor $operationalRiskScaleImportProcessor ) { } @@ -216,8 +220,7 @@ private function mergeAssetInformationRisks(Entity\MonarcObject $object, array $ foreach (array_diff_key($existingAmvs, $importingAmvsData) as $existingAmvToRemove) { /* Recreated instance risks if the object is instantiated. */ foreach ($existingAmvToRemove->getInstanceRisks() as $instanceRiskToSetSpecific) { - $instanceRiskToSetSpecific->setSpecific(InstanceRiskSuperClass::TYPE_SPECIFIC) - ->setAmv(null); + $instanceRiskToSetSpecific->setSpecific(InstanceRiskSuperClass::TYPE_SPECIFIC)->setAmv(null); $this->instanceRiskTable->save($instanceRiskToSetSpecific, false); } $this->amvTable->remove($existingAmvToRemove, false); @@ -225,18 +228,45 @@ private function mergeAssetInformationRisks(Entity\MonarcObject $object, array $ } /** Merges the rolfRisks (operational risks) of the existing object. */ - private function mergeRolfTagOperationalRisks(Entity\MonarcObject $object, ?array $rolfTagData): void - { + private function mergeRolfTagOperationalRisks( + Entity\Anr $anr, + Entity\MonarcObject $object, + ?array $rolfTagData + ): void { + /* NOTE. If rolfTag stays the same, then the rolf risks could be validated and updated if different. */ if (!empty($rolfTagData) && $object->getRolfTag() === null) { - // TODO: 1: /* if there was no rolfTag and a new one is set. */ - + $rolfTag = $this->rolfTagImportProcessor->processRolfTagData($anr, $rolfTagData); + $object->setRolfTag($rolfTag); + $this->monarcObjectTable->save($object, false); } elseif (empty($rolfTagData) && $object->getRolfTag() !== null) { - // TODO: 2. was a rolf tag and now removed, then remove all the instance risks op have to be removed. + /* if there was a rolfTag and now removed, then all the InstanceRiskOp have to be set as specific. */ + $this->setOperationalRisksSpecific($object); + $object->setRolfTag(null); + $this->monarcObjectTable->save($object, false); } elseif ($object->getRolfTag()->getCode() !== $rolfTagData['code']) { - // TODO: 3. if a new rolf is changed, then all the op risks have to be updated. - } else { - // TODO: 4. rolfTag stays the same (set) then we have to validate the difference of rolf risks. + /* If rolfTag is changed, then all the op risks have to be updated. */ + $this->setOperationalRisksSpecific($object); + $rolfTag = $this->rolfTagImportProcessor->processRolfTagData($anr, $rolfTagData); + $object->setRolfTag($rolfTag); + foreach ($object->getInstances() as $instance) { + foreach ($rolfTag->getRisks() as $rolfRisk) { + $this->anrInstanceRiskOpService->createInstanceRiskOpWithScales($instance, $object, $rolfRisk); + } + } + $this->monarcObjectTable->save($object, false); + } + } + + private function setOperationalRisksSpecific(Entity\MonarcObject $object): void + { + if ($object->getRolfTag() !== null) { + foreach ($object->getRolfTag()->getRisks() as $rolfRisk) { + foreach ($rolfRisk->getOperationalInstanceRisks() as $operationalInstanceRisk) { + $operationalInstanceRisk->setSpecific(InstanceRiskOpSuperClass::TYPE_SPECIFIC)->setRolfRisk(null); + $this->instanceRiskOpTable->save($operationalInstanceRisk, false); + } + } } } } diff --git a/src/Import/Processor/OperationalInstanceRiskImportProcessor.php b/src/Import/Processor/OperationalInstanceRiskImportProcessor.php index 26e661c0..eac180c0 100644 --- a/src/Import/Processor/OperationalInstanceRiskImportProcessor.php +++ b/src/Import/Processor/OperationalInstanceRiskImportProcessor.php @@ -83,12 +83,16 @@ public function processOperationalInstanceRisksData( ); } foreach ($operationalInstanceRisksData as $operationalInstanceRiskData) { - $operationalRisk = $this->operationalRiskImportProcessor - ->processOperationalRiskData($anr, $operationalInstanceRiskData['operationalRisk']); + $operationalRisk = empty($operationalInstanceRiskData['operationalRisk']) + ? null + : $this->operationalRiskImportProcessor->processOperationalRiskData( + $anr, + $operationalInstanceRiskData['operationalRisk'] + ); /** @var Entity\MonarcObject $object */ $object = $instance->getObject(); $operationalInstanceRisk = $this->anrInstanceRiskOpService - ->createInstanceRiskOpObject($instance, $object, $operationalRisk); + ->createInstanceRiskOpObject($instance, $object, $operationalRisk, $operationalInstanceRiskData); if ($this->importCacheHelper->getValueFromArrayCache('with_eval')) { $operationalInstanceRisk ->setBrutProb((int)$operationalInstanceRiskData['brutProb']) diff --git a/src/Import/Processor/RecommendationImportProcessor.php b/src/Import/Processor/RecommendationImportProcessor.php index 4a5c7a51..8284793f 100644 --- a/src/Import/Processor/RecommendationImportProcessor.php +++ b/src/Import/Processor/RecommendationImportProcessor.php @@ -15,6 +15,8 @@ class RecommendationImportProcessor { + private int $maxRecommendationPosition = 0; + public function __construct( private Table\RecommendationSetTable $recommendationSetTable, private Table\RecommendationTable $recommendationTable, @@ -87,6 +89,9 @@ public function processRecommendationData( $recommendationData['recommendationSet'] = $recommendationSet; + if (!empty($recommendationData['position'])) { + $recommendationData['position'] += $this->maxRecommendationPosition; + } $recommendation = $this->anrRecommendationService->create($anr, $recommendationData, false); $this->importCacheHelper->addItemToArrayCache('recommendations', $recommendation, $recommendation->getUuid()); @@ -125,7 +130,7 @@ private function prepareRecommendationsCache(Entity\Anr $anr): void { if (!$this->importCacheHelper->isCacheKeySet('is_recommendations_cache_loaded')) { $this->importCacheHelper->setArrayCacheValue('is_recommendations_cache_loaded', true); - $this->currentMaxRecommendationPosition = $this->recommendationTable->findMaxPosition(['anr' => $anr]); + $this->maxRecommendationPosition = $this->recommendationTable->findMaxPosition(['anr' => $anr]); /** @var Entity\RecommendationSet $recommendationSet */ foreach ($this->recommendationSetTable->findByAnr($anr) as $recommendationSet) { $this->importCacheHelper->addItemToArrayCache( diff --git a/src/Import/Traits/ImportDataStructureAdapterTrait.php b/src/Import/Traits/ImportDataStructureAdapterTrait.php index 69e42339..579872e8 100644 --- a/src/Import/Traits/ImportDataStructureAdapterTrait.php +++ b/src/Import/Traits/ImportDataStructureAdapterTrait.php @@ -7,8 +7,12 @@ namespace Monarc\FrontOffice\Import\Traits; +use Monarc\Core\Entity\InstanceRiskSuperClass; + trait ImportDataStructureAdapterTrait { + private int $recommendationsPositionsCounter = 0; + /** Converts the scales, comments and impact types related data from the structure prior v2.13.1 to the new one. */ public function adoptOldScalesDataStructureToNewFormat(array $data, int $languageIndex): array { @@ -242,8 +246,12 @@ private function prepareInstanceRisksData(array $data, int $languageIndex): arra $recommendationsData = []; if (!empty($data['recos'][$instanceRiskDatum['id']])) { foreach ($data['recos'][$instanceRiskDatum['id']] as $recommendationData) { - $recommendationsData[] = $this - ->prepareRecommendationData($data, $recommendationData, $languageIndex); + $recommendationsData[] = $this->prepareRecommendationData( + $data, + $recommendationData, + $instanceRiskDatum['kindOfMeasure'] !== InstanceRiskSuperClass::KIND_NOT_TREATED, + $languageIndex + ); } } @@ -327,13 +335,18 @@ private function prepareOperationalInstanceRisksData(array $data, int $languageI $recommendationsData = []; if (!empty($data['recosop'][$operationalInstanceRiskData['id']])) { foreach ($data['recosop'][$operationalInstanceRiskData['id']] as $recommendationData) { - $recommendationsData[] = $this - ->prepareRecommendationData($data, $recommendationData, $languageIndex); + $recommendationsData[] = $this->prepareRecommendationData( + $data, + $recommendationData, + $operationalInstanceRiskData['kindOfMeasure'] !== InstanceRiskSuperClass::KIND_NOT_TREATED, + $languageIndex + ); } } $operationalInstanceRisksData[] = [ 'operationalRisk' => $rolfRiskData, + 'riskCacheCode' => $operationalInstanceRiskData['riskCacheCode'] ?? 'empty-code-' . time(), 'riskCacheLabel' => $operationalInstanceRiskData['riskCacheLabel' . $languageIndex], 'riskCacheDescription' => $operationalInstanceRiskData['riskCacheDescription' . $languageIndex], 'brutProb' => $operationalInstanceRiskData['brutProb'], @@ -356,8 +369,12 @@ private function prepareOperationalInstanceRisksData(array $data, int $languageI return $operationalInstanceRisksData; } - private function prepareRecommendationData(array $data, array $recommendationData, int $languageIndex): array - { + private function prepareRecommendationData( + array $data, + array $recommendationData, + bool $isRiskTreated, + int $languageIndex + ): array { $recommendationSetUuid = $recommendationData['recommendationSet'] ?? ''; return [ @@ -371,6 +388,7 @@ private function prepareRecommendationData(array $data, array $recommendationDat 'duedate' => $recommendationData['duedate'], 'counterTreated' => $recommendationData['counterTreated'], 'commentAfter' => $recommendationData['commentAfter'], + 'position' => $isRiskTreated ? ++$this->recommendationsPositionsCounter : 0, 'recommendationSet' => [ 'uuid' => $recommendationSetUuid, 'label' => $data['recSets'][$recommendationSetUuid]['label' . $languageIndex] ?? 'Imported', diff --git a/src/Service/AnrInstanceRiskOpService.php b/src/Service/AnrInstanceRiskOpService.php index 297db9f4..3c52e7da 100644 --- a/src/Service/AnrInstanceRiskOpService.php +++ b/src/Service/AnrInstanceRiskOpService.php @@ -25,6 +25,8 @@ class AnrInstanceRiskOpService private CoreEntity\UserSuperClass $connectedUser; + private array $operationalRiskImpactScales = []; + public function __construct( private Table\InstanceRiskOpTable $instanceRiskOpTable, private Table\InstanceTable $instanceTable, @@ -191,12 +193,14 @@ public function createInstanceRiskOpWithScales( ): Entity\InstanceRiskOp { $instanceRiskOp = $this->createInstanceRiskOpObject($instance, $object, $rolfRisk); - /** @var Entity\OperationalRiskScaleType[] $operationalRiskScaleTypes */ - $operationalRiskScaleTypes = $this->operationalRiskScaleTypeTable->findByAnrAndScaleType( - $instance->getAnr(), - CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT - ); - foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { + if (empty($this->operationalRiskImpactScales)) { + /** @var Entity\OperationalRiskScaleType[] $operationalRiskScaleTypes */ + $this->operationalRiskImpactScales = $this->operationalRiskScaleTypeTable->findByAnrAndScaleType( + $instance->getAnr(), + CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT + ); + } + foreach ($this->operationalRiskImpactScales as $operationalRiskScaleType) { $this->createOperationalInstanceRiskScaleObject($instanceRiskOp, $operationalRiskScaleType); } @@ -206,27 +210,30 @@ public function createInstanceRiskOpWithScales( public function createInstanceRiskOpObject( Entity\Instance $instance, Entity\MonarcObject $object, - Entity\RolfRisk $rolfRisk + ?Entity\RolfRisk $rolfRisk, + array $data = [] ): Entity\InstanceRiskOp { + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); /** @var Entity\InstanceRiskOp $instanceRiskOp */ $instanceRiskOp = (new Entity\InstanceRiskOp()) ->setAnr($instance->getAnr()) ->setInstance($instance) ->setObject($object) ->setRolfRisk($rolfRisk) - ->setRiskCacheCode($rolfRisk->getCode()) - ->setRiskCacheLabels([ + ->setRiskCacheCode($rolfRisk ? $rolfRisk->getCode() : $data['riskCacheCode']) + ->setRiskCacheLabels($rolfRisk ? [ 'riskCacheLabel1' => $rolfRisk->getLabel(1), 'riskCacheLabel2' => $rolfRisk->getLabel(2), 'riskCacheLabel3' => $rolfRisk->getLabel(3), 'riskCacheLabel4' => $rolfRisk->getLabel(4), - ]) - ->setRiskCacheDescriptions([ + ] : ['riskCacheLabel' . $anr->getLanguage() => $data['riskCacheLabel']]) + ->setRiskCacheDescriptions($rolfRisk ? [ 'riskCacheDescription1' => $rolfRisk->getDescription(1), 'riskCacheDescription2' => $rolfRisk->getDescription(2), 'riskCacheDescription3' => $rolfRisk->getDescription(3), 'riskCacheDescription4' => $rolfRisk->getDescription(4), - ]) + ] : ['riskCacheDescription' . $anr->getLanguage() => $data['riskCacheDescription']]) ->setCreator($this->connectedUser->getEmail()); $this->instanceRiskOpTable->save($instanceRiskOp, false); diff --git a/src/Service/AnrObjectService.php b/src/Service/AnrObjectService.php index c62357ed..d20bc389 100755 --- a/src/Service/AnrObjectService.php +++ b/src/Service/AnrObjectService.php @@ -373,6 +373,7 @@ private function adjustInstancesValidateAndSetRolfTag(Entity\MonarcObject $monar if (!empty($data['rolfTag']) && ( $monarcObject->getRolfTag() === null || (int)$data['rolfTag'] !== $monarcObject->getRolfTag()->getId() )) { + /** @var Entity\RolfTag $rolfTag */ $rolfTag = $this->rolfTagTable->findByIdAndAnr((int)$data['rolfTag'], $monarcObject->getAnr()); $monarcObject->setRolfTag($rolfTag); diff --git a/src/Service/AnrService.php b/src/Service/AnrService.php index fbbcd849..d0a2432e 100755 --- a/src/Service/AnrService.php +++ b/src/Service/AnrService.php @@ -162,16 +162,14 @@ public function createBasedOnModel(array $data): Entity\Anr /** * Creates (Duplicates) an analysis based on existing one on the client's side or a model's anr * in the common database, and performs the biggest part of creation/restoring snapshots. - * - * @param string|null $snapshotMode The value is null for anr creation, and 'create' | 'restore' for snapshots. */ public function duplicateAnr( CoreEntity\AnrSuperClass $sourceAnr, array $data = [], - ?string $snapshotMode = null + bool $isSnapshotMode = false ): Entity\Anr { $isSourceCommon = $sourceAnr instanceof CoreEntity\Anr; - if (!$isSourceCommon && $snapshotMode === null) { + if (!$isSourceCommon && !$isSnapshotMode) { /* Validate id the duplicated anr accessible for the user. */ if (!$this->connectedUser->hasRole(Entity\UserRole::USER_ROLE_SYSTEM) && $this->userAnrTable->findByAnrAndUser($sourceAnr, $this->connectedUser) === null @@ -187,7 +185,7 @@ public function duplicateAnr( $newAnr = Entity\Anr::constructFromObjectAndData($sourceAnr, $data) ->setCreator($this->connectedUser->getEmail()); - if ($snapshotMode === 'create') { + if ($isSnapshotMode) { /* The "[SNAP]" prefix is added for snapshots. */ $newAnr->setLabel('[SNAP] ' . $newAnr->getLabel()); } @@ -195,7 +193,7 @@ public function duplicateAnr( $this->anrTable->save($newAnr, false); /* Not needed for snapshots creation or restoring. */ - if ($snapshotMode === null) { + if (!$isSnapshotMode) { $userAnr = (new Entity\UserAnr()) ->setUser($this->connectedUser) ->setAnr($newAnr) @@ -286,7 +284,7 @@ public function duplicateAnr( $this->duplicateRopa($sourceAnr, $newAnr); } - if ($snapshotMode !== 'create') { + if (!$isSnapshotMode) { $this->setCurrentAnrToConnectedUser($newAnr); } diff --git a/src/Service/InstanceRiskOwnerService.php b/src/Service/InstanceRiskOwnerService.php index 763709dd..45dcd19a 100644 --- a/src/Service/InstanceRiskOwnerService.php +++ b/src/Service/InstanceRiskOwnerService.php @@ -42,7 +42,7 @@ public function create(Anr $anr, string $ownerName, bool $saveIdDb = false): Ins public function getOrCreateInstanceRiskOwner(Anr $sourceAnr, Anr $anr, string $ownerName): InstanceRiskOwner { - if (isset($this->cachedData['isInstanceRiskOwnersCacheLoaded'])) { + if (!isset($this->cachedData['isInstanceRiskOwnersCacheLoaded'])) { $this->cachedData['isInstanceRiskOwnersCacheLoaded'] = true; /** @var InstanceRiskOwner $instanceRiskOwner */ foreach ($this->instanceRiskOwnerTable->findByAnr($sourceAnr) as $instanceRiskOwner) { diff --git a/src/Service/SnapshotService.php b/src/Service/SnapshotService.php index ba395ce0..44cafdd5 100755 --- a/src/Service/SnapshotService.php +++ b/src/Service/SnapshotService.php @@ -13,20 +13,18 @@ use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Entity\Anr; use Monarc\FrontOffice\Entity\Snapshot; -use Monarc\FrontOffice\Table\AnrTable; -use Monarc\FrontOffice\Table\SnapshotTable; -use Monarc\FrontOffice\Table\UserAnrTable; -use Ramsey\Uuid\Uuid; +use Monarc\FrontOffice\Table; class SnapshotService { private UserSuperClass $connectedUser; public function __construct( - private SnapshotTable $snapshotTable, - private AnrTable $anrTable, + private Table\SnapshotTable $snapshotTable, + private Table\AnrTable $anrTable, private AnrService $anrService, - private UserAnrTable $userAnrTable, + private Table\UserAnrTable $userAnrTable, + private Table\UserTable $userTable, ConnectedUserService $connectedUserService ) { $this->connectedUser = $connectedUserService->getConnectedUser(); @@ -55,7 +53,7 @@ public function getList(Anr $anr): array public function create(Anr $anr, array $data): Snapshot { - $newAnr = $this->anrService->duplicateAnr($anr, [], 'create'); + $newAnr = $this->anrService->duplicateAnr($anr, [], true); /* * Snapshots should not be visible on global dashboard * and stats not send to the StatsService (but snapshots are ignored anyway). @@ -87,36 +85,49 @@ public function restore(Anr $anrReference, int $snapshotId): Anr /** @var Snapshot $snapshot */ $snapshot = $this->snapshotTable->findById($snapshotId); if ($snapshot->getAnrReference()->getId() !== $anrReference->getId()) { - throw new Exception('The analysis associated with the snapshot does match the requested one.', 412); + throw new Exception('The analysis associated with the snapshot matches the requested one.', 412); } - /* Duplicate the anr linked to this snapshot */ - $newAnr = $this->anrService->duplicateAnr($snapshot->getAnr(), [], 'restore'); + /* Use the anr from the snapshot as a new one. */ + $snapshotAnr = $snapshot->getAnr(); /* Update the reference for all the other snapshots. */ foreach ($anrReference->getReferencedSnapshots() as $referencedSnapshot) { - $referencedSnapshot->setAnrReference($newAnr); - $this->snapshotTable->save($referencedSnapshot, false); + if ($snapshot->getId() !== $referencedSnapshot->getId()) { + $this->snapshotTable->save($referencedSnapshot->setAnrReference($snapshotAnr), false); + } + $anrReference->removeReferencedSnapshot($referencedSnapshot); } /* Move permissions from the old anr to the new one. */ foreach ($anrReference->getUsersAnrsPermissions() as $userAnrPermission) { - $this->userAnrTable->save($userAnrPermission->setAnr($newAnr), false); + $anrReference->removeUserAnrPermission($userAnrPermission); + $this->userAnrTable->save($userAnrPermission->setAnr($snapshotAnr), false); } /* * We need to set visibility on global dashboard, set stats sending option, * swap the uuid of the old anr, that we are going to drop and restore labels. */ - $newAnr->setIsVisibleOnDashboard((int)$anrReference->isVisibleOnDashboard()) + $snapshotAnr->setIsVisibleOnDashboard((int)$anrReference->isVisibleOnDashboard()) ->setIsStatsCollected((int)$anrReference->isStatsCollected()) ->setLabel($anrReference->getLabel()); $referenceAnrUuid = $anrReference->getUuid(); - $this->anrTable->remove($anrReference); - - $this->anrTable->save($newAnr->setUuid($referenceAnrUuid)); + $this->userTable->save($this->connectedUser->setCurrentAnr($snapshotAnr), false); + + $this->snapshotTable->save($snapshot->setAnr($anrReference), false); + $this->anrTable->save($anrReference->generateAndSetUuid()); + try { + $this->anrTable->remove($anrReference, false); + $this->snapshotTable->remove($snapshot, false); + $this->anrTable->save($snapshotAnr->setUuid($referenceAnrUuid)); + } catch (\Throwable $e) { + $this->snapshotTable->save($snapshot->setAnr($snapshotAnr), false); + $this->anrTable->save($anrReference->setUuid($referenceAnrUuid)); + throw $e; + } - return $newAnr; + return $snapshotAnr; } }