Skip to content

Commit

Permalink
Finalized the library assets import process.
Browse files Browse the repository at this point in the history
  • Loading branch information
ruslanbaidan committed Jun 14, 2024
1 parent 9e634d7 commit b8d07ea
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 93 deletions.
6 changes: 4 additions & 2 deletions config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -1692,8 +1692,7 @@
},

// Commands
Import\Command\ImportAnalysesCommand::class => static function (ContainerInterface $container)
{
Import\Command\ImportAnalysesCommand::class => static function (ContainerInterface $container) {
/** @var ConnectedUserService $connectedUserService */
$connectedUserService = $container->get(ConnectedUserService::class);
$connectedUserService->setConnectedUser(new Entity\User([
Expand Down Expand Up @@ -1731,6 +1730,9 @@
Service\AnrInstanceService::class => [
LazyServiceFactory::class,
],
Import\Processor\ObjectCategoryImportProcessor::class => [
LazyServiceFactory::class,
],
],
],

Expand Down
5 changes: 0 additions & 5 deletions src/Entity/MonarcObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ class MonarcObject extends ObjectSuperClass
*/
protected $children;

public function getImplicitPositionRelationsValues(): array
{
return array_merge(['anr' => $this->anr], parent::getImplicitPositionRelationsValues());
}

public function setAnr(Anr $anr): self
{
$this->anr = $anr;
Expand Down
5 changes: 0 additions & 5 deletions src/Import/Helper/ImportCacheHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ public function isItemInArrayCache(string $cacheKey, $itemKey): bool
return isset($this->arrayCache[$cacheKey][$itemKey]);
}

public function addItemsToArrayCache(string $cacheKey, array $values): void
{
$this->arrayCache[$cacheKey] = $values;
}

public function addItemToArrayCache(string $cacheKey, $value, $itemKey = null): void
{
if ($itemKey === null) {
Expand Down
22 changes: 14 additions & 8 deletions src/Import/Processor/ObjectCategoryImportProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,14 @@ public function processObjectCategoryData(
array $objectCategoryData,
string $importMode
): Entity\ObjectCategory {
$parentCategory = isset(
$objectCategoryData['parent']
) && $objectCategoryData['parent'] instanceof Entity\ObjectCategory ? $objectCategoryData['parent'] : null;
$parentCategory = null;
// TODO: support the old structure where parent is and int ID and the cats are on thr same level in the json.
if (isset($objectCategoryData['parent']) && $objectCategoryData['parent'] instanceof Entity\ObjectCategory) {
$parentCategory = $objectCategoryData['parent'];
} elseif (isset($objectCategoryData['parent']['label'])) {
$parentCategory = $this->processObjectCategoryData($anr, $objectCategoryData['parent'], $importMode);
$objectCategoryData['parent'] = $parentCategory;
}

// TODO: process the categories data when the request comes NOT from the library:
// - parent and it's parents' data are inside so this method have to be recursively called.
Expand All @@ -54,18 +59,19 @@ public function processObjectCategoryData(
$parentCategoryLabel = $parentCategory->getLabel($anr->getLanguage());
}

/* In the new data structure there is only "label" field set. */
if (isset($objectCategoryData['label'])) {
$objectCategoryData['label' . $anr->getLanguage()] = $objectCategoryData['label'];
}

/* If parents are different, a new category is created anyway. */
/** @var ?Entity\ObjectCategory $objectCategory */
$objectCategory = $this->importCacheHelper->getItemFromArrayCache(
'object_categories_by_label',
$objectCategoryData['label'] . $parentCategoryLabel
$objectCategoryData['label' . $anr->getLanguage()] . $parentCategoryLabel
);

if ($objectCategory === null) {
/* In the new data structure there is only "label" field set. */
if (isset($objectCategoryData['label'])) {
$objectCategoryData['label' . $anr->getLanguage()] = $objectCategoryData['label'];
}
/* Prepare the position and cache it. */
if (!isset($this->maxPositionPerCategory[$parentCategoryLabel])) {
/* If the parent category in new, there is no need to fetch it from the DB. */
Expand Down
69 changes: 41 additions & 28 deletions src/Import/Processor/ObjectImportProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

class ObjectImportProcessor
{
private array $linksMaxPositions = [];

public function __construct(
private MonarcObjectTable $monarcObjectTable,
private ObjectObjectTable $objectObjectTable,
Expand Down Expand Up @@ -50,6 +48,11 @@ public function processObjectData(
array $objectData,
string $importMode
): Entity\MonarcObject {
/* Only newly created objects are stored under the cache key 'created_objects_by_old_uuids'. */
if ($this->importCacheHelper->isItemInArrayCache('created_objects_by_old_uuids', $objectData['uuid'])) {
return $this->importCacheHelper->getItemFromArrayCache('created_objects_by_old_uuids', $objectData['uuid']);
}

$assetData = $objectData['asset']['asset'] ?? $objectData['asset'];
$objectScope = (int)$objectData['scope'];
$nameFiledKey = 'name' . $anr->getLanguage();
Expand All @@ -61,35 +64,33 @@ public function processObjectData(
if ($objectScope === ObjectSuperClass::SCOPE_LOCAL || (
$objectScope === ObjectSuperClass::SCOPE_GLOBAL && $importMode === ObjectImportService::IMPORT_MODE_MERGE
)) {
$object = $this->getObjectFromCache(
$object = $this->getObjectFromCacheByParams(
$objectData[$nameFiledKey],
$assetData['uuid'],
$objectScope,
$objectCategory->getId()
);
if ($object !== null) {
foreach ($object->getChildren() as $linkedObject) {
$object->removeChild($linkedObject);
}
$this->monarcObjectTable->save($object, false);
$this->objectObjectTable->deleteLinksByParentObject($object);
}
}

if ($object === null) {
$asset = $this->assetImportProcessor->processAssetData($anr, $assetData);
$rolfTag = null;
if (!empty($objectData['rofTag'])) {
if (isset($objectData['rofTag']['code'])) {
$rolfTag = $this->rolfTagImportProcessor->processRolfTagData($anr, $objectData['rofTag']);
} elseif (isset($objectData['rofTags'][$objectData['rofTag']])) {
if (!empty($objectData['rolfTag'])) {
if (isset($objectData['rolfTag']['code'])) {
$rolfTag = $this->rolfTagImportProcessor->processRolfTagData($anr, $objectData['rolfTag']);
} elseif (isset($objectData['rolfTags'][$objectData['rolfTag']])) {
/* Handles the structure prior the version 2.13.1 */
$rolfTag = $this->rolfTagImportProcessor
->processRolfTagData($anr, $objectData['rofTags'][$objectData['rofTag']]);
->processRolfTagData($anr, $objectData['rolfTags'][$objectData['rolfTag']]);
}
}

/* Avoid the UUID duplication. */
if ($this->importCacheHelper->isItemInArrayCache('objects_uuid', $objectData['uuid'])) {
$currentObjectUuid = $objectData['uuid'];
if ($this->importCacheHelper->isItemInArrayCache('objects_uuids', $objectData['uuid'])) {
unset($objectData['uuid']);
}
/* In the new data structure there is only "label" field set. */
Expand All @@ -106,35 +107,43 @@ public function processObjectData(
$object,
$objectData[$nameFiledKey] . $asset->getUuid() . $object->getScope() . $objectCategory->getId()
);
$this->importCacheHelper->addItemToArrayCache('objects_names', $objectData[$nameFiledKey]);
$this->importCacheHelper->addItemToArrayCache(
'objects_names',
$objectData[$nameFiledKey],
$objectData[$nameFiledKey]
);
$this->importCacheHelper->addItemToArrayCache('created_objects_by_old_uuids', $object, $currentObjectUuid);
}

/* Process objects links. */
foreach ($objectData['children'] as $childObjectData) {
foreach ($objectData['children'] as $positionIndex => $childObjectData) {
$objectCategory = $this->objectCategoryImportProcessor->processObjectCategoryData(
$anr,
$childObjectData['category'],
$importMode
);
$childObject = $this->processObjectData($anr, $objectCategory, $childObjectData, $importMode);
/* Determine the max position of the link and store in the cache property. */
if (!isset($this->linksMaxPositions[$object->getUuid()])) {
$this->linksMaxPositions[$object->getUuid()] = $this->objectObjectTable->findMaxPosition([
'anr' => $anr,
'parent' => $object,
]);

if (!$object->hasChild($childObject) && !$this->importCacheHelper->isItemInArrayCache(
'objects_links_uuids',
$object->getUuid() . $childObject->getUuid()
)) {
$this->anrObjectObjectService->createObjectLink($object, $childObject, [
'position' => $positionIndex + 1,
'forcePositionUpdate' => true,
], false);
$this->importCacheHelper->addItemToArrayCache(
'objects_links_uuids',
$object->getUuid() . $childObject->getUuid(),
$object->getUuid() . $childObject->getUuid()
);
}
$positionData = [
'position' => ++$this->linksMaxPositions[$object->getUuid()],
'forcePositionUpdate' => true,
];
$this->anrObjectObjectService->createObjectLink($object, $childObject, $positionData, false);
}

return $object;
}

public function getObjectFromCache(
public function getObjectFromCacheByParams(
string $name,
string $assetUuid,
int $scope,
Expand All @@ -159,7 +168,11 @@ private function prepareObjectsCache(Entity\Anr $anr): void
$object->getName($languageIndex) . $object->getAsset()->getUuid() . $object->getScope()
. $object->getCategory()?->getId()
);
$this->importCacheHelper->addItemToArrayCache('objects_names', $object->getName($languageIndex));
$this->importCacheHelper->addItemToArrayCache(
'objects_names',
$object->getName($languageIndex),
$object->getName($languageIndex)
);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/Import/Processor/RecommendationImportProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ public function prepareRecommendationsCache(Entity\Anr $anr): void
$recommendationsCodes,
$recommendationSet->getUuid()
);

}
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/Import/Processor/ThreatImportProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,14 @@ public function prepareThemesCache(Entity\Anr $anr): void

private function processThemeData(Entity\Anr $anr, array $themeData): Entity\Theme
{
$theme = $this->importCacheHelper->getItemFromArrayCache('themes_by_labels', $themeData['label']);
if (isset($themeData['label'])) {
$themeData['label' . $anr->getLanguage()] = $themeData['label'];
}
$themeLabel = $themeData['label' . $anr->getLanguage()];
$theme = $this->importCacheHelper->getItemFromArrayCache('themes_by_labels', $themeLabel);
if ($theme === null) {
$themeData['label' . $anr->getLanguage()] = $theme['label'];
$theme = $this->anrThemeService->create($anr, $themeData, false);
$this->importCacheHelper->addItemToArrayCache('themes_by_labels', $theme, $themeData['label']);
$this->importCacheHelper->addItemToArrayCache('themes_by_labels', $theme, $themeLabel);
}

return $theme;
Expand Down
24 changes: 14 additions & 10 deletions src/Import/Service/InstanceImportService.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function __construct(
private Processor\RolfTagImportProcessor $rolfTagImportProcessor,
private Processor\OperationalRisksImportProcessor $operationalRisksImportProcessor,
private Processor\RecommendationImportProcessor $recommendationImportProcessor,
private Processor\ObjectCategoryImportProcessor $objectCategoryImportProcessor,
private Service\AnrInstanceRiskService $anrInstanceRiskService,
private Service\InstanceRiskOwnerService $instanceRiskOwnerService,
private Service\AnrInstanceService $anrInstanceService,
Expand Down Expand Up @@ -228,7 +229,7 @@ private function processKnowledgeBaseData(Entity\Anr $anr, array $knowledgeBaseD
$this->assetImportProcessor->processAssetsData($anr, $knowledgeBaseData['assets']);
$this->threatImportProcessor->processThreatsData($anr, $knowledgeBaseData['threats'], []);
$this->vulnerabilityImportProcessor->processVulnerabilitiesData($anr, $knowledgeBaseData['vulnerabilities']);
$this->referentialImportProcessor->processReferentialsData($anr, $knowledgeBaseData['referentails']);
$this->referentialImportProcessor->processReferentialsData($anr, $knowledgeBaseData['referentials']);
$this->informationRiskImportProcessor->processInformationRisksData(
$anr,
$knowledgeBaseData['informationRisks']
Expand All @@ -246,10 +247,11 @@ private function processKnowledgeBaseData(Entity\Anr $anr, array $knowledgeBaseD

private function processLibraryData(Entity\Anr $anr, array $libraryData, string $importMode): void
{
// TODO: 1. process categories, 2. objects & children, 3. objects compositions. 4. asset,
// 5. rolfTag, 6. RolfRisks
// TODO: for the export: if the KB is generated then we can reduce data inside the objects: asset (uuid), rolfTag (code) and nothing more.
// TODO: for the export: it seems the category is not needed inside of the object for library export as objects are inside of categories.
$this->objectCategoryImportProcessor->processObjectCategoriesData(
$anr,
$libraryData['categories'],
$importMode
);
}

private function processInstanceImport(
Expand Down Expand Up @@ -289,6 +291,7 @@ private function importInstanceFromArray(
return false;
}

// TODO: move it to a processor and use service.
$instance = $this->createInstance($data, $anr, $parentInstance, $monarcObject);

// TODO: The instance risks are processed later again and considered that here we save or not...
Expand Down Expand Up @@ -848,10 +851,10 @@ private function importAnrFromArray(
usort($data['instances'], function ($a, $b) {
return $a['instance']['position'] <=> $b['instance']['position'];
});
$this->assetImportProcessor->prepareAssetUuidsAndCodesCache($anr);
$this->threatImportProcessor->prepareThreatUuidsAndCodesCache($anr);
$this->assetImportProcessor->prepareAssetsAndCodesCache($anr);
$this->threatImportProcessor->prepareThreatsAndCodesCache($anr);
$this->threatImportProcessor->prepareThemesCache($anr);
$this->vulnerabilityImportProcessor->prepareVulnerabilityUuidsAndCodesCache($anr);
$this->vulnerabilityImportProcessor->prepareVulnerabilitiesAndCodesCache($anr);
foreach ($data['instances'] as $inst) {
if ($first) {
if ($data['with_eval'] && isset($data['scales'])) {
Expand Down Expand Up @@ -2135,7 +2138,8 @@ private function createInstance(
array $data,
Entity\Anr $anr,
?CoreEntity\InstanceSuperClass $parentInstance,
Entity\MonarcObject $monarcObject
Entity\MonarcObject $monarcObject,
bool $saveInDb = true
): Entity\Instance {
$instanceData = $data['instance'];
$instance = (new Entity\Instance())
Expand Down Expand Up @@ -2170,7 +2174,7 @@ private function createInstance(
$instance->setInheritedAvailability((int)$instanceData['dh']);
}

$this->instanceTable->save($instance);
$this->instanceTable->save($instance, $saveInDb);

return $instance;
}
Expand Down
22 changes: 9 additions & 13 deletions src/Table/MonarcObjectTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

use Doctrine\ORM\EntityManager;
use Monarc\Core\Entity\AnrSuperClass;
use Monarc\Core\Entity\ObjectSuperClass;
use Monarc\Core\Entity\RolfTagSuperClass;
use Monarc\Core\Table\AbstractTable;
use Monarc\Core\Table\Interfaces\PositionUpdatableTableInterface;
use Monarc\Core\Table\Traits\PositionIncrementTableTrait;
Expand All @@ -36,15 +34,14 @@ public function findOneByAnrAssetNameScopeAndCategory(
int $scope,
ObjectCategory $category
): ?MonarcObject {
return $this->getRepository()
->createQueryBuilder('mo')
->innerJoin('mo.asset', 'a')
->where('mo.anr = :anr')
return $this->getRepository()->createQueryBuilder('o')
->innerJoin('o.asset', 'a')
->where('o.anr = :anr')
->andWhere('a.uuid = :assetUuid')
->andWhere('a.anr = :assetAnr')
->andWhere('mo.' . $nameKey . ' = :name')
->andWhere('mo.scope = :scope')
->andWhere('mo.category = :category')
->andWhere('o.' . $nameKey . ' = :name')
->andWhere('o.scope = :scope')
->andWhere('o.category = :category')
->setParameter('anr', $anr)
->setParameter('assetUuid', $asset->getUuid())
->setParameter('assetAnr', $anr)
Expand All @@ -58,10 +55,9 @@ public function findOneByAnrAssetNameScopeAndCategory(

public function findOneByAnrAndName(Anr $anr, string $nameKey, string $nameValue): ?MonarcObject
{
return $this->getRepository()
->createQueryBuilder('mo')
->where('mo.anr = :anr')
->andWhere('mo.' . $nameKey . ' = :name')
return $this->getRepository()->createQueryBuilder('o')
->where('o.anr = :anr')
->andWhere('o.' . $nameKey . ' = :name')
->setParameter('anr', $anr)
->setParameter('name', $nameValue)
->setMaxResults(1)
Expand Down
Loading

0 comments on commit b8d07ea

Please sign in to comment.